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 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>
65 # if HAVE_SYS_SOCKET_H
66 # include <sys/socket.h>
67 # include <netinet/in.h>
69 # else /* not HAVE_SYS_SOCKET_H */
70 # if HAVE_LAN_SOCKET_H
71 # include <lan/socket.h>
73 # include <lan/netdb.h>
74 # else /* not HAVE_LAN_SOCKET_H */
75 # define OMIT_SOCKETS 1
76 # endif /* not HAVE_LAN_SOCKET_H */
77 # endif /* not HAVE_SYS_SOCKET_H */
78 #endif /* !OMIT_SOCKETS */
83 #else /* not STDC_HEADERS */
84 extern char *getenv();
87 # else /* not HAVE_STRING_H */
89 # endif /* not HAVE_STRING_H */
90 #endif /* not STDC_HEADERS */
93 # include <sys/fcntl.h>
94 #else /* not HAVE_SYS_FCNTL_H */
97 # endif /* HAVE_FCNTL_H */
98 #endif /* not HAVE_SYS_FCNTL_H */
100 #if HAVE_SYS_SYSTEMINFO_H
101 # include <sys/systeminfo.h>
102 #endif /* HAVE_SYS_SYSTEMINFO_H */
104 #if TIME_WITH_SYS_TIME
105 # include <sys/time.h>
109 # include <sys/time.h>
120 # include <sys/wait.h>
125 # define NAMLEN(dirent) strlen((dirent)->d_name)
126 # define HAVE_DIR_STRUCT
128 # define dirent direct
129 # define NAMLEN(dirent) (dirent)->d_namlen
131 # include <sys/ndir.h>
132 # define HAVE_DIR_STRUCT
135 # include <sys/dir.h>
136 # define HAVE_DIR_STRUCT
140 # define HAVE_DIR_STRUCT
144 #include <X11/Intrinsic.h>
145 #include <X11/StringDefs.h>
146 #include <X11/Shell.h>
147 #include <X11/cursorfont.h>
148 #include <X11/Xatom.h>
149 #include <X11/Xmu/Atoms.h>
151 #include <X11/Xaw3d/Dialog.h>
152 #include <X11/Xaw3d/Form.h>
153 #include <X11/Xaw3d/List.h>
154 #include <X11/Xaw3d/Label.h>
155 #include <X11/Xaw3d/SimpleMenu.h>
156 #include <X11/Xaw3d/SmeBSB.h>
157 #include <X11/Xaw3d/SmeLine.h>
158 #include <X11/Xaw3d/Box.h>
159 #include <X11/Xaw3d/MenuButton.h>
160 #include <X11/Xaw3d/Text.h>
161 #include <X11/Xaw3d/AsciiText.h>
163 #include <X11/Xaw/Dialog.h>
164 #include <X11/Xaw/Form.h>
165 #include <X11/Xaw/List.h>
166 #include <X11/Xaw/Label.h>
167 #include <X11/Xaw/SimpleMenu.h>
168 #include <X11/Xaw/SmeBSB.h>
169 #include <X11/Xaw/SmeLine.h>
170 #include <X11/Xaw/Box.h>
171 #include <X11/Xaw/MenuButton.h>
172 #include <X11/Xaw/Text.h>
173 #include <X11/Xaw/AsciiText.h>
176 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
181 #include "pixmaps/pixmaps.h"
182 #define IMAGE_EXT "xpm"
184 #define IMAGE_EXT "xim"
185 #include "bitmaps/bitmaps.h"
188 #include "bitmaps/icon_white.bm"
189 #include "bitmaps/icon_black.bm"
190 #include "bitmaps/checkmark.bm"
192 #include "frontend.h"
194 #include "backendz.h"
198 #include "xgamelist.h"
199 #include "xhistory.h"
200 #include "xedittags.h"
203 // must be moved to xengineoutput.h
205 void EngineOutputProc P((Widget w, XEvent *event,
206 String *prms, Cardinal *nprms));
207 void EvalGraphProc P((Widget w, XEvent *event,
208 String *prms, Cardinal *nprms));
215 #define usleep(t) _sleep2(((t)+500)/1000)
219 # define _(s) gettext (s)
220 # define N_(s) gettext_noop (s)
238 int main P((int argc, char **argv));
239 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
240 char *init_path, char *mode, int (*show_entry)(), char **name_return));
241 RETSIGTYPE CmailSigHandler P((int sig));
242 RETSIGTYPE IntSigHandler P((int sig));
243 RETSIGTYPE TermSizeSigHandler P((int sig));
244 void CreateGCs P((void));
245 void CreateXIMPieces P((void));
246 void CreateXPMPieces P((void));
247 void CreateXPMBoard P((char *s, int n));
248 void CreatePieces P((void));
249 void CreatePieceMenus P((void));
250 Widget CreateMenuBar P((Menu *mb));
251 Widget CreateButtonBar P ((MenuItem *mi));
252 char *FindFont P((char *pattern, int targetPxlSize));
253 void PieceMenuPopup P((Widget w, XEvent *event,
254 String *params, Cardinal *num_params));
255 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
256 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
257 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
258 u_int wreq, u_int hreq));
259 void CreateGrid P((void));
260 int EventToSquare P((int x, int limit));
261 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
262 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
263 void HandleUserMove P((Widget w, XEvent *event,
264 String *prms, Cardinal *nprms));
265 void AnimateUserMove P((Widget w, XEvent * event,
266 String * params, Cardinal * nParams));
267 void HandlePV P((Widget w, XEvent * event,
268 String * params, Cardinal * nParams));
269 void SelectPV P((Widget w, XEvent * event,
270 String * params, Cardinal * nParams));
271 void StopPV P((Widget w, XEvent * event,
272 String * params, Cardinal * nParams));
273 void WhiteClock P((Widget w, XEvent *event,
274 String *prms, Cardinal *nprms));
275 void BlackClock P((Widget w, XEvent *event,
276 String *prms, Cardinal *nprms));
277 void DrawPositionProc P((Widget w, XEvent *event,
278 String *prms, Cardinal *nprms));
279 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
281 void CommentClick P((Widget w, XEvent * event,
282 String * params, Cardinal * nParams));
283 void CommentPopUp P((char *title, char *label));
284 void CommentPopDown P((void));
285 void CommentCallback P((Widget w, XtPointer client_data,
286 XtPointer call_data));
287 void ICSInputBoxPopUp P((void));
288 void ICSInputBoxPopDown P((void));
289 void FileNamePopUp P((char *label, char *def,
290 FileProc proc, char *openMode));
291 void FileNamePopDown P((void));
292 void FileNameCallback P((Widget w, XtPointer client_data,
293 XtPointer call_data));
294 void FileNameAction P((Widget w, XEvent *event,
295 String *prms, Cardinal *nprms));
296 void AskQuestionReplyAction P((Widget w, XEvent *event,
297 String *prms, Cardinal *nprms));
298 void AskQuestionProc P((Widget w, XEvent *event,
299 String *prms, Cardinal *nprms));
300 void AskQuestionPopDown P((void));
301 void PromotionPopDown P((void));
302 void PromotionCallback P((Widget w, XtPointer client_data,
303 XtPointer call_data));
304 void EditCommentPopDown P((void));
305 void EditCommentCallback P((Widget w, XtPointer client_data,
306 XtPointer call_data));
307 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
308 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
309 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
310 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
312 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
314 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
316 void LoadPositionProc P((Widget w, XEvent *event,
317 String *prms, Cardinal *nprms));
318 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
320 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
322 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
324 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
326 void PastePositionProc P((Widget w, XEvent *event, String *prms,
328 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
329 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
330 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
331 void SavePositionProc P((Widget w, XEvent *event,
332 String *prms, Cardinal *nprms));
333 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
334 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
336 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
337 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
338 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
340 void MachineWhiteProc P((Widget w, XEvent *event,
341 String *prms, Cardinal *nprms));
342 void AnalyzeModeProc P((Widget w, XEvent *event,
343 String *prms, Cardinal *nprms));
344 void AnalyzeFileProc P((Widget w, XEvent *event,
345 String *prms, Cardinal *nprms));
346 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
348 void IcsClientProc P((Widget w, XEvent *event, String *prms,
350 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
351 void EditPositionProc P((Widget w, XEvent *event,
352 String *prms, Cardinal *nprms));
353 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
354 void EditCommentProc P((Widget w, XEvent *event,
355 String *prms, Cardinal *nprms));
356 void IcsInputBoxProc P((Widget w, XEvent *event,
357 String *prms, Cardinal *nprms));
358 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
365 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
370 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
371 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
372 void StopObservingProc P((Widget w, XEvent *event, String *prms,
374 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
376 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
377 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
379 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
380 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
385 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
387 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
388 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
390 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
392 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
394 void AutocommProc P((Widget w, XEvent *event, String *prms,
396 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
397 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
398 void AutobsProc P((Widget w, XEvent *event, String *prms,
400 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
401 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
402 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
403 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
405 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
406 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
408 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
410 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
412 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
413 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
414 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
416 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
418 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
420 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
422 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
424 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
425 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
426 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
428 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
430 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
432 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
434 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
435 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
436 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
442 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
443 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
444 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
445 void DisplayMove P((int moveNumber));
446 void DisplayTitle P((char *title));
447 void ICSInitScript P((void));
448 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
449 void ErrorPopUp P((char *title, char *text, int modal));
450 void ErrorPopDown P((void));
451 static char *ExpandPathName P((char *path));
452 static void CreateAnimVars P((void));
453 static void DragPieceMove P((int x, int y));
454 static void DrawDragPiece P((void));
455 char *ModeToWidgetName P((GameMode mode));
456 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
457 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
458 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
459 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
460 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
461 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
462 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
463 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
464 void GameListOptionsPopDown P(());
465 void ShufflePopDown P(());
466 void EnginePopDown P(());
467 void UciPopDown P(());
468 void TimeControlPopDown P(());
469 void NewVariantPopDown P(());
470 void SettingsPopDown P(());
471 void update_ics_width P(());
472 int get_term_width P(());
473 int CopyMemoProc P(());
475 * XBoard depends on Xt R4 or higher
477 int xtVersion = XtSpecificationRelease;
482 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
483 jailSquareColor, highlightSquareColor, premoveHighlightColor;
484 Pixel lowTimeWarningColor;
485 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
486 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
487 wjPieceGC, bjPieceGC, prelineGC, countGC;
488 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
489 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
490 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
491 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
492 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
493 ICSInputShell, fileNameShell, askQuestionShell;
494 Widget historyShell, evalGraphShell, gameListShell;
495 int hOffset; // [HGM] dual
496 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
497 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
498 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
499 Font clockFontID, coordFontID, countFontID;
500 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
501 XtAppContext appContext;
503 char *oldICSInteractionTitle;
507 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
509 Position commentX = -1, commentY = -1;
510 Dimension commentW, commentH;
511 typedef unsigned int BoardSize;
513 Boolean chessProgram;
515 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
516 int squareSize, smallLayout = 0, tinyLayout = 0,
517 marginW, marginH, // [HGM] for run-time resizing
518 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
519 ICSInputBoxUp = False, askQuestionUp = False,
520 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
521 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
522 Pixel timerForegroundPixel, timerBackgroundPixel;
523 Pixel buttonForegroundPixel, buttonBackgroundPixel;
524 char *chessDir, *programName, *programVersion,
525 *gameCopyFilename, *gamePasteFilename;
526 Boolean alwaysOnTop = False;
527 Boolean saveSettingsOnExit;
528 char *settingsFileName;
529 char *icsTextMenuString;
531 char *firstChessProgramNames;
532 char *secondChessProgramNames;
534 WindowPlacement wpMain;
535 WindowPlacement wpConsole;
536 WindowPlacement wpComment;
537 WindowPlacement wpMoveHistory;
538 WindowPlacement wpEvalGraph;
539 WindowPlacement wpEngineOutput;
540 WindowPlacement wpGameList;
541 WindowPlacement wpTags;
545 Pixmap pieceBitmap[2][(int)BlackPawn];
546 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
547 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
548 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
549 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
550 Pixmap xpmBoardBitmap[2];
551 int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
552 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
553 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
554 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
555 XImage *ximLightSquare, *ximDarkSquare;
558 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
559 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
561 #define White(piece) ((int)(piece) < (int)BlackPawn)
563 /* Variables for doing smooth animation. This whole thing
564 would be much easier if the board was double-buffered,
565 but that would require a fairly major rewrite. */
570 GC blitGC, pieceGC, outlineGC;
571 XPoint startSquare, prevFrame, mouseDelta;
575 int startBoardX, startBoardY;
578 /* There can be two pieces being animated at once: a player
579 can begin dragging a piece before the remote opponent has moved. */
581 static AnimState game, player;
583 /* Bitmaps for use as masks when drawing XPM pieces.
584 Need one for each black and white piece. */
585 static Pixmap xpmMask[BlackKing + 1];
587 /* This magic number is the number of intermediate frames used
588 in each half of the animation. For short moves it's reduced
589 by 1. The total number of frames will be factor * 2 + 1. */
592 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
594 MenuItem fileMenu[] = {
595 {"New Game", "New Game", ResetProc},
596 {"New Shuffle Game ...", "New Shuffle Game", ShuffleMenuProc},
597 {"New Variant ...", "New Variant", NewVariantProc}, // [HGM] variant: not functional yet
598 {"----", NULL, NothingProc},
599 {"Load Game", "Load Game", LoadGameProc},
600 {"Load Position", "Load Position", LoadPositionProc},
601 // {"Load Next Game", "Load Next Game", LoadNextGameProc},
602 // {"Load Previous Game", "Load Previous Game", LoadPrevGameProc},
603 // {"Reload Same Game", "Reload Same Game", ReloadGameProc},
604 {"----", NULL, NothingProc},
605 // {"Load Next Position", "Load Next Position", LoadNextPositionProc},
606 // {"Load Previous Position", "Load Previous Position", LoadPrevPositionProc},
607 // {"Reload Same Position", "Reload Same Position", ReloadPositionProc},
608 {"Save Game", "Save Game", SaveGameProc},
609 {"Save Position", "Save Position", SavePositionProc},
610 {"----", NULL, NothingProc},
611 {"Mail Move", "Mail Move", MailMoveProc},
612 {"Reload CMail Message", "Reload CMail Message", ReloadCmailMsgProc},
613 {"----", NULL, NothingProc},
614 {"Exit", "Exit", QuitProc},
618 MenuItem editMenu[] = {
619 {"Copy Game", "Copy Game", CopyGameProc},
620 {"Copy Position", "Copy Position", CopyPositionProc},
621 {"----", NULL, NothingProc},
622 {"Paste Game", "Paste Game", PasteGameProc},
623 {"Paste Position", "Paste Position", PastePositionProc},
624 {"----", NULL, NothingProc},
625 {"Edit Game", "Edit Game", EditGameProc},
626 {"Edit Position", "Edit Position", EditPositionProc},
627 {"----", NULL, NothingProc},
628 {"Edit Tags", "Edit Tags", EditTagsProc},
629 {"Edit Comment", "Edit Comment", EditCommentProc},
630 {"----", NULL, NothingProc},
631 {"Revert", "Revert", RevertProc},
632 {"Annotate", "Annotate", AnnotateProc},
633 {"Truncate Game", "Truncate Game", TruncateGameProc},
634 {"----", NULL, NothingProc},
635 {"Backward", "Backward", BackwardProc},
636 {"Forward", "Forward", ForwardProc},
637 {"Back to Start", "Back to Start", ToStartProc},
638 {"Forward to End", "Forward to End", ToEndProc},
642 MenuItem viewMenu[] = {
643 {"Flip View", "Flip View", FlipViewProc},
644 {"----", NULL, NothingProc},
645 {"Show Engine Output", "Show Engine Output", EngineOutputProc},
646 {"Show Evaluation Graph", "Show Evaluation Graph", EvalGraphProc},
647 {"Show Game List", "Show Game List", ShowGameListProc},
648 {"Show Move History", "Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
649 {"----", NULL, NothingProc},
650 {"Show Tags", "Show Tags", EditTagsProc},
651 {"Show Comments", "Show Comments", EditCommentProc},
652 {"ICS Input Box", "ICS Input Box", IcsInputBoxProc},
656 MenuItem modeMenu[] = {
657 {"Machine White", "Machine White", MachineWhiteProc},
658 {"Machine Black", "Machine Black", MachineBlackProc},
659 {"Two Machines", "Two Machines", TwoMachinesProc},
660 {"Analysis Mode", "Analysis Mode", AnalyzeModeProc},
661 {"Analyze File", "Analyze File", AnalyzeFileProc },
662 {"Edit Game", "Edit Game", EditGameProc},
663 {"Edit Position", "Edit Position", EditPositionProc},
664 {"Training", "Training", TrainingProc},
665 {"ICS Client", "ICS Client", IcsClientProc},
666 {"----", NULL, NothingProc},
667 {"Pause", "Pause", PauseProc},
671 MenuItem actionMenu[] = {
672 {"Accept", "Accept", AcceptProc},
673 {"Decline", "Decline", DeclineProc},
674 {"Rematch", "Rematch", RematchProc},
675 {"----", NULL, NothingProc},
676 {"Call Flag", "Call Flag", CallFlagProc},
677 {"Draw", "Draw", DrawProc},
678 {"Adjourn", "Adjourn", AdjournProc},
679 {"Abort", "Abort", AbortProc},
680 {"Resign", "Resign", ResignProc},
681 {"----", NULL, NothingProc},
682 {"Stop Observing", "Stop Observing", StopObservingProc},
683 {"Stop Examining", "Stop Examining", StopExaminingProc},
684 {"Upload to Examine", "Upload to Examine", UploadProc},
685 {"----", NULL, NothingProc},
686 {"Adjudicate to White", "Adjudicate to White", AdjuWhiteProc},
687 {"Adjudicate to Black", "Adjudicate to Black", AdjuBlackProc},
688 {"Adjudicate Draw", "Adjudicate Draw", AdjuDrawProc},
692 MenuItem engineMenu[] = {
693 {"Engine #1 Settings", "Engine #1 Settings", FirstSettingsProc},
694 {"Engine #2 Settings", "Engine #2 Settings", SecondSettingsProc},
695 {"----", NULL, NothingProc},
696 {"Move Now", "Move Now", MoveNowProc},
697 {"Retract Move", "Retract Move", RetractMoveProc},
701 MenuItem optionsMenu[] = {
702 {"Time Control ...", "Time Control ...", TimeControlProc},
703 {"Common Engine ...", "Common Engine ...", UciMenuProc},
704 {"Adjudications ...", "Adjudications ...", EngineMenuProc},
705 {"Game List ...", "Game List ...", GameListOptionsPopUp},
706 {"----", NULL, NothingProc},
707 {"Always Queen", "Always Queen", AlwaysQueenProc},
708 {"Animate Dragging", "Animate Dragging", AnimateDraggingProc},
709 {"Animate Moving", "Animate Moving", AnimateMovingProc},
710 {"Auto Comment", "Auto Comment", AutocommProc},
711 {"Auto Flag", "Auto Flag", AutoflagProc},
712 {"Auto Flip View", "Auto Flip View", AutoflipProc},
713 {"Auto Observe", "Auto Observe", AutobsProc},
714 {"Auto Raise Board", "Auto Raise Board", AutoraiseProc},
715 {"Auto Save", "Auto Save", AutosaveProc},
716 {"Blindfold", "Blindfold", BlindfoldProc},
717 {"Flash Moves", "Flash Moves", FlashMovesProc},
718 {"Get Move List", "Get Move List", GetMoveListProc},
720 {"Highlight Dragging", "Highlight Dragging", HighlightDraggingProc},
722 {"Highlight Last Move", "Highlight Last Move", HighlightLastMoveProc},
723 {"Move Sound", "Move Sound", MoveSoundProc},
724 {"ICS Alarm", "ICS Alarm", IcsAlarmProc},
725 {"Old Save Style", "Old Save Style", OldSaveStyleProc},
726 {"Periodic Updates", "Periodic Updates", PeriodicUpdatesProc},
727 {"Ponder Next Move", "Ponder Next Move", PonderNextMoveProc},
728 {"Popup Exit Message", "Popup Exit Message", PopupExitMessageProc},
729 {"Popup Move Errors", "Popup Move Errors", PopupMoveErrorsProc},
730 {"Premove", "Premove", PremoveProc},
731 {"Quiet Play", "Quiet Play", QuietPlayProc},
732 {"Show Coords", "Show Coords", ShowCoordsProc},
733 {"Hide Thinking", "Hide Thinking", HideThinkingProc},
734 {"Test Legality", "Test Legality", TestLegalityProc},
735 {"----", NULL, NothingProc},
736 {"Save Settings Now", "Save Settings Now", SaveSettingsProc},
737 {"Save Settings on Exit", "Save Settings on Exit", SaveOnExitProc},
741 MenuItem helpMenu[] = {
742 {"Info XBoard", "Info XBoard", InfoProc},
743 {"Man XBoard", "Man XBoard", ManProc},
744 {"----", NULL, NothingProc},
745 {"Hint", "Hint", HintProc},
746 {"Book", "Book", BookProc},
747 {"----", NULL, NothingProc},
748 {"About XBoard", "About XBoard", AboutProc},
753 {"File", "File", fileMenu},
754 {"Edit", "Edit", editMenu},
755 {"View", "View", viewMenu},
756 {"Mode", "Mode", modeMenu},
757 {"Action", "Action", actionMenu},
758 {"Engine", "Engine", engineMenu},
759 {"Options", "Options", optionsMenu},
760 {"Help", "Help", helpMenu},
764 #define PAUSE_BUTTON "P"
765 MenuItem buttonBar[] = {
766 {"<<", "<<", ToStartProc},
767 {"<", "<", BackwardProc},
768 {PAUSE_BUTTON, PAUSE_BUTTON, PauseProc},
769 {">", ">", ForwardProc},
770 {">>", ">>", ToEndProc},
774 #define PIECE_MENU_SIZE 18
775 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
776 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
777 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
778 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
779 N_("Empty square"), N_("Clear board") },
780 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
781 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
782 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
783 N_("Empty square"), N_("Clear board") }
785 /* must be in same order as PieceMenuStrings! */
786 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
787 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
788 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
789 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
790 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
791 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
792 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
793 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
794 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
797 #define DROP_MENU_SIZE 6
798 String dropMenuStrings[DROP_MENU_SIZE] = {
799 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
801 /* must be in same order as PieceMenuStrings! */
802 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
803 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
804 WhiteRook, WhiteQueen
812 DropMenuEnables dmEnables[] = {
830 { XtNborderWidth, 0 },
831 { XtNdefaultDistance, 0 },
835 { XtNborderWidth, 0 },
836 { XtNresizable, (XtArgVal) True },
840 { XtNborderWidth, 0 },
846 { XtNjustify, (XtArgVal) XtJustifyRight },
847 { XtNlabel, (XtArgVal) "..." },
848 { XtNresizable, (XtArgVal) True },
849 { XtNresize, (XtArgVal) False }
852 Arg messageArgs[] = {
853 { XtNjustify, (XtArgVal) XtJustifyLeft },
854 { XtNlabel, (XtArgVal) "..." },
855 { XtNresizable, (XtArgVal) True },
856 { XtNresize, (XtArgVal) False }
860 { XtNborderWidth, 0 },
861 { XtNjustify, (XtArgVal) XtJustifyLeft }
864 XtResource clientResources[] = {
865 { "flashCount", "flashCount", XtRInt, sizeof(int),
866 XtOffset(AppDataPtr, flashCount), XtRImmediate,
867 (XtPointer) FLASH_COUNT },
870 XrmOptionDescRec shellOptions[] = {
871 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
872 { "-flash", "flashCount", XrmoptionNoArg, "3" },
873 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
876 XtActionsRec boardActions[] = {
877 { "DrawPosition", DrawPositionProc },
878 { "HandleUserMove", HandleUserMove },
879 { "AnimateUserMove", AnimateUserMove },
880 { "HandlePV", HandlePV },
881 { "SelectPV", SelectPV },
882 { "StopPV", StopPV },
883 { "FileNameAction", FileNameAction },
884 { "AskQuestionProc", AskQuestionProc },
885 { "AskQuestionReplyAction", AskQuestionReplyAction },
886 { "PieceMenuPopup", PieceMenuPopup },
887 { "WhiteClock", WhiteClock },
888 { "BlackClock", BlackClock },
889 { "Iconify", Iconify },
890 { "ResetProc", ResetProc },
891 { "NewVariantProc", NewVariantProc },
892 { "LoadGameProc", LoadGameProc },
893 { "LoadNextGameProc", LoadNextGameProc },
894 { "LoadPrevGameProc", LoadPrevGameProc },
895 { "LoadSelectedProc", LoadSelectedProc },
896 { "SetFilterProc", SetFilterProc },
897 { "ReloadGameProc", ReloadGameProc },
898 { "LoadPositionProc", LoadPositionProc },
899 { "LoadNextPositionProc", LoadNextPositionProc },
900 { "LoadPrevPositionProc", LoadPrevPositionProc },
901 { "ReloadPositionProc", ReloadPositionProc },
902 { "CopyPositionProc", CopyPositionProc },
903 { "PastePositionProc", PastePositionProc },
904 { "CopyGameProc", CopyGameProc },
905 { "PasteGameProc", PasteGameProc },
906 { "SaveGameProc", SaveGameProc },
907 { "SavePositionProc", SavePositionProc },
908 { "MailMoveProc", MailMoveProc },
909 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
910 { "QuitProc", QuitProc },
911 { "MachineWhiteProc", MachineWhiteProc },
912 { "MachineBlackProc", MachineBlackProc },
913 { "AnalysisModeProc", AnalyzeModeProc },
914 { "AnalyzeFileProc", AnalyzeFileProc },
915 { "TwoMachinesProc", TwoMachinesProc },
916 { "IcsClientProc", IcsClientProc },
917 { "EditGameProc", EditGameProc },
918 { "EditPositionProc", EditPositionProc },
919 { "TrainingProc", EditPositionProc },
920 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
921 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
922 { "ShowGameListProc", ShowGameListProc },
923 { "ShowMoveListProc", HistoryShowProc},
924 { "EditTagsProc", EditCommentProc },
925 { "EditCommentProc", EditCommentProc },
926 { "IcsAlarmProc", IcsAlarmProc },
927 { "IcsInputBoxProc", IcsInputBoxProc },
928 { "PauseProc", PauseProc },
929 { "AcceptProc", AcceptProc },
930 { "DeclineProc", DeclineProc },
931 { "RematchProc", RematchProc },
932 { "CallFlagProc", CallFlagProc },
933 { "DrawProc", DrawProc },
934 { "AdjournProc", AdjournProc },
935 { "AbortProc", AbortProc },
936 { "ResignProc", ResignProc },
937 { "AdjuWhiteProc", AdjuWhiteProc },
938 { "AdjuBlackProc", AdjuBlackProc },
939 { "AdjuDrawProc", AdjuDrawProc },
940 { "EnterKeyProc", EnterKeyProc },
941 { "UpKeyProc", UpKeyProc },
942 { "DownKeyProc", DownKeyProc },
943 { "StopObservingProc", StopObservingProc },
944 { "StopExaminingProc", StopExaminingProc },
945 { "UploadProc", UploadProc },
946 { "BackwardProc", BackwardProc },
947 { "ForwardProc", ForwardProc },
948 { "ToStartProc", ToStartProc },
949 { "ToEndProc", ToEndProc },
950 { "RevertProc", RevertProc },
951 { "AnnotateProc", AnnotateProc },
952 { "TruncateGameProc", TruncateGameProc },
953 { "MoveNowProc", MoveNowProc },
954 { "RetractMoveProc", RetractMoveProc },
955 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
956 { "UciMenuProc", (XtActionProc) UciMenuProc },
957 { "TimeControlProc", (XtActionProc) TimeControlProc },
958 { "AlwaysQueenProc", AlwaysQueenProc },
959 { "AnimateDraggingProc", AnimateDraggingProc },
960 { "AnimateMovingProc", AnimateMovingProc },
961 { "AutoflagProc", AutoflagProc },
962 { "AutoflipProc", AutoflipProc },
963 { "AutobsProc", AutobsProc },
964 { "AutoraiseProc", AutoraiseProc },
965 { "AutosaveProc", AutosaveProc },
966 { "BlindfoldProc", BlindfoldProc },
967 { "FlashMovesProc", FlashMovesProc },
968 { "FlipViewProc", FlipViewProc },
969 { "GetMoveListProc", GetMoveListProc },
971 { "HighlightDraggingProc", HighlightDraggingProc },
973 { "HighlightLastMoveProc", HighlightLastMoveProc },
974 { "IcsAlarmProc", IcsAlarmProc },
975 { "MoveSoundProc", MoveSoundProc },
976 { "OldSaveStyleProc", OldSaveStyleProc },
977 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
978 { "PonderNextMoveProc", PonderNextMoveProc },
979 { "PopupExitMessageProc", PopupExitMessageProc },
980 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
981 { "PremoveProc", PremoveProc },
982 { "QuietPlayProc", QuietPlayProc },
983 { "ShowCoordsProc", ShowCoordsProc },
984 { "ShowThinkingProc", ShowThinkingProc },
985 { "HideThinkingProc", HideThinkingProc },
986 { "TestLegalityProc", TestLegalityProc },
987 { "SaveSettingsProc", SaveSettingsProc },
988 { "SaveOnExitProc", SaveOnExitProc },
989 { "InfoProc", InfoProc },
990 { "ManProc", ManProc },
991 { "HintProc", HintProc },
992 { "BookProc", BookProc },
993 { "AboutGameProc", AboutGameProc },
994 { "AboutProc", AboutProc },
995 { "DebugProc", DebugProc },
996 { "NothingProc", NothingProc },
997 { "CommentClick", (XtActionProc) CommentClick },
998 { "CommentPopDown", (XtActionProc) CommentPopDown },
999 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
1000 { "TagsPopDown", (XtActionProc) TagsPopDown },
1001 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
1002 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
1003 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
1004 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
1005 { "GameListPopDown", (XtActionProc) GameListPopDown },
1006 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
1007 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1008 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
1009 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1010 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1011 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
1012 { "EnginePopDown", (XtActionProc) EnginePopDown },
1013 { "UciPopDown", (XtActionProc) UciPopDown },
1014 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
1015 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
1016 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
1017 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1020 char globalTranslations[] =
1021 ":<Key>F9: ResignProc() \n \
1022 :Ctrl<Key>n: ResetProc() \n \
1023 :Meta<Key>V: NewVariantProc() \n \
1024 :Ctrl<Key>o: LoadGameProc() \n \
1025 :Meta<Key>Next: LoadNextGameProc() \n \
1026 :Meta<Key>Prior: LoadPrevGameProc() \n \
1027 :Ctrl<Key>s: SaveGameProc() \n \
1028 :Ctrl<Key>c: CopyGameProc() \n \
1029 :Ctrl<Key>v: PasteGameProc() \n \
1030 :Ctrl<Key>O: LoadPositionProc() \n \
1031 :Shift Meta<Key>Next: LoadNextPositionProc() \n \
1032 :Shift Meta<Key>Prior: LoadPrevPositionProc() \n \
1033 :Ctrl<Key>S: SavePositionProc() \n \
1034 :Ctrl<Key>C: CopyPositionProc() \n \
1035 :Ctrl<Key>V: PastePositionProc() \n \
1036 :Ctrl<Key>q: QuitProc() \n \
1037 :Ctrl<Key>w: MachineWhiteProc() \n \
1038 :Ctrl<Key>b: MachineBlackProc() \n \
1039 :Ctrl<Key>t: TwoMachinesProc() \n \
1040 :Ctrl<Key>a: AnalysisModeProc() \n \
1041 :Ctrl<Key>f: AnalyzeFileProc() \n \
1042 :Ctrl<Key>e: EditGameProc() \n \
1043 :Ctrl<Key>E: EditPositionProc() \n \
1044 :Meta<Key>O: EngineOutputProc() \n \
1045 :Meta<Key>E: EvalGraphProc() \n \
1046 :Meta<Key>G: ShowGameListProc() \n \
1047 :Meta<Key>H: ShowMoveListProc() \n \
1048 :<Key>Pause: PauseProc() \n \
1049 :<Key>F3: AcceptProc() \n \
1050 :<Key>F4: DeclineProc() \n \
1051 :<Key>F12: RematchProc() \n \
1052 :<Key>F5: CallFlagProc() \n \
1053 :<Key>F6: DrawProc() \n \
1054 :<Key>F7: AdjournProc() \n \
1055 :<Key>F8: AbortProc() \n \
1056 :<Key>F10: StopObservingProc() \n \
1057 :<Key>F11: StopExaminingProc() \n \
1058 :Meta Ctrl<Key>F12: DebugProc() \n \
1059 :Meta<Key>End: ToEndProc() \n \
1060 :Meta<Key>Right: ForwardProc() \n \
1061 :Meta<Key>Home: ToStartProc() \n \
1062 :Meta<Key>Left: BackwardProc() \n \
1063 :Ctrl<Key>m: MoveNowProc() \n \
1064 :Ctrl<Key>x: RetractMoveProc() \n \
1065 :Meta<Key>J: EngineMenuProc() \n \
1066 :Meta<Key>U: UciMenuProc() \n \
1067 :Meta<Key>T: TimeControlProc() \n \
1068 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1069 :Ctrl<Key>F: AutoflagProc() \n \
1070 :Ctrl<Key>A: AnimateMovingProc() \n \
1071 :Ctrl<Key>P: PonderNextMoveProc() \n \
1072 :Ctrl<Key>L: TestLegalityProc() \n \
1073 :Ctrl<Key>H: HideThinkingProc() \n \
1074 :<Key>-: Iconify() \n \
1075 :<Key>F1: ManProc() \n \
1076 :<Key>F2: FlipViewProc() \n \
1077 <KeyDown>.: BackwardProc() \n \
1078 <KeyUp>.: ForwardProc() \n \
1079 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1080 \"Send to chess program:\",,1) \n \
1081 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1082 \"Send to second chess program:\",,2) \n";
1084 char boardTranslations[] =
1085 "<Btn1Down>: HandleUserMove(0) \n \
1086 Shift<Btn1Up>: HandleUserMove(1) \n \
1087 <Btn1Up>: HandleUserMove(0) \n \
1088 <Btn1Motion>: AnimateUserMove() \n \
1089 <Btn3Motion>: HandlePV() \n \
1090 <Btn3Up>: PieceMenuPopup(menuB) \n \
1091 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1092 PieceMenuPopup(menuB) \n \
1093 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1094 PieceMenuPopup(menuW) \n \
1095 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1096 PieceMenuPopup(menuW) \n \
1097 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1098 PieceMenuPopup(menuB) \n";
1100 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1101 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1103 char ICSInputTranslations[] =
1104 "<Key>Up: UpKeyProc() \n "
1105 "<Key>Down: DownKeyProc() \n "
1106 "<Key>Return: EnterKeyProc() \n";
1108 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1109 // as the widget is destroyed before the up-click can call extend-end
1110 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1112 String xboardResources[] = {
1113 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1114 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1115 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1120 /* Max possible square size */
1121 #define MAXSQSIZE 256
1123 static int xpm_avail[MAXSQSIZE];
1125 #ifdef HAVE_DIR_STRUCT
1127 /* Extract piece size from filename */
1129 xpm_getsize(name, len, ext)
1140 if ((p=strchr(name, '.')) == NULL ||
1141 StrCaseCmp(p+1, ext) != 0)
1147 while (*p && isdigit(*p))
1154 /* Setup xpm_avail */
1156 xpm_getavail(dirname, ext)
1164 for (i=0; i<MAXSQSIZE; ++i)
1167 if (appData.debugMode)
1168 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1170 dir = opendir(dirname);
1173 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1174 programName, dirname);
1178 while ((ent=readdir(dir)) != NULL) {
1179 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1180 if (i > 0 && i < MAXSQSIZE)
1190 xpm_print_avail(fp, ext)
1196 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1197 for (i=1; i<MAXSQSIZE; ++i) {
1203 /* Return XPM piecesize closest to size */
1205 xpm_closest_to(dirname, size, ext)
1211 int sm_diff = MAXSQSIZE;
1215 xpm_getavail(dirname, ext);
1217 if (appData.debugMode)
1218 xpm_print_avail(stderr, ext);
1220 for (i=1; i<MAXSQSIZE; ++i) {
1223 diff = (diff<0) ? -diff : diff;
1224 if (diff < sm_diff) {
1232 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1238 #else /* !HAVE_DIR_STRUCT */
1239 /* If we are on a system without a DIR struct, we can't
1240 read the directory, so we can't collect a list of
1241 filenames, etc., so we can't do any size-fitting. */
1243 xpm_closest_to(dirname, size, ext)
1248 fprintf(stderr, _("\
1249 Warning: No DIR structure found on this system --\n\
1250 Unable to autosize for XPM/XIM pieces.\n\
1251 Please report this error to frankm@hiwaay.net.\n\
1252 Include system type & operating system in message.\n"));
1255 #endif /* HAVE_DIR_STRUCT */
1257 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1258 "magenta", "cyan", "white" };
1262 TextColors textColors[(int)NColorClasses];
1264 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1266 parse_color(str, which)
1270 char *p, buf[100], *d;
1273 if (strlen(str) > 99) /* watch bounds on buf */
1278 for (i=0; i<which; ++i) {
1285 /* Could be looking at something like:
1287 .. in which case we want to stop on a comma also */
1288 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1292 return -1; /* Use default for empty field */
1295 if (which == 2 || isdigit(*p))
1298 while (*p && isalpha(*p))
1303 for (i=0; i<8; ++i) {
1304 if (!StrCaseCmp(buf, cnames[i]))
1305 return which? (i+40) : (i+30);
1307 if (!StrCaseCmp(buf, "default")) return -1;
1309 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1314 parse_cpair(cc, str)
1318 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1319 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1324 /* bg and attr are optional */
1325 textColors[(int)cc].bg = parse_color(str, 1);
1326 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1327 textColors[(int)cc].attr = 0;
1333 /* Arrange to catch delete-window events */
1334 Atom wm_delete_window;
1336 CatchDeleteWindow(Widget w, String procname)
1339 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1340 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1341 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1348 XtSetArg(args[0], XtNiconic, False);
1349 XtSetValues(shellWidget, args, 1);
1351 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1354 //---------------------------------------------------------------------------------------------------------
1355 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1358 #define CW_USEDEFAULT (1<<31)
1359 #define ICS_TEXT_MENU_SIZE 90
1360 #define DEBUG_FILE "xboard.debug"
1361 #define SetCurrentDirectory chdir
1362 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1366 // these two must some day move to frontend.h, when they are implemented
1367 Boolean GameListIsUp();
1369 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1372 // front-end part of option handling
1374 // [HGM] This platform-dependent table provides the location for storing the color info
1375 extern char *crWhite, * crBlack;
1379 &appData.whitePieceColor,
1380 &appData.blackPieceColor,
1381 &appData.lightSquareColor,
1382 &appData.darkSquareColor,
1383 &appData.highlightSquareColor,
1384 &appData.premoveHighlightColor,
1385 &appData.lowTimeWarningColor,
1396 // [HGM] font: keep a font for each square size, even non-stndard ones
1397 #define NUM_SIZES 18
1398 #define MAX_SIZE 130
1399 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1400 char *fontTable[NUM_FONTS][MAX_SIZE];
1403 ParseFont(char *name, int number)
1404 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1406 if(sscanf(name, "size%d:", &size)) {
1407 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1408 // defer processing it until we know if it matches our board size
1409 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1410 fontTable[number][size] = strdup(strchr(name, ':')+1);
1411 fontValid[number][size] = True;
1416 case 0: // CLOCK_FONT
1417 appData.clockFont = strdup(name);
1419 case 1: // MESSAGE_FONT
1420 appData.font = strdup(name);
1422 case 2: // COORD_FONT
1423 appData.coordFont = strdup(name);
1428 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1433 { // only 2 fonts currently
1434 appData.clockFont = CLOCK_FONT_NAME;
1435 appData.coordFont = COORD_FONT_NAME;
1436 appData.font = DEFAULT_FONT_NAME;
1441 { // no-op, until we identify the code for this already in XBoard and move it here
1445 ParseColor(int n, char *name)
1446 { // in XBoard, just copy the color-name string
1447 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1451 ParseTextAttribs(ColorClass cc, char *s)
1453 (&appData.colorShout)[cc] = strdup(s);
1457 ParseBoardSize(void *addr, char *name)
1459 appData.boardSize = strdup(name);
1464 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1468 SetCommPortDefaults()
1469 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1472 // [HGM] args: these three cases taken out to stay in front-end
1474 SaveFontArg(FILE *f, ArgDescriptor *ad)
1477 int i, n = (int)ad->argLoc;
1479 case 0: // CLOCK_FONT
1480 name = appData.clockFont;
1482 case 1: // MESSAGE_FONT
1483 name = appData.font;
1485 case 2: // COORD_FONT
1486 name = appData.coordFont;
1491 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1492 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1493 fontTable[n][squareSize] = strdup(name);
1494 fontValid[n][squareSize] = True;
1497 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1498 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1503 { // nothing to do, as the sounds are at all times represented by their text-string names already
1507 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1508 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1509 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1513 SaveColor(FILE *f, ArgDescriptor *ad)
1514 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1515 if(colorVariable[(int)ad->argLoc])
1516 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1520 SaveBoardSize(FILE *f, char *name, void *addr)
1521 { // wrapper to shield back-end from BoardSize & sizeInfo
1522 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1526 ParseCommPortSettings(char *s)
1527 { // no such option in XBoard (yet)
1530 extern Widget engineOutputShell;
1531 extern Widget tagsShell, editTagsShell;
1533 GetActualPlacement(Widget wg, WindowPlacement *wp)
1543 XtSetArg(args[i], XtNx, &x); i++;
1544 XtSetArg(args[i], XtNy, &y); i++;
1545 XtSetArg(args[i], XtNwidth, &w); i++;
1546 XtSetArg(args[i], XtNheight, &h); i++;
1547 XtGetValues(wg, args, i);
1556 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1557 // In XBoard this will have to wait until awareness of window parameters is implemented
1558 GetActualPlacement(shellWidget, &wpMain);
1559 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1560 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1561 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1562 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1563 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1564 else GetActualPlacement(editShell, &wpComment);
1565 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1566 else GetActualPlacement(editTagsShell, &wpTags);
1570 PrintCommPortSettings(FILE *f, char *name)
1571 { // This option does not exist in XBoard
1575 MySearchPath(char *installDir, char *name, char *fullname)
1576 { // just append installDir and name. Perhaps ExpandPath should be used here?
1577 name = ExpandPathName(name);
1578 if(name && name[0] == '/')
1579 safeStrCpy(fullname, name, MSG_SIZ );
1581 sprintf(fullname, "%s%c%s", installDir, '/', name);
1587 MyGetFullPathName(char *name, char *fullname)
1588 { // should use ExpandPath?
1589 name = ExpandPathName(name);
1590 safeStrCpy(fullname, name, MSG_SIZ );
1595 EnsureOnScreen(int *x, int *y, int minX, int minY)
1602 { // [HGM] args: allows testing if main window is realized from back-end
1603 return xBoardWindow != 0;
1607 PopUpStartupDialog()
1608 { // start menu not implemented in XBoard
1612 ConvertToLine(int argc, char **argv)
1614 static char line[128*1024], buf[1024];
1618 for(i=1; i<argc; i++)
1620 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1621 && argv[i][0] != '{' )
1622 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1624 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1625 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1628 line[strlen(line)-1] = NULLCHAR;
1632 //--------------------------------------------------------------------------------------------
1634 extern Boolean twoBoards, partnerUp;
1637 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1639 #define BoardSize int
1640 void InitDrawingSizes(BoardSize boardSize, int flags)
1641 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1642 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1644 XtGeometryResult gres;
1647 if(!formWidget) return;
1650 * Enable shell resizing.
1652 shellArgs[0].value = (XtArgVal) &w;
1653 shellArgs[1].value = (XtArgVal) &h;
1654 XtGetValues(shellWidget, shellArgs, 2);
1656 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1657 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1658 XtSetValues(shellWidget, &shellArgs[2], 4);
1660 XtSetArg(args[0], XtNdefaultDistance, &sep);
1661 XtGetValues(formWidget, args, 1);
1663 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1664 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1666 hOffset = boardWidth + 10;
1667 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1668 secondSegments[i] = gridSegments[i];
1669 secondSegments[i].x1 += hOffset;
1670 secondSegments[i].x2 += hOffset;
1673 XtSetArg(args[0], XtNwidth, boardWidth);
1674 XtSetArg(args[1], XtNheight, boardHeight);
1675 XtSetValues(boardWidget, args, 2);
1677 timerWidth = (boardWidth - sep) / 2;
1678 XtSetArg(args[0], XtNwidth, timerWidth);
1679 XtSetValues(whiteTimerWidget, args, 1);
1680 XtSetValues(blackTimerWidget, args, 1);
1682 XawFormDoLayout(formWidget, False);
1684 if (appData.titleInWindow) {
1686 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1687 XtSetArg(args[i], XtNheight, &h); i++;
1688 XtGetValues(titleWidget, args, i);
1690 w = boardWidth - 2*bor;
1692 XtSetArg(args[0], XtNwidth, &w);
1693 XtGetValues(menuBarWidget, args, 1);
1694 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1697 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1698 if (gres != XtGeometryYes && appData.debugMode) {
1700 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1701 programName, gres, w, h, wr, hr);
1705 XawFormDoLayout(formWidget, True);
1708 * Inhibit shell resizing.
1710 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1711 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1712 shellArgs[4].value = shellArgs[2].value = w;
1713 shellArgs[5].value = shellArgs[3].value = h;
1714 XtSetValues(shellWidget, &shellArgs[0], 6);
1716 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1719 for(i=0; i<4; i++) {
1721 for(p=0; p<=(int)WhiteKing; p++)
1722 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1723 if(gameInfo.variant == VariantShogi) {
1724 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1725 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1726 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1727 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1728 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1731 if(gameInfo.variant == VariantGothic) {
1732 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1735 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1736 xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
1737 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1740 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1741 for(p=0; p<=(int)WhiteKing; p++)
1742 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1743 if(gameInfo.variant == VariantShogi) {
1744 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1745 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1746 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1747 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1748 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1751 if(gameInfo.variant == VariantGothic) {
1752 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1755 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1756 ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
1757 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1762 for(i=0; i<2; i++) {
1764 for(p=0; p<=(int)WhiteKing; p++)
1765 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1766 if(gameInfo.variant == VariantShogi) {
1767 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1768 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1769 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1770 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1771 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1774 if(gameInfo.variant == VariantGothic) {
1775 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1778 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1779 pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
1780 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1795 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1796 XSetWindowAttributes window_attributes;
1798 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1799 XrmValue vFrom, vTo;
1800 XtGeometryResult gres;
1803 int forceMono = False;
1805 srandom(time(0)); // [HGM] book: make random truly random
1807 setbuf(stdout, NULL);
1808 setbuf(stderr, NULL);
1811 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1812 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1816 programName = strrchr(argv[0], '/');
1817 if (programName == NULL)
1818 programName = argv[0];
1823 XtSetLanguageProc(NULL, NULL, NULL);
1824 bindtextdomain(PACKAGE, LOCALEDIR);
1825 textdomain(PACKAGE);
1829 XtAppInitialize(&appContext, "XBoard", shellOptions,
1830 XtNumber(shellOptions),
1831 &argc, argv, xboardResources, NULL, 0);
1832 appData.boardSize = "";
1833 InitAppData(ConvertToLine(argc, argv));
1835 if (p == NULL) p = "/tmp";
1836 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1837 gameCopyFilename = (char*) malloc(i);
1838 gamePasteFilename = (char*) malloc(i);
1839 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1840 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1842 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1843 clientResources, XtNumber(clientResources),
1846 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1847 static char buf[MSG_SIZ];
1848 EscapeExpand(buf, appData.initString);
1849 appData.initString = strdup(buf);
1850 EscapeExpand(buf, appData.secondInitString);
1851 appData.secondInitString = strdup(buf);
1852 EscapeExpand(buf, appData.firstComputerString);
1853 appData.firstComputerString = strdup(buf);
1854 EscapeExpand(buf, appData.secondComputerString);
1855 appData.secondComputerString = strdup(buf);
1858 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1861 if (chdir(chessDir) != 0) {
1862 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1868 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1869 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1870 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1871 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1874 setbuf(debugFP, NULL);
1877 /* [HGM,HR] make sure board size is acceptable */
1878 if(appData.NrFiles > BOARD_FILES ||
1879 appData.NrRanks > BOARD_RANKS )
1880 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1883 /* This feature does not work; animation needs a rewrite */
1884 appData.highlightDragging = FALSE;
1888 xDisplay = XtDisplay(shellWidget);
1889 xScreen = DefaultScreen(xDisplay);
1890 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1892 gameInfo.variant = StringToVariant(appData.variant);
1893 InitPosition(FALSE);
1896 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1898 if (isdigit(appData.boardSize[0])) {
1899 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1900 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1901 &fontPxlSize, &smallLayout, &tinyLayout);
1903 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1904 programName, appData.boardSize);
1908 /* Find some defaults; use the nearest known size */
1909 SizeDefaults *szd, *nearest;
1910 int distance = 99999;
1911 nearest = szd = sizeDefaults;
1912 while (szd->name != NULL) {
1913 if (abs(szd->squareSize - squareSize) < distance) {
1915 distance = abs(szd->squareSize - squareSize);
1916 if (distance == 0) break;
1920 if (i < 2) lineGap = nearest->lineGap;
1921 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1922 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1923 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1924 if (i < 6) smallLayout = nearest->smallLayout;
1925 if (i < 7) tinyLayout = nearest->tinyLayout;
1928 SizeDefaults *szd = sizeDefaults;
1929 if (*appData.boardSize == NULLCHAR) {
1930 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1931 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1934 if (szd->name == NULL) szd--;
1935 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1937 while (szd->name != NULL &&
1938 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1939 if (szd->name == NULL) {
1940 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1941 programName, appData.boardSize);
1945 squareSize = szd->squareSize;
1946 lineGap = szd->lineGap;
1947 clockFontPxlSize = szd->clockFontPxlSize;
1948 coordFontPxlSize = szd->coordFontPxlSize;
1949 fontPxlSize = szd->fontPxlSize;
1950 smallLayout = szd->smallLayout;
1951 tinyLayout = szd->tinyLayout;
1952 // [HGM] font: use defaults from settings file if available and not overruled
1954 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
1955 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
1956 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
1957 appData.font = fontTable[MESSAGE_FONT][squareSize];
1958 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
1959 appData.coordFont = fontTable[COORD_FONT][squareSize];
1961 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1962 if (strlen(appData.pixmapDirectory) > 0) {
1963 p = ExpandPathName(appData.pixmapDirectory);
1965 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1966 appData.pixmapDirectory);
1969 if (appData.debugMode) {
1970 fprintf(stderr, _("\
1971 XBoard square size (hint): %d\n\
1972 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1974 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1975 if (appData.debugMode) {
1976 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1979 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1981 /* [HR] height treated separately (hacked) */
1982 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1983 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1984 if (appData.showJail == 1) {
1985 /* Jail on top and bottom */
1986 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1987 XtSetArg(boardArgs[2], XtNheight,
1988 boardHeight + 2*(lineGap + squareSize));
1989 } else if (appData.showJail == 2) {
1991 XtSetArg(boardArgs[1], XtNwidth,
1992 boardWidth + 2*(lineGap + squareSize));
1993 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1996 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1997 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2001 * Determine what fonts to use.
2003 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2004 clockFontID = XLoadFont(xDisplay, appData.clockFont);
2005 clockFontStruct = XQueryFont(xDisplay, clockFontID);
2006 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2007 coordFontID = XLoadFont(xDisplay, appData.coordFont);
2008 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2009 appData.font = FindFont(appData.font, fontPxlSize);
2010 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
2011 countFontStruct = XQueryFont(xDisplay, countFontID);
2012 // appData.font = FindFont(appData.font, fontPxlSize);
2014 xdb = XtDatabase(xDisplay);
2015 XrmPutStringResource(&xdb, "*font", appData.font);
2018 * Detect if there are not enough colors available and adapt.
2020 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2021 appData.monoMode = True;
2024 if (!appData.monoMode) {
2025 vFrom.addr = (caddr_t) appData.lightSquareColor;
2026 vFrom.size = strlen(appData.lightSquareColor);
2027 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2028 if (vTo.addr == NULL) {
2029 appData.monoMode = True;
2032 lightSquareColor = *(Pixel *) vTo.addr;
2035 if (!appData.monoMode) {
2036 vFrom.addr = (caddr_t) appData.darkSquareColor;
2037 vFrom.size = strlen(appData.darkSquareColor);
2038 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2039 if (vTo.addr == NULL) {
2040 appData.monoMode = True;
2043 darkSquareColor = *(Pixel *) vTo.addr;
2046 if (!appData.monoMode) {
2047 vFrom.addr = (caddr_t) appData.whitePieceColor;
2048 vFrom.size = strlen(appData.whitePieceColor);
2049 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2050 if (vTo.addr == NULL) {
2051 appData.monoMode = True;
2054 whitePieceColor = *(Pixel *) vTo.addr;
2057 if (!appData.monoMode) {
2058 vFrom.addr = (caddr_t) appData.blackPieceColor;
2059 vFrom.size = strlen(appData.blackPieceColor);
2060 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2061 if (vTo.addr == NULL) {
2062 appData.monoMode = True;
2065 blackPieceColor = *(Pixel *) vTo.addr;
2069 if (!appData.monoMode) {
2070 vFrom.addr = (caddr_t) appData.highlightSquareColor;
2071 vFrom.size = strlen(appData.highlightSquareColor);
2072 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2073 if (vTo.addr == NULL) {
2074 appData.monoMode = True;
2077 highlightSquareColor = *(Pixel *) vTo.addr;
2081 if (!appData.monoMode) {
2082 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
2083 vFrom.size = strlen(appData.premoveHighlightColor);
2084 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2085 if (vTo.addr == NULL) {
2086 appData.monoMode = True;
2089 premoveHighlightColor = *(Pixel *) vTo.addr;
2094 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2097 if (appData.bitmapDirectory == NULL ||
2098 appData.bitmapDirectory[0] == NULLCHAR)
2099 appData.bitmapDirectory = DEF_BITMAP_DIR;
2102 if (appData.lowTimeWarning && !appData.monoMode) {
2103 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2104 vFrom.size = strlen(appData.lowTimeWarningColor);
2105 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2106 if (vTo.addr == NULL)
2107 appData.monoMode = True;
2109 lowTimeWarningColor = *(Pixel *) vTo.addr;
2112 if (appData.monoMode && appData.debugMode) {
2113 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2114 (unsigned long) XWhitePixel(xDisplay, xScreen),
2115 (unsigned long) XBlackPixel(xDisplay, xScreen));
2118 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2119 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2120 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2121 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2122 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2123 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2124 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2125 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2126 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2127 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2129 if (appData.colorize) {
2131 _("%s: can't parse color names; disabling colorization\n"),
2134 appData.colorize = FALSE;
2136 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2137 textColors[ColorNone].attr = 0;
2139 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2145 layoutName = "tinyLayout";
2146 } else if (smallLayout) {
2147 layoutName = "smallLayout";
2149 layoutName = "normalLayout";
2151 /* Outer layoutWidget is there only to provide a name for use in
2152 resources that depend on the layout style */
2154 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2155 layoutArgs, XtNumber(layoutArgs));
2157 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2158 formArgs, XtNumber(formArgs));
2159 XtSetArg(args[0], XtNdefaultDistance, &sep);
2160 XtGetValues(formWidget, args, 1);
2163 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2164 XtSetArg(args[0], XtNtop, XtChainTop);
2165 XtSetArg(args[1], XtNbottom, XtChainTop);
2166 XtSetArg(args[2], XtNright, XtChainLeft);
2167 XtSetValues(menuBarWidget, args, 3);
2169 widgetList[j++] = whiteTimerWidget =
2170 XtCreateWidget("whiteTime", labelWidgetClass,
2171 formWidget, timerArgs, XtNumber(timerArgs));
2172 XtSetArg(args[0], XtNfont, clockFontStruct);
2173 XtSetArg(args[1], XtNtop, XtChainTop);
2174 XtSetArg(args[2], XtNbottom, XtChainTop);
2175 XtSetValues(whiteTimerWidget, args, 3);
2177 widgetList[j++] = blackTimerWidget =
2178 XtCreateWidget("blackTime", labelWidgetClass,
2179 formWidget, timerArgs, XtNumber(timerArgs));
2180 XtSetArg(args[0], XtNfont, clockFontStruct);
2181 XtSetArg(args[1], XtNtop, XtChainTop);
2182 XtSetArg(args[2], XtNbottom, XtChainTop);
2183 XtSetValues(blackTimerWidget, args, 3);
2185 if (appData.titleInWindow) {
2186 widgetList[j++] = titleWidget =
2187 XtCreateWidget("title", labelWidgetClass, formWidget,
2188 titleArgs, XtNumber(titleArgs));
2189 XtSetArg(args[0], XtNtop, XtChainTop);
2190 XtSetArg(args[1], XtNbottom, XtChainTop);
2191 XtSetValues(titleWidget, args, 2);
2194 if (appData.showButtonBar) {
2195 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2196 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2197 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2198 XtSetArg(args[2], XtNtop, XtChainTop);
2199 XtSetArg(args[3], XtNbottom, XtChainTop);
2200 XtSetValues(buttonBarWidget, args, 4);
2203 widgetList[j++] = messageWidget =
2204 XtCreateWidget("message", labelWidgetClass, formWidget,
2205 messageArgs, XtNumber(messageArgs));
2206 XtSetArg(args[0], XtNtop, XtChainTop);
2207 XtSetArg(args[1], XtNbottom, XtChainTop);
2208 XtSetValues(messageWidget, args, 2);
2210 widgetList[j++] = boardWidget =
2211 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2212 XtNumber(boardArgs));
2214 XtManageChildren(widgetList, j);
2216 timerWidth = (boardWidth - sep) / 2;
2217 XtSetArg(args[0], XtNwidth, timerWidth);
2218 XtSetValues(whiteTimerWidget, args, 1);
2219 XtSetValues(blackTimerWidget, args, 1);
2221 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2222 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2223 XtGetValues(whiteTimerWidget, args, 2);
2225 if (appData.showButtonBar) {
2226 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2227 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2228 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2232 * formWidget uses these constraints but they are stored
2236 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2237 XtSetValues(menuBarWidget, args, i);
2238 if (appData.titleInWindow) {
2241 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2242 XtSetValues(whiteTimerWidget, args, i);
2244 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2245 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2246 XtSetValues(blackTimerWidget, args, i);
2248 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2249 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2250 XtSetValues(titleWidget, args, i);
2252 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2253 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2254 XtSetValues(messageWidget, args, i);
2255 if (appData.showButtonBar) {
2257 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2258 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2259 XtSetValues(buttonBarWidget, args, i);
2263 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2264 XtSetValues(whiteTimerWidget, args, i);
2266 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2267 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2268 XtSetValues(blackTimerWidget, args, i);
2270 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2271 XtSetValues(titleWidget, args, i);
2273 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2274 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2275 XtSetValues(messageWidget, args, i);
2276 if (appData.showButtonBar) {
2278 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2279 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2280 XtSetValues(buttonBarWidget, args, i);
2285 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2286 XtSetValues(whiteTimerWidget, args, i);
2288 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2289 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2290 XtSetValues(blackTimerWidget, args, i);
2292 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2293 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2294 XtSetValues(messageWidget, args, i);
2295 if (appData.showButtonBar) {
2297 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2298 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2299 XtSetValues(buttonBarWidget, args, i);
2303 XtSetArg(args[0], XtNfromVert, messageWidget);
2304 XtSetArg(args[1], XtNtop, XtChainTop);
2305 XtSetArg(args[2], XtNbottom, XtChainBottom);
2306 XtSetArg(args[3], XtNleft, XtChainLeft);
2307 XtSetArg(args[4], XtNright, XtChainRight);
2308 XtSetValues(boardWidget, args, 5);
2310 XtRealizeWidget(shellWidget);
2313 XtSetArg(args[0], XtNx, wpMain.x);
2314 XtSetArg(args[1], XtNy, wpMain.y);
2315 XtSetValues(shellWidget, args, 2);
2319 * Correct the width of the message and title widgets.
2320 * It is not known why some systems need the extra fudge term.
2321 * The value "2" is probably larger than needed.
2323 XawFormDoLayout(formWidget, False);
2325 #define WIDTH_FUDGE 2
2327 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2328 XtSetArg(args[i], XtNheight, &h); i++;
2329 XtGetValues(messageWidget, args, i);
2330 if (appData.showButtonBar) {
2332 XtSetArg(args[i], XtNwidth, &w); i++;
2333 XtGetValues(buttonBarWidget, args, i);
2334 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2336 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2339 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2340 if (gres != XtGeometryYes && appData.debugMode) {
2341 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2342 programName, gres, w, h, wr, hr);
2345 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2346 /* The size used for the child widget in layout lags one resize behind
2347 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2349 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2350 if (gres != XtGeometryYes && appData.debugMode) {
2351 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2352 programName, gres, w, h, wr, hr);
2355 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2356 XtSetArg(args[1], XtNright, XtChainRight);
2357 XtSetValues(messageWidget, args, 2);
2359 if (appData.titleInWindow) {
2361 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2362 XtSetArg(args[i], XtNheight, &h); i++;
2363 XtGetValues(titleWidget, args, i);
2365 w = boardWidth - 2*bor;
2367 XtSetArg(args[0], XtNwidth, &w);
2368 XtGetValues(menuBarWidget, args, 1);
2369 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2372 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2373 if (gres != XtGeometryYes && appData.debugMode) {
2375 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2376 programName, gres, w, h, wr, hr);
2379 XawFormDoLayout(formWidget, True);
2381 xBoardWindow = XtWindow(boardWidget);
2383 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2384 // not need to go into InitDrawingSizes().
2388 * Create X checkmark bitmap and initialize option menu checks.
2390 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2391 checkmark_bits, checkmark_width, checkmark_height);
2392 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2393 if (appData.alwaysPromoteToQueen) {
2394 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2397 if (appData.animateDragging) {
2398 XtSetValues(XtNameToWidget(menuBarWidget,
2399 "menuOptions.Animate Dragging"),
2402 if (appData.animate) {
2403 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2406 if (appData.autoComment) {
2407 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2410 if (appData.autoCallFlag) {
2411 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2414 if (appData.autoFlipView) {
2415 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2418 if (appData.autoObserve) {
2419 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2422 if (appData.autoRaiseBoard) {
2423 XtSetValues(XtNameToWidget(menuBarWidget,
2424 "menuOptions.Auto Raise Board"), args, 1);
2426 if (appData.autoSaveGames) {
2427 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2430 if (appData.saveGameFile[0] != NULLCHAR) {
2431 /* Can't turn this off from menu */
2432 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2434 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2438 if (appData.blindfold) {
2439 XtSetValues(XtNameToWidget(menuBarWidget,
2440 "menuOptions.Blindfold"), args, 1);
2442 if (appData.flashCount > 0) {
2443 XtSetValues(XtNameToWidget(menuBarWidget,
2444 "menuOptions.Flash Moves"),
2447 if (appData.getMoveList) {
2448 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2452 if (appData.highlightDragging) {
2453 XtSetValues(XtNameToWidget(menuBarWidget,
2454 "menuOptions.Highlight Dragging"),
2458 if (appData.highlightLastMove) {
2459 XtSetValues(XtNameToWidget(menuBarWidget,
2460 "menuOptions.Highlight Last Move"),
2463 if (appData.icsAlarm) {
2464 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2467 if (appData.ringBellAfterMoves) {
2468 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2471 if (appData.oldSaveStyle) {
2472 XtSetValues(XtNameToWidget(menuBarWidget,
2473 "menuOptions.Old Save Style"), args, 1);
2475 if (appData.periodicUpdates) {
2476 XtSetValues(XtNameToWidget(menuBarWidget,
2477 "menuOptions.Periodic Updates"), args, 1);
2479 if (appData.ponderNextMove) {
2480 XtSetValues(XtNameToWidget(menuBarWidget,
2481 "menuOptions.Ponder Next Move"), args, 1);
2483 if (appData.popupExitMessage) {
2484 XtSetValues(XtNameToWidget(menuBarWidget,
2485 "menuOptions.Popup Exit Message"), args, 1);
2487 if (appData.popupMoveErrors) {
2488 XtSetValues(XtNameToWidget(menuBarWidget,
2489 "menuOptions.Popup Move Errors"), args, 1);
2491 if (appData.premove) {
2492 XtSetValues(XtNameToWidget(menuBarWidget,
2493 "menuOptions.Premove"), args, 1);
2495 if (appData.quietPlay) {
2496 XtSetValues(XtNameToWidget(menuBarWidget,
2497 "menuOptions.Quiet Play"), args, 1);
2499 if (appData.showCoords) {
2500 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2503 if (appData.hideThinkingFromHuman) {
2504 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2507 if (appData.testLegality) {
2508 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2511 if (saveSettingsOnExit) {
2512 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2519 ReadBitmap(&wIconPixmap, "icon_white.bm",
2520 icon_white_bits, icon_white_width, icon_white_height);
2521 ReadBitmap(&bIconPixmap, "icon_black.bm",
2522 icon_black_bits, icon_black_width, icon_black_height);
2523 iconPixmap = wIconPixmap;
2525 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2526 XtSetValues(shellWidget, args, i);
2529 * Create a cursor for the board widget.
2531 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2532 XChangeWindowAttributes(xDisplay, xBoardWindow,
2533 CWCursor, &window_attributes);
2536 * Inhibit shell resizing.
2538 shellArgs[0].value = (XtArgVal) &w;
2539 shellArgs[1].value = (XtArgVal) &h;
2540 XtGetValues(shellWidget, shellArgs, 2);
2541 shellArgs[4].value = shellArgs[2].value = w;
2542 shellArgs[5].value = shellArgs[3].value = h;
2543 XtSetValues(shellWidget, &shellArgs[2], 4);
2544 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2545 marginH = h - boardHeight;
2547 CatchDeleteWindow(shellWidget, "QuitProc");
2552 if (appData.bitmapDirectory[0] != NULLCHAR) {
2556 CreateXPMBoard(appData.liteBackTextureFile, 1);
2557 CreateXPMBoard(appData.darkBackTextureFile, 0);
2561 /* Create regular pieces */
2562 if (!useImages) CreatePieces();
2567 if (appData.animate || appData.animateDragging)
2570 XtAugmentTranslations(formWidget,
2571 XtParseTranslationTable(globalTranslations));
2572 XtAugmentTranslations(boardWidget,
2573 XtParseTranslationTable(boardTranslations));
2574 XtAugmentTranslations(whiteTimerWidget,
2575 XtParseTranslationTable(whiteTranslations));
2576 XtAugmentTranslations(blackTimerWidget,
2577 XtParseTranslationTable(blackTranslations));
2579 /* Why is the following needed on some versions of X instead
2580 * of a translation? */
2581 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2582 (XtEventHandler) EventProc, NULL);
2585 /* [AS] Restore layout */
2586 if( wpMoveHistory.visible ) {
2590 if( wpEvalGraph.visible )
2595 if( wpEngineOutput.visible ) {
2596 EngineOutputPopUp();
2601 if (errorExitStatus == -1) {
2602 if (appData.icsActive) {
2603 /* We now wait until we see "login:" from the ICS before
2604 sending the logon script (problems with timestamp otherwise) */
2605 /*ICSInitScript();*/
2606 if (appData.icsInputBox) ICSInputBoxPopUp();
2610 signal(SIGWINCH, TermSizeSigHandler);
2612 signal(SIGINT, IntSigHandler);
2613 signal(SIGTERM, IntSigHandler);
2614 if (*appData.cmailGameName != NULLCHAR) {
2615 signal(SIGUSR1, CmailSigHandler);
2618 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2620 XtSetKeyboardFocus(shellWidget, formWidget);
2622 XtAppMainLoop(appContext);
2623 if (appData.debugMode) fclose(debugFP); // [DM] debug
2630 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2631 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2633 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2634 unlink(gameCopyFilename);
2635 unlink(gamePasteFilename);
2638 RETSIGTYPE TermSizeSigHandler(int sig)
2651 CmailSigHandler(sig)
2657 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2659 /* Activate call-back function CmailSigHandlerCallBack() */
2660 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2662 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2666 CmailSigHandlerCallBack(isr, closure, message, count, error)
2674 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2676 /**** end signal code ****/
2682 /* try to open the icsLogon script, either in the location given
2683 * or in the users HOME directory
2690 f = fopen(appData.icsLogon, "r");
2693 homedir = getenv("HOME");
2694 if (homedir != NULL)
2696 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2697 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2698 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2699 f = fopen(buf, "r");
2704 ProcessICSInitScript(f);
2706 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2715 EditCommentPopDown();
2730 if (!menuBarWidget) return;
2731 w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2733 DisplayError("menuEdit.Revert", 0);
2735 XtSetSensitive(w, !grey);
2737 w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2739 DisplayError("menuEdit.Annotate", 0);
2741 XtSetSensitive(w, !grey);
2746 SetMenuEnables(enab)
2750 if (!menuBarWidget) return;
2751 while (enab->name != NULL) {
2752 w = XtNameToWidget(menuBarWidget, enab->name);
2754 DisplayError(enab->name, 0);
2756 XtSetSensitive(w, enab->value);
2762 Enables icsEnables[] = {
2763 { "menuFile.Mail Move", False },
2764 { "menuFile.Reload CMail Message", False },
2765 { "menuMode.Machine Black", False },
2766 { "menuMode.Machine White", False },
2767 { "menuMode.Analysis Mode", False },
2768 { "menuMode.Analyze File", False },
2769 { "menuMode.Two Machines", False },
2771 { "menuHelp.Hint", False },
2772 { "menuHelp.Book", False },
2773 { "menuEngine.Move Now", False },
2774 { "menuOptions.Periodic Updates", False },
2775 { "menuOptions.Hide Thinking", False },
2776 { "menuOptions.Ponder Next Move", False },
2777 { "menuEngine.Engine #1 Settings", False },
2779 { "menuEngine.Engine #2 Settings", False },
2780 { "menuEdit.Annotate", False },
2784 Enables ncpEnables[] = {
2785 { "menuFile.Mail Move", False },
2786 { "menuFile.Reload CMail Message", False },
2787 { "menuMode.Machine White", False },
2788 { "menuMode.Machine Black", False },
2789 { "menuMode.Analysis Mode", False },
2790 { "menuMode.Analyze File", False },
2791 { "menuMode.Two Machines", False },
2792 { "menuMode.ICS Client", False },
2793 { "menuView.ICS Input Box", False },
2794 { "Action", False },
2795 { "menuEdit.Revert", False },
2796 { "menuEdit.Annotate", False },
2797 { "menuEngine.Engine #1 Settings", False },
2798 { "menuEngine.Engine #2 Settings", False },
2799 { "menuEngine.Move Now", False },
2800 { "menuEngine.Retract Move", False },
2801 { "menuOptions.Auto Comment", False },
2802 { "menuOptions.Auto Flag", False },
2803 { "menuOptions.Auto Flip View", False },
2804 { "menuOptions.Auto Observe", False },
2805 { "menuOptions.Auto Raise Board", False },
2806 { "menuOptions.Get Move List", False },
2807 { "menuOptions.ICS Alarm", False },
2808 { "menuOptions.Move Sound", False },
2809 { "menuOptions.Quiet Play", False },
2810 { "menuOptions.Hide Thinking", False },
2811 { "menuOptions.Periodic Updates", False },
2812 { "menuOptions.Ponder Next Move", False },
2813 { "menuHelp.Hint", False },
2814 { "menuHelp.Book", False },
2818 Enables gnuEnables[] = {
2819 { "menuMode.ICS Client", False },
2820 { "menuView.ICS Input Box", False },
2821 { "menuAction.Accept", False },
2822 { "menuAction.Decline", False },
2823 { "menuAction.Rematch", False },
2824 { "menuAction.Adjourn", False },
2825 { "menuAction.Stop Examining", False },
2826 { "menuAction.Stop Observing", False },
2827 { "menuAction.Upload to Examine", False },
2828 { "menuEdit.Revert", False },
2829 { "menuEdit.Annotate", False },
2830 { "menuOptions.Auto Comment", False },
2831 { "menuOptions.Auto Observe", False },
2832 { "menuOptions.Auto Raise Board", False },
2833 { "menuOptions.Get Move List", False },
2834 { "menuOptions.Premove", False },
2835 { "menuOptions.Quiet Play", False },
2837 /* The next two options rely on SetCmailMode being called *after* */
2838 /* SetGNUMode so that when GNU is being used to give hints these */
2839 /* menu options are still available */
2841 { "menuFile.Mail Move", False },
2842 { "menuFile.Reload CMail Message", False },
2846 Enables cmailEnables[] = {
2848 { "menuAction.Call Flag", False },
2849 { "menuAction.Draw", True },
2850 { "menuAction.Adjourn", False },
2851 { "menuAction.Abort", False },
2852 { "menuAction.Stop Observing", False },
2853 { "menuAction.Stop Examining", False },
2854 { "menuFile.Mail Move", True },
2855 { "menuFile.Reload CMail Message", True },
2859 Enables trainingOnEnables[] = {
2860 { "menuMode.Edit Comment", False },
2861 { "menuMode.Pause", False },
2862 { "menuEdit.Forward", False },
2863 { "menuEdit.Backward", False },
2864 { "menuEdit.Forward to End", False },
2865 { "menuEdit.Back to Start", False },
2866 { "menuEngine.Move Now", False },
2867 { "menuEdit.Truncate Game", False },
2871 Enables trainingOffEnables[] = {
2872 { "menuMode.Edit Comment", True },
2873 { "menuMode.Pause", True },
2874 { "menuEdit.Forward", True },
2875 { "menuEdit.Backward", True },
2876 { "menuEdit.Forward to End", True },
2877 { "menuEdit.Back to Start", True },
2878 { "menuEngine.Move Now", True },
2879 { "menuEdit.Truncate Game", True },
2883 Enables machineThinkingEnables[] = {
2884 { "menuFile.Load Game", False },
2885 // { "menuFile.Load Next Game", False },
2886 // { "menuFile.Load Previous Game", False },
2887 // { "menuFile.Reload Same Game", False },
2888 { "menuEdit.Paste Game", False },
2889 { "menuFile.Load Position", False },
2890 // { "menuFile.Load Next Position", False },
2891 // { "menuFile.Load Previous Position", False },
2892 // { "menuFile.Reload Same Position", False },
2893 { "menuEdit.Paste Position", False },
2894 { "menuMode.Machine White", False },
2895 { "menuMode.Machine Black", False },
2896 { "menuMode.Two Machines", False },
2897 { "menuEngine.Retract Move", False },
2901 Enables userThinkingEnables[] = {
2902 { "menuFile.Load Game", True },
2903 // { "menuFile.Load Next Game", True },
2904 // { "menuFile.Load Previous Game", True },
2905 // { "menuFile.Reload Same Game", True },
2906 { "menuEdit.Paste Game", True },
2907 { "menuFile.Load Position", True },
2908 // { "menuFile.Load Next Position", True },
2909 // { "menuFile.Load Previous Position", True },
2910 // { "menuFile.Reload Same Position", True },
2911 { "menuEdit.Paste Position", True },
2912 { "menuMode.Machine White", True },
2913 { "menuMode.Machine Black", True },
2914 { "menuMode.Two Machines", True },
2915 { "menuEngine.Retract Move", True },
2921 SetMenuEnables(icsEnables);
2924 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2925 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2932 SetMenuEnables(ncpEnables);
2938 SetMenuEnables(gnuEnables);
2944 SetMenuEnables(cmailEnables);
2950 SetMenuEnables(trainingOnEnables);
2951 if (appData.showButtonBar) {
2952 XtSetSensitive(buttonBarWidget, False);
2958 SetTrainingModeOff()
2960 SetMenuEnables(trainingOffEnables);
2961 if (appData.showButtonBar) {
2962 XtSetSensitive(buttonBarWidget, True);
2967 SetUserThinkingEnables()
2969 if (appData.noChessProgram) return;
2970 SetMenuEnables(userThinkingEnables);
2974 SetMachineThinkingEnables()
2976 if (appData.noChessProgram) return;
2977 SetMenuEnables(machineThinkingEnables);
2979 case MachinePlaysBlack:
2980 case MachinePlaysWhite:
2981 case TwoMachinesPlay:
2982 XtSetSensitive(XtNameToWidget(menuBarWidget,
2983 ModeToWidgetName(gameMode)), True);
2990 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2991 #define HISTORY_SIZE 64
\r
2992 static char *history[HISTORY_SIZE];
\r
2993 int histIn = 0, histP = 0;
\r
2996 SaveInHistory(char *cmd)
\r
2998 if (history[histIn] != NULL) {
\r
2999 free(history[histIn]);
\r
3000 history[histIn] = NULL;
\r
3002 if (*cmd == NULLCHAR) return;
\r
3003 history[histIn] = StrSave(cmd);
\r
3004 histIn = (histIn + 1) % HISTORY_SIZE;
\r
3005 if (history[histIn] != NULL) {
\r
3006 free(history[histIn]);
\r
3007 history[histIn] = NULL;
\r
3013 PrevInHistory(char *cmd)
\r
3016 if (histP == histIn) {
\r
3017 if (history[histIn] != NULL) free(history[histIn]);
\r
3018 history[histIn] = StrSave(cmd);
\r
3020 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
3021 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
3023 return history[histP];
\r
3029 if (histP == histIn) return NULL;
\r
3030 histP = (histP + 1) % HISTORY_SIZE;
\r
3031 return history[histP];
\r
3033 // end of borrowed code
\r
3035 #define Abs(n) ((n)<0 ? -(n) : (n))
3038 * Find a font that matches "pattern" that is as close as
3039 * possible to the targetPxlSize. Prefer fonts that are k
3040 * pixels smaller to fonts that are k pixels larger. The
3041 * pattern must be in the X Consortium standard format,
3042 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3043 * The return value should be freed with XtFree when no
3047 FindFont(pattern, targetPxlSize)
3051 char **fonts, *p, *best, *scalable, *scalableTail;
3052 int i, j, nfonts, minerr, err, pxlSize;
3055 char **missing_list;
3057 char *def_string, *base_fnt_lst, strInt[3];
3059 XFontStruct **fnt_list;
3061 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3062 snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
3063 p = strstr(pattern, "--");
3064 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3065 strcat(base_fnt_lst, strInt);
3066 strcat(base_fnt_lst, strchr(p + 2, '-'));
3068 if ((fntSet = XCreateFontSet(xDisplay,
3072 &def_string)) == NULL) {
3074 fprintf(stderr, _("Unable to create font set.\n"));
3078 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3080 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3082 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3083 programName, pattern);
3091 for (i=0; i<nfonts; i++) {
3094 if (*p != '-') continue;
3096 if (*p == NULLCHAR) break;
3097 if (*p++ == '-') j++;
3099 if (j < 7) continue;
3102 scalable = fonts[i];
3105 err = pxlSize - targetPxlSize;
3106 if (Abs(err) < Abs(minerr) ||
3107 (minerr > 0 && err < 0 && -err == minerr)) {
3113 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3114 /* If the error is too big and there is a scalable font,
3115 use the scalable font. */
3116 int headlen = scalableTail - scalable;
3117 p = (char *) XtMalloc(strlen(scalable) + 10);
3118 while (isdigit(*scalableTail)) scalableTail++;
3119 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3121 p = (char *) XtMalloc(strlen(best) + 2);
3122 safeStrCpy(p, best, strlen(best)+1 );
3124 if (appData.debugMode) {
3125 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3126 pattern, targetPxlSize, p);
3129 if (missing_count > 0)
3130 XFreeStringList(missing_list);
3131 XFreeFontSet(xDisplay, fntSet);
3133 XFreeFontNames(fonts);
3140 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3141 | GCBackground | GCFunction | GCPlaneMask;
3142 XGCValues gc_values;
3145 gc_values.plane_mask = AllPlanes;
3146 gc_values.line_width = lineGap;
3147 gc_values.line_style = LineSolid;
3148 gc_values.function = GXcopy;
3150 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3151 gc_values.background = XBlackPixel(xDisplay, xScreen);
3152 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3154 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3155 gc_values.background = XWhitePixel(xDisplay, xScreen);
3156 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3157 XSetFont(xDisplay, coordGC, coordFontID);
3159 // [HGM] make font for holdings counts (white on black0
3160 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3161 gc_values.background = XBlackPixel(xDisplay, xScreen);
3162 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3163 XSetFont(xDisplay, countGC, countFontID);
3165 if (appData.monoMode) {
3166 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3167 gc_values.background = XWhitePixel(xDisplay, xScreen);
3168 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3170 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3171 gc_values.background = XBlackPixel(xDisplay, xScreen);
3172 lightSquareGC = wbPieceGC
3173 = XtGetGC(shellWidget, value_mask, &gc_values);
3175 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3176 gc_values.background = XWhitePixel(xDisplay, xScreen);
3177 darkSquareGC = bwPieceGC
3178 = XtGetGC(shellWidget, value_mask, &gc_values);
3180 if (DefaultDepth(xDisplay, xScreen) == 1) {
3181 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3182 gc_values.function = GXcopyInverted;
3183 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3184 gc_values.function = GXcopy;
3185 if (XBlackPixel(xDisplay, xScreen) == 1) {
3186 bwPieceGC = darkSquareGC;
3187 wbPieceGC = copyInvertedGC;
3189 bwPieceGC = copyInvertedGC;
3190 wbPieceGC = lightSquareGC;
3194 gc_values.foreground = highlightSquareColor;
3195 gc_values.background = highlightSquareColor;
3196 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3198 gc_values.foreground = premoveHighlightColor;
3199 gc_values.background = premoveHighlightColor;
3200 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3202 gc_values.foreground = lightSquareColor;
3203 gc_values.background = darkSquareColor;
3204 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3206 gc_values.foreground = darkSquareColor;
3207 gc_values.background = lightSquareColor;
3208 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3210 gc_values.foreground = jailSquareColor;
3211 gc_values.background = jailSquareColor;
3212 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3214 gc_values.foreground = whitePieceColor;
3215 gc_values.background = darkSquareColor;
3216 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3218 gc_values.foreground = whitePieceColor;
3219 gc_values.background = lightSquareColor;
3220 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3222 gc_values.foreground = whitePieceColor;
3223 gc_values.background = jailSquareColor;
3224 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3226 gc_values.foreground = blackPieceColor;
3227 gc_values.background = darkSquareColor;
3228 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3230 gc_values.foreground = blackPieceColor;
3231 gc_values.background = lightSquareColor;
3232 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3234 gc_values.foreground = blackPieceColor;
3235 gc_values.background = jailSquareColor;
3236 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3240 void loadXIM(xim, xmask, filename, dest, mask)
3253 fp = fopen(filename, "rb");
3255 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3262 for (y=0; y<h; ++y) {
3263 for (x=0; x<h; ++x) {
3268 XPutPixel(xim, x, y, blackPieceColor);
3270 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3273 XPutPixel(xim, x, y, darkSquareColor);
3275 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3278 XPutPixel(xim, x, y, whitePieceColor);
3280 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3283 XPutPixel(xim, x, y, lightSquareColor);
3285 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3291 /* create Pixmap of piece */
3292 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3294 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3297 /* create Pixmap of clipmask
3298 Note: We assume the white/black pieces have the same
3299 outline, so we make only 6 masks. This is okay
3300 since the XPM clipmask routines do the same. */
3302 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3304 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3307 /* now create the 1-bit version */
3308 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3311 values.foreground = 1;
3312 values.background = 0;
3314 /* Don't use XtGetGC, not read only */
3315 maskGC = XCreateGC(xDisplay, *mask,
3316 GCForeground | GCBackground, &values);
3317 XCopyPlane(xDisplay, temp, *mask, maskGC,
3318 0, 0, squareSize, squareSize, 0, 0, 1);
3319 XFreePixmap(xDisplay, temp);
3324 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3326 void CreateXIMPieces()
3331 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3336 /* The XSynchronize calls were copied from CreatePieces.
3337 Not sure if needed, but can't hurt */
3338 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3341 /* temp needed by loadXIM() */
3342 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3343 0, 0, ss, ss, AllPlanes, XYPixmap);
3345 if (strlen(appData.pixmapDirectory) == 0) {
3349 if (appData.monoMode) {
3350 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3354 fprintf(stderr, _("\nLoading XIMs...\n"));
3356 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3357 fprintf(stderr, "%d", piece+1);
3358 for (kind=0; kind<4; kind++) {
3359 fprintf(stderr, ".");
3360 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3361 ExpandPathName(appData.pixmapDirectory),
3362 piece <= (int) WhiteKing ? "" : "w",
3363 pieceBitmapNames[piece],
3365 ximPieceBitmap[kind][piece] =
3366 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3367 0, 0, ss, ss, AllPlanes, XYPixmap);
3368 if (appData.debugMode)
3369 fprintf(stderr, _("(File:%s:) "), buf);
3370 loadXIM(ximPieceBitmap[kind][piece],
3372 &(xpmPieceBitmap2[kind][piece]),
3373 &(ximMaskPm2[piece]));
3374 if(piece <= (int)WhiteKing)
3375 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3377 fprintf(stderr," ");
3379 /* Load light and dark squares */
3380 /* If the LSQ and DSQ pieces don't exist, we will
3381 draw them with solid squares. */
3382 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3383 if (access(buf, 0) != 0) {
3387 fprintf(stderr, _("light square "));
3389 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3390 0, 0, ss, ss, AllPlanes, XYPixmap);
3391 if (appData.debugMode)
3392 fprintf(stderr, _("(File:%s:) "), buf);
3394 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3395 fprintf(stderr, _("dark square "));
3396 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3397 ExpandPathName(appData.pixmapDirectory), ss);
3398 if (appData.debugMode)
3399 fprintf(stderr, _("(File:%s:) "), buf);
3401 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3402 0, 0, ss, ss, AllPlanes, XYPixmap);
3403 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3404 xpmJailSquare = xpmLightSquare;
3406 fprintf(stderr, _("Done.\n"));
3408 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3412 void CreateXPMBoard(char *s, int kind)
3416 if(s == NULL || *s == 0 || *s == '*') return;
3417 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3418 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3422 void CreateXPMPieces()
3426 u_int ss = squareSize;
3428 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3429 XpmColorSymbol symbols[4];
3431 /* The XSynchronize calls were copied from CreatePieces.
3432 Not sure if needed, but can't hurt */
3433 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3435 /* Setup translations so piece colors match square colors */
3436 symbols[0].name = "light_piece";
3437 symbols[0].value = appData.whitePieceColor;
3438 symbols[1].name = "dark_piece";
3439 symbols[1].value = appData.blackPieceColor;
3440 symbols[2].name = "light_square";
3441 symbols[2].value = appData.lightSquareColor;
3442 symbols[3].name = "dark_square";
3443 symbols[3].value = appData.darkSquareColor;
3445 attr.valuemask = XpmColorSymbols;
3446 attr.colorsymbols = symbols;
3447 attr.numsymbols = 4;
3449 if (appData.monoMode) {
3450 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3454 if (strlen(appData.pixmapDirectory) == 0) {
3455 XpmPieces* pieces = builtInXpms;
3458 while (pieces->size != squareSize && pieces->size) pieces++;
3459 if (!pieces->size) {
3460 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3463 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3464 for (kind=0; kind<4; kind++) {
3466 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3467 pieces->xpm[piece][kind],
3468 &(xpmPieceBitmap2[kind][piece]),
3469 NULL, &attr)) != 0) {
3470 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3474 if(piece <= (int) WhiteKing)
3475 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3479 xpmJailSquare = xpmLightSquare;
3483 fprintf(stderr, _("\nLoading XPMs...\n"));
3486 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3487 fprintf(stderr, "%d ", piece+1);
3488 for (kind=0; kind<4; kind++) {
3489 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3490 ExpandPathName(appData.pixmapDirectory),
3491 piece > (int) WhiteKing ? "w" : "",
3492 pieceBitmapNames[piece],
3494 if (appData.debugMode) {
3495 fprintf(stderr, _("(File:%s:) "), buf);
3497 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3498 &(xpmPieceBitmap2[kind][piece]),
3499 NULL, &attr)) != 0) {
3500 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3501 // [HGM] missing: read of unorthodox piece failed; substitute King.
3502 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3503 ExpandPathName(appData.pixmapDirectory),
3505 if (appData.debugMode) {
3506 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3508 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3509 &(xpmPieceBitmap2[kind][piece]),
3513 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3518 if(piece <= (int) WhiteKing)
3519 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3522 /* Load light and dark squares */
3523 /* If the LSQ and DSQ pieces don't exist, we will
3524 draw them with solid squares. */
3525 fprintf(stderr, _("light square "));
3526 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3527 if (access(buf, 0) != 0) {
3531 if (appData.debugMode)
3532 fprintf(stderr, _("(File:%s:) "), buf);
3534 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3535 &xpmLightSquare, NULL, &attr)) != 0) {
3536 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3539 fprintf(stderr, _("dark square "));
3540 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3541 ExpandPathName(appData.pixmapDirectory), ss);
3542 if (appData.debugMode) {
3543 fprintf(stderr, _("(File:%s:) "), buf);
3545 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3546 &xpmDarkSquare, NULL, &attr)) != 0) {
3547 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3551 xpmJailSquare = xpmLightSquare;
3552 fprintf(stderr, _("Done.\n"));
3554 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3557 #endif /* HAVE_LIBXPM */
3560 /* No built-in bitmaps */
3565 u_int ss = squareSize;
3567 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3570 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3571 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3572 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3573 pieceBitmapNames[piece],
3574 ss, kind == SOLID ? 's' : 'o');
3575 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3576 if(piece <= (int)WhiteKing)
3577 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3581 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3585 /* With built-in bitmaps */
3588 BuiltInBits* bib = builtInBits;
3591 u_int ss = squareSize;
3593 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3596 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3598 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3599 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3600 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3601 pieceBitmapNames[piece],
3602 ss, kind == SOLID ? 's' : 'o');
3603 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3604 bib->bits[kind][piece], ss, ss);
3605 if(piece <= (int)WhiteKing)
3606 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3610 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3615 void ReadBitmap(pm, name, bits, wreq, hreq)
3618 unsigned char bits[];
3624 char msg[MSG_SIZ], fullname[MSG_SIZ];
3626 if (*appData.bitmapDirectory != NULLCHAR) {
3627 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3628 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3629 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3630 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3631 &w, &h, pm, &x_hot, &y_hot);
3632 fprintf(stderr, "load %s\n", name);
3633 if (errcode != BitmapSuccess) {
3635 case BitmapOpenFailed:
3636 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3638 case BitmapFileInvalid:
3639 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3641 case BitmapNoMemory:
3642 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3646 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3650 fprintf(stderr, _("%s: %s...using built-in\n"),
3652 } else if (w != wreq || h != hreq) {
3654 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3655 programName, fullname, w, h, wreq, hreq);
3661 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3670 if (lineGap == 0) return;
3672 /* [HR] Split this into 2 loops for non-square boards. */
3674 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3675 gridSegments[i].x1 = 0;
3676 gridSegments[i].x2 =
3677 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3678 gridSegments[i].y1 = gridSegments[i].y2
3679 = lineGap / 2 + (i * (squareSize + lineGap));
3682 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3683 gridSegments[j + i].y1 = 0;
3684 gridSegments[j + i].y2 =
3685 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3686 gridSegments[j + i].x1 = gridSegments[j + i].x2
3687 = lineGap / 2 + (j * (squareSize + lineGap));
3691 static void MenuBarSelect(w, addr, index)
3696 XtActionProc proc = (XtActionProc) addr;
3698 (proc)(NULL, NULL, NULL, NULL);
3701 void CreateMenuBarPopup(parent, name, mb)
3711 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3714 XtSetArg(args[j], XtNleftMargin, 20); j++;
3715 XtSetArg(args[j], XtNrightMargin, 20); j++;
3717 while (mi->string != NULL) {
3718 if (strcmp(mi->string, "----") == 0) {
3719 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3722 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3723 entry = XtCreateManagedWidget(mi->ref, smeBSBObjectClass,
3725 XtAddCallback(entry, XtNcallback,
3726 (XtCallbackProc) MenuBarSelect,
3727 (caddr_t) mi->proc);
3733 Widget CreateMenuBar(mb)
3737 Widget anchor, menuBar;
3739 char menuName[MSG_SIZ];
3742 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3743 XtSetArg(args[j], XtNvSpace, 0); j++;
3744 XtSetArg(args[j], XtNborderWidth, 0); j++;
3745 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3746 formWidget, args, j);
3748 while (mb->name != NULL) {
3749 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3750 strncat(menuName, mb->ref, MSG_SIZ - strlen(menuName) - 1);
3752 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3755 shortName[0] = _(mb->name)[0];
3756 shortName[1] = NULLCHAR;
3757 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3760 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3763 XtSetArg(args[j], XtNborderWidth, 0); j++;
3764 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3766 CreateMenuBarPopup(menuBar, menuName, mb);
3772 Widget CreateButtonBar(mi)
3776 Widget button, buttonBar;
3780 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3782 XtSetArg(args[j], XtNhSpace, 0); j++;
3784 XtSetArg(args[j], XtNborderWidth, 0); j++;
3785 XtSetArg(args[j], XtNvSpace, 0); j++;
3786 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3787 formWidget, args, j);
3789 while (mi->string != NULL) {
3792 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3793 XtSetArg(args[j], XtNborderWidth, 0); j++;
3795 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3796 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3797 buttonBar, args, j);
3798 XtAddCallback(button, XtNcallback,
3799 (XtCallbackProc) MenuBarSelect,
3800 (caddr_t) mi->proc);
3807 CreatePieceMenu(name, color)
3814 ChessSquare selection;
3816 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3817 boardWidget, args, 0);
3819 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3820 String item = pieceMenuStrings[color][i];
3822 if (strcmp(item, "----") == 0) {
3823 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3826 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3827 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3829 selection = pieceMenuTranslation[color][i];
3830 XtAddCallback(entry, XtNcallback,
3831 (XtCallbackProc) PieceMenuSelect,
3832 (caddr_t) selection);
3833 if (selection == WhitePawn || selection == BlackPawn) {
3834 XtSetArg(args[0], XtNpopupOnEntry, entry);
3835 XtSetValues(menu, args, 1);
3848 ChessSquare selection;
3850 whitePieceMenu = CreatePieceMenu("menuW", 0);
3851 blackPieceMenu = CreatePieceMenu("menuB", 1);
3853 XtRegisterGrabAction(PieceMenuPopup, True,
3854 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3855 GrabModeAsync, GrabModeAsync);
3857 XtSetArg(args[0], XtNlabel, _("Drop"));
3858 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3859 boardWidget, args, 1);
3860 for (i = 0; i < DROP_MENU_SIZE; i++) {
3861 String item = dropMenuStrings[i];
3863 if (strcmp(item, "----") == 0) {
3864 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3867 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3868 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3870 selection = dropMenuTranslation[i];
3871 XtAddCallback(entry, XtNcallback,
3872 (XtCallbackProc) DropMenuSelect,
3873 (caddr_t) selection);
3878 void SetupDropMenu()
3886 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3887 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3888 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3889 dmEnables[i].piece);
3890 XtSetSensitive(entry, p != NULL || !appData.testLegality
3891 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3892 && !appData.icsActive));
3894 while (p && *p++ == dmEnables[i].piece) count++;
3895 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3897 XtSetArg(args[j], XtNlabel, label); j++;
3898 XtSetValues(entry, args, j);
3902 void PieceMenuPopup(w, event, params, num_params)
3906 Cardinal *num_params;
3908 String whichMenu; int menuNr;
3909 if (event->type == ButtonRelease)
3910 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3911 else if (event->type == ButtonPress)
3912 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3914 case 0: whichMenu = params[0]; break;
3915 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3917 case -1: if (errorUp) ErrorPopDown();
3920 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3923 static void PieceMenuSelect(w, piece, junk)
3928 if (pmFromX < 0 || pmFromY < 0) return;
3929 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3932 static void DropMenuSelect(w, piece, junk)
3937 if (pmFromX < 0 || pmFromY < 0) return;
3938 DropMenuEvent(piece, pmFromX, pmFromY);
3941 void WhiteClock(w, event, prms, nprms)
3947 if (gameMode == EditPosition || gameMode == IcsExamining) {
3948 SetWhiteToPlayEvent();
3949 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3954 void BlackClock(w, event, prms, nprms)
3960 if (gameMode == EditPosition || gameMode == IcsExamining) {
3961 SetBlackToPlayEvent();
3962 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3969 * If the user selects on a border boundary, return -1; if off the board,
3970 * return -2. Otherwise map the event coordinate to the square.
3972 int EventToSquare(x, limit)
3980 if ((x % (squareSize + lineGap)) >= squareSize)
3982 x /= (squareSize + lineGap);
3988 static void do_flash_delay(msec)
3994 static void drawHighlight(file, rank, gc)
4000 if (lineGap == 0 || appData.blindfold) return;
4003 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
4004 (squareSize + lineGap);
4005 y = lineGap/2 + rank * (squareSize + lineGap);
4007 x = lineGap/2 + file * (squareSize + lineGap);
4008 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
4009 (squareSize + lineGap);
4012 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
4013 squareSize+lineGap, squareSize+lineGap);
4016 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
4017 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4020 SetHighlights(fromX, fromY, toX, toY)
4021 int fromX, fromY, toX, toY;
4023 if (hi1X != fromX || hi1Y != fromY) {
4024 if (hi1X >= 0 && hi1Y >= 0) {
4025 drawHighlight(hi1X, hi1Y, lineGC);
4027 } // [HGM] first erase both, then draw new!
4028 if (hi2X != toX || hi2Y != toY) {
4029 if (hi2X >= 0 && hi2Y >= 0) {
4030 drawHighlight(hi2X, hi2Y, lineGC);
4033 if (hi1X != fromX || hi1Y != fromY) {
4034 if (fromX >= 0 && fromY >= 0) {
4035 drawHighlight(fromX, fromY, highlineGC);
4038 if (hi2X != toX || hi2Y != toY) {
4039 if (toX >= 0 && toY >= 0) {
4040 drawHighlight(toX, toY, highlineGC);
4052 SetHighlights(-1, -1, -1, -1);
4057 SetPremoveHighlights(fromX, fromY, toX, toY)
4058 int fromX, fromY, toX, toY;
4060 if (pm1X != fromX || pm1Y != fromY) {
4061 if (pm1X >= 0 && pm1Y >= 0) {
4062 drawHighlight(pm1X, pm1Y, lineGC);
4064 if (fromX >= 0 && fromY >= 0) {
4065 drawHighlight(fromX, fromY, prelineGC);
4068 if (pm2X != toX || pm2Y != toY) {
4069 if (pm2X >= 0 && pm2Y >= 0) {
4070 drawHighlight(pm2X, pm2Y, lineGC);
4072 if (toX >= 0 && toY >= 0) {
4073 drawHighlight(toX, toY, prelineGC);
4083 ClearPremoveHighlights()
4085 SetPremoveHighlights(-1, -1, -1, -1);
4088 static int CutOutSquare(x, y, x0, y0, kind)
4089 int x, y, *x0, *y0, kind;
4091 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
4092 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
4094 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
4095 if(textureW[kind] < W*squareSize)
4096 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
4098 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
4099 if(textureH[kind] < H*squareSize)
4100 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
4102 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
4106 static void BlankSquare(x, y, color, piece, dest, fac)
4107 int x, y, color, fac;
4110 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
4112 if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
4113 XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
4114 squareSize, squareSize, x*fac, y*fac);
4116 if (useImages && useImageSqs) {
4120 pm = xpmLightSquare;
4125 case 2: /* neutral */
4130 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4131 squareSize, squareSize, x*fac, y*fac);
4141 case 2: /* neutral */
4146 XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
4151 I split out the routines to draw a piece so that I could
4152 make a generic flash routine.
4154 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4156 int square_color, x, y;
4159 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4160 switch (square_color) {
4162 case 2: /* neutral */
4164 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4165 ? *pieceToOutline(piece)
4166 : *pieceToSolid(piece),
4167 dest, bwPieceGC, 0, 0,
4168 squareSize, squareSize, x, y);
4171 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4172 ? *pieceToSolid(piece)
4173 : *pieceToOutline(piece),
4174 dest, wbPieceGC, 0, 0,
4175 squareSize, squareSize, x, y);
4180 static void monoDrawPiece(piece, square_color, x, y, dest)
4182 int square_color, x, y;
4185 switch (square_color) {
4187 case 2: /* neutral */
4189 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4190 ? *pieceToOutline(piece)
4191 : *pieceToSolid(piece),
4192 dest, bwPieceGC, 0, 0,
4193 squareSize, squareSize, x, y, 1);
4196 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4197 ? *pieceToSolid(piece)
4198 : *pieceToOutline(piece),
4199 dest, wbPieceGC, 0, 0,
4200 squareSize, squareSize, x, y, 1);
4205 static void colorDrawPiece(piece, square_color, x, y, dest)
4207 int square_color, x, y;
4210 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4211 switch (square_color) {
4213 XCopyPlane(xDisplay, *pieceToSolid(piece),
4214 dest, (int) piece < (int) BlackPawn
4215 ? wlPieceGC : blPieceGC, 0, 0,
4216 squareSize, squareSize, x, y, 1);
4219 XCopyPlane(xDisplay, *pieceToSolid(piece),
4220 dest, (int) piece < (int) BlackPawn
4221 ? wdPieceGC : bdPieceGC, 0, 0,
4222 squareSize, squareSize, x, y, 1);
4224 case 2: /* neutral */
4226 XCopyPlane(xDisplay, *pieceToSolid(piece),
4227 dest, (int) piece < (int) BlackPawn
4228 ? wjPieceGC : bjPieceGC, 0, 0,
4229 squareSize, squareSize, x, y, 1);
4234 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4236 int square_color, x, y;
4239 int kind, p = piece;
4241 switch (square_color) {
4243 case 2: /* neutral */
4245 if ((int)piece < (int) BlackPawn) {
4253 if ((int)piece < (int) BlackPawn) {
4261 if(appData.upsideDown && flipView) kind ^= 2; // swap white and black pieces
4262 if(useTexture & square_color+1) {
4263 BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
4264 XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
4265 XSetClipOrigin(xDisplay, wlPieceGC, x, y);
4266 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);
4267 XSetClipMask(xDisplay, wlPieceGC, None);
4268 XSetClipOrigin(xDisplay, wlPieceGC, 0, 0);
4270 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4271 dest, wlPieceGC, 0, 0,
4272 squareSize, squareSize, x, y);
4275 typedef void (*DrawFunc)();
4277 DrawFunc ChooseDrawFunc()
4279 if (appData.monoMode) {
4280 if (DefaultDepth(xDisplay, xScreen) == 1) {
4281 return monoDrawPiece_1bit;
4283 return monoDrawPiece;
4287 return colorDrawPieceImage;
4289 return colorDrawPiece;
4293 /* [HR] determine square color depending on chess variant. */
4294 static int SquareColor(row, column)
4299 if (gameInfo.variant == VariantXiangqi) {
4300 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4302 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4304 } else if (row <= 4) {
4310 square_color = ((column + row) % 2) == 1;
4313 /* [hgm] holdings: next line makes all holdings squares light */
4314 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4316 return square_color;
4319 void DrawSquare(row, column, piece, do_flash)
4320 int row, column, do_flash;
4323 int square_color, x, y, direction, font_ascent, font_descent;
4326 XCharStruct overall;
4330 /* Calculate delay in milliseconds (2-delays per complete flash) */
4331 flash_delay = 500 / appData.flashRate;
4334 x = lineGap + ((BOARD_WIDTH-1)-column) *
4335 (squareSize + lineGap);
4336 y = lineGap + row * (squareSize + lineGap);
4338 x = lineGap + column * (squareSize + lineGap);
4339 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4340 (squareSize + lineGap);
4343 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4345 square_color = SquareColor(row, column);
4347 if ( // [HGM] holdings: blank out area between board and holdings
4348 column == BOARD_LEFT-1 || column == BOARD_RGHT
4349 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4350 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4351 BlankSquare(x, y, 2, EmptySquare, xBoardWindow, 1);
4353 // [HGM] print piece counts next to holdings
4354 string[1] = NULLCHAR;
4355 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4356 string[0] = '0' + piece;
4357 XTextExtents(countFontStruct, string, 1, &direction,
4358 &font_ascent, &font_descent, &overall);
4359 if (appData.monoMode) {
4360 XDrawImageString(xDisplay, xBoardWindow, countGC,
4361 x + squareSize - overall.width - 2,
4362 y + font_ascent + 1, string, 1);
4364 XDrawString(xDisplay, xBoardWindow, countGC,
4365 x + squareSize - overall.width - 2,
4366 y + font_ascent + 1, string, 1);
4369 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4370 string[0] = '0' + piece;
4371 XTextExtents(countFontStruct, string, 1, &direction,
4372 &font_ascent, &font_descent, &overall);
4373 if (appData.monoMode) {
4374 XDrawImageString(xDisplay, xBoardWindow, countGC,
4375 x + 2, y + font_ascent + 1, string, 1);
4377 XDrawString(xDisplay, xBoardWindow, countGC,
4378 x + 2, y + font_ascent + 1, string, 1);
4382 if (piece == EmptySquare || appData.blindfold) {
4383 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4385 drawfunc = ChooseDrawFunc();
4386 if (do_flash && appData.flashCount > 0) {
4387 for (i=0; i<appData.flashCount; ++i) {
4389 drawfunc(piece, square_color, x, y, xBoardWindow);
4390 XSync(xDisplay, False);
4391 do_flash_delay(flash_delay);
4393 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4394 XSync(xDisplay, False);
4395 do_flash_delay(flash_delay);
4398 drawfunc(piece, square_color, x, y, xBoardWindow);
4402 string[1] = NULLCHAR;
4403 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4404 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4405 string[0] = 'a' + column - BOARD_LEFT;
4406 XTextExtents(coordFontStruct, string, 1, &direction,
4407 &font_ascent, &font_descent, &overall);
4408 if (appData.monoMode) {
4409 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4410 x + squareSize - overall.width - 2,
4411 y + squareSize - font_descent - 1, string, 1);
4413 XDrawString(xDisplay, xBoardWindow, coordGC,
4414 x + squareSize - overall.width - 2,
4415 y + squareSize - font_descent - 1, string, 1);
4418 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4419 string[0] = ONE + row;
4420 XTextExtents(coordFontStruct, string, 1, &direction,
4421 &font_ascent, &font_descent, &overall);
4422 if (appData.monoMode) {
4423 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4424 x + 2, y + font_ascent + 1, string, 1);
4426 XDrawString(xDisplay, xBoardWindow, coordGC,
4427 x + 2, y + font_ascent + 1, string, 1);
4430 if(!partnerUp && marker[row][column]) {
4431 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4432 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4437 /* Why is this needed on some versions of X? */
4438 void EventProc(widget, unused, event)
4443 if (!XtIsRealized(widget))
4446 switch (event->type) {
4448 if (event->xexpose.count > 0) return; /* no clipping is done */
4449 XDrawPosition(widget, True, NULL);
4450 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4451 flipView = !flipView; partnerUp = !partnerUp;
4452 XDrawPosition(widget, True, NULL);
4453 flipView = !flipView; partnerUp = !partnerUp;
4457 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
\r
4464 void DrawPosition(fullRedraw, board)
4465 /*Boolean*/int fullRedraw;
4468 XDrawPosition(boardWidget, fullRedraw, board);
4471 /* Returns 1 if there are "too many" differences between b1 and b2
4472 (i.e. more than 1 move was made) */
4473 static int too_many_diffs(b1, b2)
4479 for (i=0; i<BOARD_HEIGHT; ++i) {
4480 for (j=0; j<BOARD_WIDTH; ++j) {
4481 if (b1[i][j] != b2[i][j]) {
4482 if (++c > 4) /* Castling causes 4 diffs */
4491 /* Matrix describing castling maneuvers */
4492 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4493 static int castling_matrix[4][5] = {
4494 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4495 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4496 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4497 { 7, 7, 4, 5, 6 } /* 0-0, black */
4500 /* Checks whether castling occurred. If it did, *rrow and *rcol
4501 are set to the destination (row,col) of the rook that moved.
4503 Returns 1 if castling occurred, 0 if not.
4505 Note: Only handles a max of 1 castling move, so be sure
4506 to call too_many_diffs() first.
4508 static int check_castle_draw(newb, oldb, rrow, rcol)
4515 /* For each type of castling... */
4516 for (i=0; i<4; ++i) {
4517 r = castling_matrix[i];
4519 /* Check the 4 squares involved in the castling move */
4521 for (j=1; j<=4; ++j) {
4522 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4529 /* All 4 changed, so it must be a castling move */
4538 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4539 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4541 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4544 void DrawSeekBackground( int left, int top, int right, int bottom )
4546 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4549 void DrawSeekText(char *buf, int x, int y)
4551 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4554 void DrawSeekDot(int x, int y, int colorNr)
4556 int square = colorNr & 0x80;
4559 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4561 XFillRectangle(xDisplay, xBoardWindow, color,
4562 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4564 XFillArc(xDisplay, xBoardWindow, color,
4565 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4568 static int damage[2][BOARD_RANKS][BOARD_FILES];
4571 * event handler for redrawing the board
4573 void XDrawPosition(w, repaint, board)
4575 /*Boolean*/int repaint;
4579 static int lastFlipView = 0;
4580 static int lastBoardValid[2] = {0, 0};
4581 static Board lastBoard[2];
4584 int nr = twoBoards*partnerUp;
4586 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4588 if (board == NULL) {
4589 if (!lastBoardValid[nr]) return;
4590 board = lastBoard[nr];
4592 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4593 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4594 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Flip View"),
4599 * It would be simpler to clear the window with XClearWindow()
4600 * but this causes a very distracting flicker.
4603 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4605 /* If too much changes (begin observing new game, etc.), don't
4607 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4609 /* Special check for castling so we don't flash both the king
4610 and the rook (just flash the king). */
4612 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4613 /* Draw rook with NO flashing. King will be drawn flashing later */
4614 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4615 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4619 /* First pass -- Draw (newly) empty squares and repair damage.
4620 This prevents you from having a piece show up twice while it
4621 is flashing on its new square */
4622 for (i = 0; i < BOARD_HEIGHT; i++)
4623 for (j = 0; j < BOARD_WIDTH; j++)
4624 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4625 || damage[nr][i][j]) {
4626 DrawSquare(i, j, board[i][j], 0);
4627 damage[nr][i][j] = False;
4630 /* Second pass -- Draw piece(s) in new position and flash them */
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]) {
4634 DrawSquare(i, j, board[i][j], do_flash);
4638 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4639 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4640 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4642 for (i = 0; i < BOARD_HEIGHT; i++)
4643 for (j = 0; j < BOARD_WIDTH; j++) {
4644 DrawSquare(i, j, board[i][j], 0);
4645 damage[nr][i][j] = False;
4649 CopyBoard(lastBoard[nr], board);
4650 lastBoardValid[nr] = 1;
4651 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4652 lastFlipView = flipView;
4654 /* Draw highlights */
4655 if (pm1X >= 0 && pm1Y >= 0) {
4656 drawHighlight(pm1X, pm1Y, prelineGC);
4658 if (pm2X >= 0 && pm2Y >= 0) {
4659 drawHighlight(pm2X, pm2Y, prelineGC);
4661 if (hi1X >= 0 && hi1Y >= 0) {
4662 drawHighlight(hi1X, hi1Y, highlineGC);
4664 if (hi2X >= 0 && hi2Y >= 0) {
4665 drawHighlight(hi2X, hi2Y, highlineGC);
4668 /* If piece being dragged around board, must redraw that too */
4671 XSync(xDisplay, False);
4676 * event handler for redrawing the board
4678 void DrawPositionProc(w, event, prms, nprms)
4684 XDrawPosition(w, True, NULL);
4689 * event handler for parsing user moves
4691 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4692 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4693 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4694 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4695 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4696 // and at the end FinishMove() to perform the move after optional promotion popups.
4697 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4698 void HandleUserMove(w, event, prms, nprms)
4704 if (w != boardWidget || errorExitStatus != -1) return;
4705 if(nprms) shiftKey = !strcmp(prms[0], "1");
4708 if (event->type == ButtonPress) {
4709 XtPopdown(promotionShell);
4710 XtDestroyWidget(promotionShell);
4711 promotionUp = False;
4719 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4720 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4721 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4724 void AnimateUserMove (Widget w, XEvent * event,
4725 String * params, Cardinal * nParams)
4727 DragPieceMove(event->xmotion.x, event->xmotion.y);
4730 void HandlePV (Widget w, XEvent * event,
4731 String * params, Cardinal * nParams)
4732 { // [HGM] pv: walk PV
4733 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4736 Widget CommentCreate(name, text, mutable, callback, lines)
4738 int /*Boolean*/ mutable;
4739 XtCallbackProc callback;
4743 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4748 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4749 XtGetValues(boardWidget, args, j);
4752 XtSetArg(args[j], XtNresizable, True); j++;
4755 XtCreatePopupShell(name, topLevelShellWidgetClass,
4756 shellWidget, args, j);
4759 XtCreatePopupShell(name, transientShellWidgetClass,
4760 shellWidget, args, j);
4763 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4764 layoutArgs, XtNumber(layoutArgs));
4766 XtCreateManagedWidget("form", formWidgetClass, layout,
4767 formArgs, XtNumber(formArgs));
4771 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4772 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4774 XtSetArg(args[j], XtNstring, text); j++;
4775 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4776 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4777 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4778 XtSetArg(args[j], XtNright, XtChainRight); j++;
4779 XtSetArg(args[j], XtNresizable, True); j++;
4780 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4781 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4782 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4783 XtSetArg(args[j], XtNautoFill, True); j++;
4784 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4786 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4787 XtOverrideTranslations(edit, XtParseTranslationTable(commentTranslations));
4791 XtSetArg(args[j], XtNfromVert, edit); j++;
4792 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4793 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4794 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4795 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4797 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4798 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4801 XtSetArg(args[j], XtNfromVert, edit); j++;
4802 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4803 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4804 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4805 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4806 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4808 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4809 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4812 XtSetArg(args[j], XtNfromVert, edit); j++;
4813 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4814 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4815 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4816 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4817 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4819 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4820 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4823 XtSetArg(args[j], XtNfromVert, edit); 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(_("close"), commandWidgetClass, form, args, j);
4830 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4833 XtSetArg(args[j], XtNfromVert, edit); j++;
4834 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4835 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4836 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4837 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4838 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4840 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4841 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4844 XtRealizeWidget(shell);
4846 if (commentX == -1) {
4849 Dimension pw_height;
4850 Dimension ew_height;
4853 XtSetArg(args[j], XtNheight, &ew_height); j++;
4854 XtGetValues(edit, args, j);
4857 XtSetArg(args[j], XtNheight, &pw_height); j++;
4858 XtGetValues(shell, args, j);
4859 commentH = pw_height + (lines - 1) * ew_height;
4860 commentW = bw_width - 16;
4862 XSync(xDisplay, False);
4864 /* This code seems to tickle an X bug if it is executed too soon
4865 after xboard starts up. The coordinates get transformed as if
4866 the main window was positioned at (0, 0).
4868 XtTranslateCoords(shellWidget,
4869 (bw_width - commentW) / 2, 0 - commentH / 2,
4870 &commentX, &commentY);
4872 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4873 RootWindowOfScreen(XtScreen(shellWidget)),
4874 (bw_width - commentW) / 2, 0 - commentH / 2,
4879 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4882 if(wpComment.width > 0) {
4883 commentX = wpComment.x;
4884 commentY = wpComment.y;
4885 commentW = wpComment.width;
4886 commentH = wpComment.height;
4890 XtSetArg(args[j], XtNheight, commentH); j++;
4891 XtSetArg(args[j], XtNwidth, commentW); j++;
4892 XtSetArg(args[j], XtNx, commentX); j++;
4893 XtSetArg(args[j], XtNy, commentY); j++;
4894 XtSetValues(shell, args, j);
4895 XtSetKeyboardFocus(shell, edit);
4900 /* Used for analysis window and ICS input window */
4901 Widget MiscCreate(name, text, mutable, callback, lines)
4903 int /*Boolean*/ mutable;
4904 XtCallbackProc callback;
4908 Widget shell, layout, form, edit;
4910 Dimension bw_width, pw_height, ew_height, w, h;
4916 XtSetArg(args[j], XtNresizable, True); j++;
4919 XtCreatePopupShell(name, topLevelShellWidgetClass,
4920 shellWidget, args, j);
4923 XtCreatePopupShell(name, transientShellWidgetClass,
4924 shellWidget, args, j);
4927 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4928 layoutArgs, XtNumber(layoutArgs));
4930 XtCreateManagedWidget("form", formWidgetClass, layout,
4931 formArgs, XtNumber(formArgs));
4935 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4936 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4938 XtSetArg(args[j], XtNstring, text); j++;
4939 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4940 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4941 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4942 XtSetArg(args[j], XtNright, XtChainRight); j++;
4943 XtSetArg(args[j], XtNresizable, True); j++;
4944 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4945 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4946 XtSetArg(args[j], XtNautoFill, True); j++;
4947 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4949 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4951 XtRealizeWidget(shell);
4954 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4955 XtGetValues(boardWidget, args, j);
4958 XtSetArg(args[j], XtNheight, &ew_height); j++;
4959 XtGetValues(edit, args, j);
4962 XtSetArg(args[j], XtNheight, &pw_height); j++;
4963 XtGetValues(shell, args, j);
4964 h = pw_height + (lines - 1) * ew_height;
4967 XSync(xDisplay, False);
4969 /* This code seems to tickle an X bug if it is executed too soon
4970 after xboard starts up. The coordinates get transformed as if
4971 the main window was positioned at (0, 0).
4973 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4975 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4976 RootWindowOfScreen(XtScreen(shellWidget)),
4977 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4981 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4984 XtSetArg(args[j], XtNheight, h); j++;
4985 XtSetArg(args[j], XtNwidth, w); j++;
4986 XtSetArg(args[j], XtNx, x); j++;
4987 XtSetArg(args[j], XtNy, y); j++;
4988 XtSetValues(shell, args, j);
4994 static int savedIndex; /* gross that this is global */
4996 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
4999 XawTextPosition index, dummy;
5002 XawTextGetSelectionPos(w, &index, &dummy);
5003 XtSetArg(arg, XtNstring, &val);
5004 XtGetValues(w, &arg, 1);
5005 ReplaceComment(savedIndex, val);
5006 if(savedIndex != currentMove) ToNrEvent(savedIndex);
5007 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
5010 void EditCommentPopUp(index, title, text)
5019 if (text == NULL) text = "";
5021 if (editShell == NULL) {
5023 CommentCreate(title, text, True, EditCommentCallback, 4);
5024 XtRealizeWidget(editShell);
5025 CatchDeleteWindow(editShell, "EditCommentPopDown");
5027 edit = XtNameToWidget(editShell, "*form.text");
5029 XtSetArg(args[j], XtNstring, text); j++;
5030 XtSetValues(edit, args, j);
5032 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5033 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5034 XtSetValues(editShell, args, j);
5037 XtPopup(editShell, XtGrabNone);
5041 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5042 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"),
5044 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"),
5048 void EditCommentCallback(w, client_data, call_data)
5050 XtPointer client_data, call_data;
5058 XtSetArg(args[j], XtNlabel, &name); j++;
5059 XtGetValues(w, args, j);
5061 if (strcmp(name, _("ok")) == 0) {
5062 edit = XtNameToWidget(editShell, "*form.text");
5064 XtSetArg(args[j], XtNstring, &val); j++;
5065 XtGetValues(edit, args, j);
5066 ReplaceComment(savedIndex, val);
5067 EditCommentPopDown();
5068 } else if (strcmp(name, _("cancel")) == 0) {
5069 EditCommentPopDown();
5070 } else if (strcmp(name, _("clear")) == 0) {
5071 edit = XtNameToWidget(editShell, "*form.text");
5072 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5073 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5077 void EditCommentPopDown()
5082 if (!editUp) return;
5084 XtSetArg(args[j], XtNx, &commentX); j++;
5085 XtSetArg(args[j], XtNy, &commentY); j++;
5086 XtSetArg(args[j], XtNheight, &commentH); j++;
5087 XtSetArg(args[j], XtNwidth, &commentW); j++;
5088 XtGetValues(editShell, args, j);
5089 XtPopdown(editShell);
5092 XtSetArg(args[j], XtNleftBitmap, None); j++;
5093 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"),
5095 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"),
5099 void ICSInputBoxPopUp()
5104 char *title = _("ICS Input");
5107 if (ICSInputShell == NULL) {
5108 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
5109 tr = XtParseTranslationTable(ICSInputTranslations);
5110 edit = XtNameToWidget(ICSInputShell, "*form.text");
5111 XtOverrideTranslations(edit, tr);
5112 XtRealizeWidget(ICSInputShell);
5113 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
5116 edit = XtNameToWidget(ICSInputShell, "*form.text");
5118 XtSetArg(args[j], XtNstring, ""); j++;
5119 XtSetValues(edit, args, j);
5121 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5122 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5123 XtSetValues(ICSInputShell, args, j);
5126 XtPopup(ICSInputShell, XtGrabNone);
5127 XtSetKeyboardFocus(ICSInputShell, edit);
5129 ICSInputBoxUp = True;
5131 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5132 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.ICS Input Box"),
5136 void ICSInputSendText()
5143 edit = XtNameToWidget(ICSInputShell, "*form.text");
5145 XtSetArg(args[j], XtNstring, &val); j++;
5146 XtGetValues(edit, args, j);
5148 SendMultiLineToICS(val);
5149 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5150 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5153 void ICSInputBoxPopDown()
5158 if (!ICSInputBoxUp) return;
5160 XtPopdown(ICSInputShell);
5161 ICSInputBoxUp = False;
5163 XtSetArg(args[j], XtNleftBitmap, None); j++;
5164 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.ICS Input Box"),
5168 void CommentPopUp(title, text)
5175 savedIndex = currentMove; // [HGM] vari
5176 if (commentShell == NULL) {
5178 CommentCreate(title, text, False, CommentCallback, 4);
5179 XtRealizeWidget(commentShell);
5180 CatchDeleteWindow(commentShell, "CommentPopDown");
5182 edit = XtNameToWidget(commentShell, "*form.text");
5184 XtSetArg(args[j], XtNstring, text); j++;
5185 XtSetValues(edit, args, j);
5187 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5188 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5189 XtSetValues(commentShell, args, j);
5192 XtPopup(commentShell, XtGrabNone);
5193 XSync(xDisplay, False);
5198 void CommentCallback(w, client_data, call_data)
5200 XtPointer client_data, call_data;
5207 XtSetArg(args[j], XtNlabel, &name); j++;
5208 XtGetValues(w, args, j);
5210 if (strcmp(name, _("close")) == 0) {
5212 } else if (strcmp(name, _("edit")) == 0) {
5219 void CommentPopDown()
5224 if (!commentUp) return;
5226 XtSetArg(args[j], XtNx, &commentX); j++;
5227 XtSetArg(args[j], XtNy, &commentY); j++;
5228 XtSetArg(args[j], XtNwidth, &commentW); j++;
5229 XtSetArg(args[j], XtNheight, &commentH); j++;
5230 XtGetValues(commentShell, args, j);
5231 XtPopdown(commentShell);
5232 XSync(xDisplay, False);
5236 void FileNamePopUp(label, def, proc, openMode)
5242 fileProc = proc; /* I can't see a way not */
5243 fileOpenMode = openMode; /* to use globals here */
5244 { // [HGM] use file-selector dialog stolen from Ghostview
5246 int index; // this is not supported yet
5248 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5249 def, openMode, NULL, &name))
5250 (void) (*fileProc)(f, index=0, name);
5254 void FileNamePopDown()
5256 if (!filenameUp) return;
5257 XtPopdown(fileNameShell);
5258 XtDestroyWidget(fileNameShell);
5263 void FileNameCallback(w, client_data, call_data)
5265 XtPointer client_data, call_data;
5270 XtSetArg(args[0], XtNlabel, &name);
5271 XtGetValues(w, args, 1);
5273 if (strcmp(name, _("cancel")) == 0) {
5278 FileNameAction(w, NULL, NULL, NULL);
5281 void FileNameAction(w, event, prms, nprms)
5293 name = XawDialogGetValueString(w = XtParent(w));
5295 if ((name != NULL) && (*name != NULLCHAR)) {
5296 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
5297 XtPopdown(w = XtParent(XtParent(w)));
5301 p = strrchr(buf, ' ');
5308 fullname = ExpandPathName(buf);
5310 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5313 f = fopen(fullname, fileOpenMode);
5315 DisplayError(_("Failed to open file"), errno);
5317 (void) (*fileProc)(f, index, buf);
5324 XtPopdown(w = XtParent(XtParent(w)));
5330 void PromotionPopUp()
5333 Widget dialog, layout;
5335 Dimension bw_width, pw_width;
5339 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5340 XtGetValues(boardWidget, args, j);
5343 XtSetArg(args[j], XtNresizable, True); j++;
5344 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5346 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5347 shellWidget, args, j);
5349 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5350 layoutArgs, XtNumber(layoutArgs));
5353 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5354 XtSetArg(args[j], XtNborderWidth, 0); j++;
5355 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5358 if(gameInfo.variant != VariantShogi) {
5359 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5360 (XtPointer) dialog);
5361 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5362 (XtPointer) dialog);
5363 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5364 (XtPointer) dialog);
5365 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5366 (XtPointer) dialog);
5367 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5368 gameInfo.variant == VariantGiveaway) {
5369 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5370 (XtPointer) dialog);
5372 if(gameInfo.variant == VariantCapablanca ||
5373 gameInfo.variant == VariantGothic ||
5374 gameInfo.variant == VariantCapaRandom) {
5375 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5376 (XtPointer) dialog);
5377 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5378 (XtPointer) dialog);
5380 } else // [HGM] shogi
5382 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5383 (XtPointer) dialog);
5384 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5385 (XtPointer) dialog);
5387 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5388 (XtPointer) dialog);
5390 XtRealizeWidget(promotionShell);
5391 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5394 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5395 XtGetValues(promotionShell, args, j);
5397 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5398 lineGap + squareSize/3 +
5399 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5400 0 : 6*(squareSize + lineGap)), &x, &y);
5403 XtSetArg(args[j], XtNx, x); j++;
5404 XtSetArg(args[j], XtNy, y); j++;
5405 XtSetValues(promotionShell, args, j);
5407 XtPopup(promotionShell, XtGrabNone);
5412 void PromotionPopDown()
5414 if (!promotionUp) return;
5415 XtPopdown(promotionShell);
5416 XtDestroyWidget(promotionShell);
5417 promotionUp = False;
5420 void PromotionCallback(w, client_data, call_data)
5422 XtPointer client_data, call_data;
5428 XtSetArg(args[0], XtNlabel, &name);
5429 XtGetValues(w, args, 1);
5433 if (fromX == -1) return;
5435 if (strcmp(name, _("cancel")) == 0) {
5439 } else if (strcmp(name, _("Knight")) == 0) {
5441 } else if (strcmp(name, _("Promote")) == 0) {
5443 } else if (strcmp(name, _("Defer")) == 0) {
5446 promoChar = ToLower(name[0]);
5449 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5451 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5452 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5457 void ErrorCallback(w, client_data, call_data)
5459 XtPointer client_data, call_data;
5462 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5464 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5470 if (!errorUp) return;
5472 XtPopdown(errorShell);
5473 XtDestroyWidget(errorShell);
5474 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5477 void ErrorPopUp(title, label, modal)
5478 char *title, *label;
5482 Widget dialog, layout;
5486 Dimension bw_width, pw_width;
5487 Dimension pw_height;
5491 XtSetArg(args[i], XtNresizable, True); i++;
5492 XtSetArg(args[i], XtNtitle, title); i++;
5494 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5495 shellWidget, args, i);
5497 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5498 layoutArgs, XtNumber(layoutArgs));
5501 XtSetArg(args[i], XtNlabel, label); i++;
5502 XtSetArg(args[i], XtNborderWidth, 0); i++;
5503 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5506 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5508 XtRealizeWidget(errorShell);
5509 CatchDeleteWindow(errorShell, "ErrorPopDown");
5512 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5513 XtGetValues(boardWidget, args, i);
5515 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5516 XtSetArg(args[i], XtNheight, &pw_height); i++;
5517 XtGetValues(errorShell, args, i);
5520 /* This code seems to tickle an X bug if it is executed too soon
5521 after xboard starts up. The coordinates get transformed as if
5522 the main window was positioned at (0, 0).
5524 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5525 0 - pw_height + squareSize / 3, &x, &y);
5527 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5528 RootWindowOfScreen(XtScreen(boardWidget)),
5529 (bw_width - pw_width) / 2,
5530 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5534 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5537 XtSetArg(args[i], XtNx, x); i++;
5538 XtSetArg(args[i], XtNy, y); i++;
5539 XtSetValues(errorShell, args, i);
5542 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5545 /* Disable all user input other than deleting the window */
5546 static int frozen = 0;
5550 /* Grab by a widget that doesn't accept input */
5551 XtAddGrab(messageWidget, TRUE, FALSE);
5555 /* Undo a FreezeUI */
5558 if (!frozen) return;
5559 XtRemoveGrab(messageWidget);
5563 char *ModeToWidgetName(mode)
5567 case BeginningOfGame:
5568 if (appData.icsActive)
5569 return "menuMode.ICS Client";
5570 else if (appData.noChessProgram ||
5571 *appData.cmailGameName != NULLCHAR)
5572 return "menuMode.Edit Game";
5574 return "menuMode.Machine Black";
5575 case MachinePlaysBlack:
5576 return "menuMode.Machine Black";
5577 case MachinePlaysWhite:
5578 return "menuMode.Machine White";
5580 return "menuMode.Analysis Mode";
5582 return "menuMode.Analyze File";
5583 case TwoMachinesPlay:
5584 return "menuMode.Two Machines";
5586 return "menuMode.Edit Game";
5587 case PlayFromGameFile:
5588 return "menuFile.Load Game";
5590 return "menuMode.Edit Position";
5592 return "menuMode.Training";
5593 case IcsPlayingWhite:
5594 case IcsPlayingBlack:
5598 return "menuMode.ICS Client";
5605 void ModeHighlight()
5608 static int oldPausing = FALSE;
5609 static GameMode oldmode = (GameMode) -1;
5612 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5614 if (pausing != oldPausing) {
5615 oldPausing = pausing;
5617 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5619 XtSetArg(args[0], XtNleftBitmap, None);
5621 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5624 if (appData.showButtonBar) {
5625 /* Always toggle, don't set. Previous code messes up when
5626 invoked while the button is pressed, as releasing it
5627 toggles the state again. */
5630 XtSetArg(args[0], XtNbackground, &oldbg);
5631 XtSetArg(args[1], XtNforeground, &oldfg);
5632 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5634 XtSetArg(args[0], XtNbackground, oldfg);
5635 XtSetArg(args[1], XtNforeground, oldbg);
5637 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5641 wname = ModeToWidgetName(oldmode);
5642 if (wname != NULL) {
5643 XtSetArg(args[0], XtNleftBitmap, None);
5644 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5646 wname = ModeToWidgetName(gameMode);
5647 if (wname != NULL) {
5648 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5649 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5653 /* Maybe all the enables should be handled here, not just this one */
5654 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5655 gameMode == Training || gameMode == PlayFromGameFile);
5660 * Button/menu procedures
5662 void ResetProc(w, event, prms, nprms)
5671 int LoadGamePopUp(f, gameNumber, title)
5676 cmailMsgLoaded = FALSE;
5677 if (gameNumber == 0) {
5678 int error = GameListBuild(f);
5680 DisplayError(_("Cannot build game list"), error);
5681 } else if (!ListEmpty(&gameList) &&
5682 ((ListGame *) gameList.tailPred)->number > 1) {
5683 GameListPopUp(f, title);
5689 return LoadGame(f, gameNumber, title, FALSE);
5692 void LoadGameProc(w, event, prms, nprms)
5698 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5701 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5704 void LoadNextGameProc(w, event, prms, nprms)
5713 void LoadPrevGameProc(w, event, prms, nprms)
5722 void ReloadGameProc(w, event, prms, nprms)
5731 void LoadNextPositionProc(w, event, prms, nprms)
5740 void LoadPrevPositionProc(w, event, prms, nprms)
5749 void ReloadPositionProc(w, event, prms, nprms)
5758 void LoadPositionProc(w, event, prms, nprms)
5764 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5767 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5770 void SaveGameProc(w, event, prms, nprms)
5776 FileNamePopUp(_("Save game file name?"),
5777 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5781 void SavePositionProc(w, event, prms, nprms)
5787 FileNamePopUp(_("Save position file name?"),
5788 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5792 void ReloadCmailMsgProc(w, event, prms, nprms)
5798 ReloadCmailMsgEvent(FALSE);
5801 void MailMoveProc(w, event, prms, nprms)
5810 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5811 char *selected_fen_position=NULL;
5814 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5815 Atom *type_return, XtPointer *value_return,
5816 unsigned long *length_return, int *format_return)
5818 char *selection_tmp;
5820 if (!selected_fen_position) return False; /* should never happen */
5821 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5822 /* note: since no XtSelectionDoneProc was registered, Xt will
5823 * automatically call XtFree on the value returned. So have to
5824 * make a copy of it allocated with XtMalloc */
5825 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5826 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
5828 *value_return=selection_tmp;
5829 *length_return=strlen(selection_tmp);
5830 *type_return=*target;
5831 *format_return = 8; /* bits per byte */
5833 } else if (*target == XA_TARGETS(xDisplay)) {
5834 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5835 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5836 targets_tmp[1] = XA_STRING;
5837 *value_return = targets_tmp;
5838 *type_return = XA_ATOM;
5840 *format_return = 8 * sizeof(Atom);
5841 if (*format_return > 32) {
5842 *length_return *= *format_return / 32;
5843 *format_return = 32;
5851 /* note: when called from menu all parameters are NULL, so no clue what the
5852 * Widget which was clicked on was, or what the click event was
5854 void CopyPositionProc(w, event, prms, nprms)
5861 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5862 * have a notion of a position that is selected but not copied.
5863 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5865 if(gameMode == EditPosition) EditPositionDone(TRUE);
5866 if (selected_fen_position) free(selected_fen_position);
5867 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5868 if (!selected_fen_position) return;
5869 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5871 SendPositionSelection,
5872 NULL/* lose_ownership_proc */ ,
5873 NULL/* transfer_done_proc */);
5874 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5876 SendPositionSelection,
5877 NULL/* lose_ownership_proc */ ,
5878 NULL/* transfer_done_proc */);
5881 /* function called when the data to Paste is ready */
5883 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5884 Atom *type, XtPointer value, unsigned long *len, int *format)
5887 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5888 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5889 EditPositionPasteFEN(fenstr);
5893 /* called when Paste Position button is pressed,
5894 * all parameters will be NULL */
5895 void PastePositionProc(w, event, prms, nprms)
5901 XtGetSelectionValue(menuBarWidget,
5902 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5903 /* (XtSelectionCallbackProc) */ PastePositionCB,
5904 NULL, /* client_data passed to PastePositionCB */
5906 /* better to use the time field from the event that triggered the
5907 * call to this function, but that isn't trivial to get
5915 SendGameSelection(Widget w, Atom *selection, Atom *target,
5916 Atom *type_return, XtPointer *value_return,
5917 unsigned long *length_return, int *format_return)
5919 char *selection_tmp;
5921 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5922 FILE* f = fopen(gameCopyFilename, "r");
5925 if (f == NULL) return False;
5929 selection_tmp = XtMalloc(len + 1);
5930 count = fread(selection_tmp, 1, len, f);
5932 XtFree(selection_tmp);
5935 selection_tmp[len] = NULLCHAR;
5936 *value_return = selection_tmp;
5937 *length_return = len;
5938 *type_return = *target;
5939 *format_return = 8; /* bits per byte */
5941 } else if (*target == XA_TARGETS(xDisplay)) {
5942 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5943 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5944 targets_tmp[1] = XA_STRING;
5945 *value_return = targets_tmp;
5946 *type_return = XA_ATOM;
5948 *format_return = 8 * sizeof(Atom);
5949 if (*format_return > 32) {
5950 *length_return *= *format_return / 32;
5951 *format_return = 32;
5959 /* note: when called from menu all parameters are NULL, so no clue what the
5960 * Widget which was clicked on was, or what the click event was
5962 void CopyGameProc(w, event, prms, nprms)
5970 ret = SaveGameToFile(gameCopyFilename, FALSE);
5974 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5975 * have a notion of a game that is selected but not copied.
5976 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5978 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5981 NULL/* lose_ownership_proc */ ,
5982 NULL/* transfer_done_proc */);
5983 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5986 NULL/* lose_ownership_proc */ ,
5987 NULL/* transfer_done_proc */);
5990 /* function called when the data to Paste is ready */
5992 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5993 Atom *type, XtPointer value, unsigned long *len, int *format)
5996 if (value == NULL || *len == 0) {
5997 return; /* nothing had been selected to copy */
5999 f = fopen(gamePasteFilename, "w");
6001 DisplayError(_("Can't open temp file"), errno);
6004 fwrite(value, 1, *len, f);
6007 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
6010 /* called when Paste Game button is pressed,
6011 * all parameters will be NULL */
6012 void PasteGameProc(w, event, prms, nprms)
6018 XtGetSelectionValue(menuBarWidget,
6019 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
6020 /* (XtSelectionCallbackProc) */ PasteGameCB,
6021 NULL, /* client_data passed to PasteGameCB */
6023 /* better to use the time field from the event that triggered the
6024 * call to this function, but that isn't trivial to get
6034 SaveGameProc(NULL, NULL, NULL, NULL);
6038 void QuitProc(w, event, prms, nprms)
6047 void PauseProc(w, event, prms, nprms)
6057 void MachineBlackProc(w, event, prms, nprms)
6063 MachineBlackEvent();
6066 void MachineWhiteProc(w, event, prms, nprms)
6072 MachineWhiteEvent();
6075 void AnalyzeModeProc(w, event, prms, nprms)
6083 if (!first.analysisSupport) {
6084 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6085 DisplayError(buf, 0);
6088 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
6089 if (appData.icsActive) {
6090 if (gameMode != IcsObserving) {
6091 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
6092 DisplayError(buf, 0);
6094 if (appData.icsEngineAnalyze) {
6095 if (appData.debugMode)
6096 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
6102 /* if enable, use want disable icsEngineAnalyze */
6103 if (appData.icsEngineAnalyze) {
6108 appData.icsEngineAnalyze = TRUE;
6109 if (appData.debugMode)
6110 fprintf(debugFP, _("ICS engine analyze starting... \n"));
6112 if (!appData.showThinking)
6113 ShowThinkingProc(w,event,prms,nprms);
6118 void AnalyzeFileProc(w, event, prms, nprms)
6124 if (!first.analysisSupport) {
6126 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6127 DisplayError(buf, 0);
6132 if (!appData.showThinking)
6133 ShowThinkingProc(w,event,prms,nprms);
6136 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
6137 AnalysisPeriodicEvent(1);
6140 void TwoMachinesProc(w, event, prms, nprms)
6149 void IcsClientProc(w, event, prms, nprms)
6158 void EditGameProc(w, event, prms, nprms)
6167 void EditPositionProc(w, event, prms, nprms)
6173 EditPositionEvent();
6176 void TrainingProc(w, event, prms, nprms)
6185 void EditCommentProc(w, event, prms, nprms)
6192 EditCommentPopDown();
6198 void IcsInputBoxProc(w, event, prms, nprms)
6204 if (ICSInputBoxUp) {
6205 ICSInputBoxPopDown();
6211 void AcceptProc(w, event, prms, nprms)
6220 void DeclineProc(w, event, prms, nprms)
6229 void RematchProc(w, event, prms, nprms)
6238 void CallFlagProc(w, event, prms, nprms)
6247 void DrawProc(w, event, prms, nprms)
6256 void AbortProc(w, event, prms, nprms)
6265 void AdjournProc(w, event, prms, nprms)
6274 void ResignProc(w, event, prms, nprms)
6283 void AdjuWhiteProc(w, event, prms, nprms)
6289 UserAdjudicationEvent(+1);
6292 void AdjuBlackProc(w, event, prms, nprms)
6298 UserAdjudicationEvent(-1);
6301 void AdjuDrawProc(w, event, prms, nprms)
6307 UserAdjudicationEvent(0);
6310 void EnterKeyProc(w, event, prms, nprms)
6316 if (ICSInputBoxUp == True)
6320 void UpKeyProc(w, event, prms, nprms)
6325 { // [HGM] input: let up-arrow recall previous line from history
6332 if (!ICSInputBoxUp) return;
6333 edit = XtNameToWidget(ICSInputShell, "*form.text");
6335 XtSetArg(args[j], XtNstring, &val); j++;
6336 XtGetValues(edit, args, j);
6337 val = PrevInHistory(val);
6338 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6339 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6341 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6342 XawTextReplace(edit, 0, 0, &t);
6343 XawTextSetInsertionPoint(edit, 9999);
6347 void DownKeyProc(w, event, prms, nprms)
6352 { // [HGM] input: let down-arrow recall next line from history
6357 if (!ICSInputBoxUp) return;
6358 edit = XtNameToWidget(ICSInputShell, "*form.text");
6359 val = NextInHistory();
6360 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6361 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6363 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6364 XawTextReplace(edit, 0, 0, &t);
6365 XawTextSetInsertionPoint(edit, 9999);
6369 void StopObservingProc(w, event, prms, nprms)
6375 StopObservingEvent();
6378 void StopExaminingProc(w, event, prms, nprms)
6384 StopExaminingEvent();
6387 void UploadProc(w, event, prms, nprms)
6397 void ForwardProc(w, event, prms, nprms)
6407 void BackwardProc(w, event, prms, nprms)
6416 void ToStartProc(w, event, prms, nprms)
6425 void ToEndProc(w, event, prms, nprms)
6434 void RevertProc(w, event, prms, nprms)
6443 void AnnotateProc(w, event, prms, nprms)
6452 void TruncateGameProc(w, event, prms, nprms)
6458 TruncateGameEvent();
6460 void RetractMoveProc(w, event, prms, nprms)
6469 void MoveNowProc(w, event, prms, nprms)
6479 void AlwaysQueenProc(w, event, prms, nprms)
6487 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6489 if (appData.alwaysPromoteToQueen) {
6490 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6492 XtSetArg(args[0], XtNleftBitmap, None);
6494 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6498 void AnimateDraggingProc(w, event, prms, nprms)
6506 appData.animateDragging = !appData.animateDragging;
6508 if (appData.animateDragging) {
6509 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6512 XtSetArg(args[0], XtNleftBitmap, None);
6514 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6518 void AnimateMovingProc(w, event, prms, nprms)
6526 appData.animate = !appData.animate;
6528 if (appData.animate) {
6529 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6532 XtSetArg(args[0], XtNleftBitmap, None);
6534 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6538 void AutocommProc(w, event, prms, nprms)
6546 appData.autoComment = !appData.autoComment;
6548 if (appData.autoComment) {
6549 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6551 XtSetArg(args[0], XtNleftBitmap, None);
6553 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6558 void AutoflagProc(w, event, prms, nprms)
6566 appData.autoCallFlag = !appData.autoCallFlag;
6568 if (appData.autoCallFlag) {
6569 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6571 XtSetArg(args[0], XtNleftBitmap, None);
6573 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6577 void AutoflipProc(w, event, prms, nprms)
6585 appData.autoFlipView = !appData.autoFlipView;
6587 if (appData.autoFlipView) {
6588 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6590 XtSetArg(args[0], XtNleftBitmap, None);
6592 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6596 void AutobsProc(w, event, prms, nprms)
6604 appData.autoObserve = !appData.autoObserve;
6606 if (appData.autoObserve) {
6607 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6609 XtSetArg(args[0], XtNleftBitmap, None);
6611 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6615 void AutoraiseProc(w, event, prms, nprms)
6623 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6625 if (appData.autoRaiseBoard) {
6626 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6628 XtSetArg(args[0], XtNleftBitmap, None);
6630 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6634 void AutosaveProc(w, event, prms, nprms)
6642 appData.autoSaveGames = !appData.autoSaveGames;
6644 if (appData.autoSaveGames) {
6645 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6647 XtSetArg(args[0], XtNleftBitmap, None);
6649 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6653 void BlindfoldProc(w, event, prms, nprms)
6661 appData.blindfold = !appData.blindfold;
6663 if (appData.blindfold) {
6664 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6666 XtSetArg(args[0], XtNleftBitmap, None);
6668 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6671 DrawPosition(True, NULL);
6674 void TestLegalityProc(w, event, prms, nprms)
6682 appData.testLegality = !appData.testLegality;
6684 if (appData.testLegality) {
6685 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6687 XtSetArg(args[0], XtNleftBitmap, None);
6689 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6694 void FlashMovesProc(w, event, prms, nprms)
6702 if (appData.flashCount == 0) {
6703 appData.flashCount = 3;
6705 appData.flashCount = -appData.flashCount;
6708 if (appData.flashCount > 0) {
6709 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6711 XtSetArg(args[0], XtNleftBitmap, None);
6713 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6717 void FlipViewProc(w, event, prms, nprms)
6723 flipView = !flipView;
6724 DrawPosition(True, NULL);
6727 void GetMoveListProc(w, event, prms, nprms)
6735 appData.getMoveList = !appData.getMoveList;
6737 if (appData.getMoveList) {
6738 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6741 XtSetArg(args[0], XtNleftBitmap, None);
6743 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6748 void HighlightDraggingProc(w, event, prms, nprms)
6756 appData.highlightDragging = !appData.highlightDragging;
6758 if (appData.highlightDragging) {
6759 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6761 XtSetArg(args[0], XtNleftBitmap, None);
6763 XtSetValues(XtNameToWidget(menuBarWidget,
6764 "menuOptions.Highlight Dragging"), args, 1);
6768 void HighlightLastMoveProc(w, event, prms, nprms)
6776 appData.highlightLastMove = !appData.highlightLastMove;
6778 if (appData.highlightLastMove) {
6779 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6781 XtSetArg(args[0], XtNleftBitmap, None);
6783 XtSetValues(XtNameToWidget(menuBarWidget,
6784 "menuOptions.Highlight Last Move"), args, 1);
6787 void IcsAlarmProc(w, event, prms, nprms)
6795 appData.icsAlarm = !appData.icsAlarm;
6797 if (appData.icsAlarm) {
6798 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6800 XtSetArg(args[0], XtNleftBitmap, None);
6802 XtSetValues(XtNameToWidget(menuBarWidget,
6803 "menuOptions.ICS Alarm"), args, 1);
6806 void MoveSoundProc(w, event, prms, nprms)
6814 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6816 if (appData.ringBellAfterMoves) {
6817 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6819 XtSetArg(args[0], XtNleftBitmap, None);
6821 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6826 void OldSaveStyleProc(w, event, prms, nprms)
6834 appData.oldSaveStyle = !appData.oldSaveStyle;
6836 if (appData.oldSaveStyle) {
6837 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6839 XtSetArg(args[0], XtNleftBitmap, None);
6841 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6845 void PeriodicUpdatesProc(w, event, prms, nprms)
6853 PeriodicUpdatesEvent(!appData.periodicUpdates);
6855 if (appData.periodicUpdates) {
6856 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6858 XtSetArg(args[0], XtNleftBitmap, None);
6860 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6864 void PonderNextMoveProc(w, event, prms, nprms)
6872 PonderNextMoveEvent(!appData.ponderNextMove);
6874 if (appData.ponderNextMove) {
6875 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6877 XtSetArg(args[0], XtNleftBitmap, None);
6879 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6883 void PopupExitMessageProc(w, event, prms, nprms)
6891 appData.popupExitMessage = !appData.popupExitMessage;
6893 if (appData.popupExitMessage) {
6894 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6896 XtSetArg(args[0], XtNleftBitmap, None);
6898 XtSetValues(XtNameToWidget(menuBarWidget,
6899 "menuOptions.Popup Exit Message"), args, 1);
6902 void PopupMoveErrorsProc(w, event, prms, nprms)
6910 appData.popupMoveErrors = !appData.popupMoveErrors;
6912 if (appData.popupMoveErrors) {
6913 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6915 XtSetArg(args[0], XtNleftBitmap, None);
6917 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6921 void PremoveProc(w, event, prms, nprms)
6929 appData.premove = !appData.premove;
6931 if (appData.premove) {
6932 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6934 XtSetArg(args[0], XtNleftBitmap, None);
6936 XtSetValues(XtNameToWidget(menuBarWidget,
6937 "menuOptions.Premove"), args, 1);
6940 void QuietPlayProc(w, event, prms, nprms)
6948 appData.quietPlay = !appData.quietPlay;
6950 if (appData.quietPlay) {
6951 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6953 XtSetArg(args[0], XtNleftBitmap, None);
6955 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6959 void ShowCoordsProc(w, event, prms, nprms)
6967 appData.showCoords = !appData.showCoords;
6969 if (appData.showCoords) {
6970 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6972 XtSetArg(args[0], XtNleftBitmap, None);
6974 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6977 DrawPosition(True, NULL);
6980 void ShowThinkingProc(w, event, prms, nprms)
6986 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6987 ShowThinkingEvent();
6990 void HideThinkingProc(w, event, prms, nprms)
6998 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6999 ShowThinkingEvent();
7001 if (appData.hideThinkingFromHuman) {
7002 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
7004 XtSetArg(args[0], XtNleftBitmap, None);
7006 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
7010 void SaveOnExitProc(w, event, prms, nprms)
7018 saveSettingsOnExit = !saveSettingsOnExit;
7020 if (saveSettingsOnExit) {
7021 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
7023 XtSetArg(args[0], XtNleftBitmap, None);
7025 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
7029 void SaveSettingsProc(w, event, prms, nprms)
7035 SaveSettings(settingsFileName);
7038 void InfoProc(w, event, prms, nprms)
7045 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
7050 void ManProc(w, event, prms, nprms)
7058 if (nprms && *nprms > 0)
7062 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
7066 void HintProc(w, event, prms, nprms)
7075 void BookProc(w, event, prms, nprms)
7084 void AboutProc(w, event, prms, nprms)
7092 char *zippy = " (with Zippy code)";
7096 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
7097 programVersion, zippy,
7098 "Copyright 1991 Digital Equipment Corporation",
7099 "Enhancements Copyright 1992-2009 Free Software Foundation",
7100 "Enhancements Copyright 2005 Alessandro Scotti",
7101 PACKAGE, " is free software and carries NO WARRANTY;",
7102 "see the file COPYING for more information.");
7103 ErrorPopUp(_("About XBoard"), buf, FALSE);
7106 void DebugProc(w, event, prms, nprms)
7112 appData.debugMode = !appData.debugMode;
7115 void AboutGameProc(w, event, prms, nprms)
7124 void NothingProc(w, event, prms, nprms)
7133 void Iconify(w, event, prms, nprms)
7142 XtSetArg(args[0], XtNiconic, True);
7143 XtSetValues(shellWidget, args, 1);
7146 void DisplayMessage(message, extMessage)
7147 char *message, *extMessage;
7149 /* display a message in the message widget */
7158 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
7163 message = extMessage;
7167 /* need to test if messageWidget already exists, since this function
7168 can also be called during the startup, if for example a Xresource
7169 is not set up correctly */
7172 XtSetArg(arg, XtNlabel, message);
7173 XtSetValues(messageWidget, &arg, 1);
7179 void DisplayTitle(text)
7184 char title[MSG_SIZ];
7187 if (text == NULL) text = "";
7189 if (appData.titleInWindow) {
7191 XtSetArg(args[i], XtNlabel, text); i++;
7192 XtSetValues(titleWidget, args, i);
7195 if (*text != NULLCHAR) {
7196 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
7197 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
7198 } else if (appData.icsActive) {
7199 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7200 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7201 } else if (appData.cmailGameName[0] != NULLCHAR) {
7202 snprintf(icon, sizeof(icon), "%s", "CMail");
7203 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7205 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7206 } else if (gameInfo.variant == VariantGothic) {
7207 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7208 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
7211 } else if (gameInfo.variant == VariantFalcon) {
7212 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7213 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
7215 } else if (appData.noChessProgram) {
7216 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7217 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
7219 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
7220 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7223 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7224 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7225 XtSetValues(shellWidget, args, i);
7230 DisplayError(message, error)
7237 if (appData.debugMode || appData.matchMode) {
7238 fprintf(stderr, "%s: %s\n", programName, message);
7241 if (appData.debugMode || appData.matchMode) {
7242 fprintf(stderr, "%s: %s: %s\n",
7243 programName, message, strerror(error));
7245 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7248 ErrorPopUp(_("Error"), message, FALSE);
7252 void DisplayMoveError(message)
7257 DrawPosition(FALSE, NULL);
7258 if (appData.debugMode || appData.matchMode) {
7259 fprintf(stderr, "%s: %s\n", programName, message);
7261 if (appData.popupMoveErrors) {
7262 ErrorPopUp(_("Error"), message, FALSE);
7264 DisplayMessage(message, "");
7269 void DisplayFatalError(message, error, status)
7275 errorExitStatus = status;
7277 fprintf(stderr, "%s: %s\n", programName, message);
7279 fprintf(stderr, "%s: %s: %s\n",
7280 programName, message, strerror(error));
7281 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7284 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7285 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7291 void DisplayInformation(message)
7295 ErrorPopUp(_("Information"), message, TRUE);
7298 void DisplayNote(message)
7302 ErrorPopUp(_("Note"), message, FALSE);
7306 NullXErrorCheck(dpy, error_event)
7308 XErrorEvent *error_event;
7313 void DisplayIcsInteractionTitle(message)
7316 if (oldICSInteractionTitle == NULL) {
7317 /* Magic to find the old window title, adapted from vim */
7318 char *wina = getenv("WINDOWID");
7320 Window win = (Window) atoi(wina);
7321 Window root, parent, *children;
7322 unsigned int nchildren;
7323 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7325 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7326 if (!XQueryTree(xDisplay, win, &root, &parent,
7327 &children, &nchildren)) break;
7328 if (children) XFree((void *)children);
7329 if (parent == root || parent == 0) break;
7332 XSetErrorHandler(oldHandler);
7334 if (oldICSInteractionTitle == NULL) {
7335 oldICSInteractionTitle = "xterm";
7338 printf("\033]0;%s\007", message);
7342 char pendingReplyPrefix[MSG_SIZ];
7343 ProcRef pendingReplyPR;
7345 void AskQuestionProc(w, event, prms, nprms)
7352 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7356 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7359 void AskQuestionPopDown()
7361 if (!askQuestionUp) return;
7362 XtPopdown(askQuestionShell);
7363 XtDestroyWidget(askQuestionShell);
7364 askQuestionUp = False;
7367 void AskQuestionReplyAction(w, event, prms, nprms)
7377 reply = XawDialogGetValueString(w = XtParent(w));
7378 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
7379 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
7380 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
7381 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
7382 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7383 AskQuestionPopDown();
7385 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7388 void AskQuestionCallback(w, client_data, call_data)
7390 XtPointer client_data, call_data;
7395 XtSetArg(args[0], XtNlabel, &name);
7396 XtGetValues(w, args, 1);
7398 if (strcmp(name, _("cancel")) == 0) {
7399 AskQuestionPopDown();
7401 AskQuestionReplyAction(w, NULL, NULL, NULL);
7405 void AskQuestion(title, question, replyPrefix, pr)
7406 char *title, *question, *replyPrefix;
7410 Widget popup, layout, dialog, edit;
7416 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
7417 pendingReplyPR = pr;
7420 XtSetArg(args[i], XtNresizable, True); i++;
7421 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7422 askQuestionShell = popup =
7423 XtCreatePopupShell(title, transientShellWidgetClass,
7424 shellWidget, args, i);
7427 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7428 layoutArgs, XtNumber(layoutArgs));
7431 XtSetArg(args[i], XtNlabel, question); i++;
7432 XtSetArg(args[i], XtNvalue, ""); i++;
7433 XtSetArg(args[i], XtNborderWidth, 0); i++;
7434 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7437 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7438 (XtPointer) dialog);
7439 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7440 (XtPointer) dialog);
7442 XtRealizeWidget(popup);
7443 CatchDeleteWindow(popup, "AskQuestionPopDown");
7445 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7446 &x, &y, &win_x, &win_y, &mask);
7448 XtSetArg(args[0], XtNx, x - 10);
7449 XtSetArg(args[1], XtNy, y - 30);
7450 XtSetValues(popup, args, 2);
7452 XtPopup(popup, XtGrabExclusive);
7453 askQuestionUp = True;
7455 edit = XtNameToWidget(dialog, "*value");
7456 XtSetKeyboardFocus(popup, edit);
7464 if (*name == NULLCHAR) {
7466 } else if (strcmp(name, "$") == 0) {
7467 putc(BELLCHAR, stderr);
7470 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7478 PlaySound(appData.soundMove);
7484 PlaySound(appData.soundIcsWin);
7490 PlaySound(appData.soundIcsLoss);
7496 PlaySound(appData.soundIcsDraw);
7500 PlayIcsUnfinishedSound()
7502 PlaySound(appData.soundIcsUnfinished);
7508 PlaySound(appData.soundIcsAlarm);
7514 system("stty echo");
7520 system("stty -echo");
7524 Colorize(cc, continuation)
7529 int count, outCount, error;
7531 if (textColors[(int)cc].bg > 0) {
7532 if (textColors[(int)cc].fg > 0) {
7533 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7534 textColors[(int)cc].fg, textColors[(int)cc].bg);
7536 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7537 textColors[(int)cc].bg);
7540 if (textColors[(int)cc].fg > 0) {
7541 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7542 textColors[(int)cc].fg);
7544 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7547 count = strlen(buf);
7548 outCount = OutputToProcess(NoProc, buf, count, &error);
7549 if (outCount < count) {
7550 DisplayFatalError(_("Error writing to display"), error, 1);
7553 if (continuation) return;
7556 PlaySound(appData.soundShout);
7559 PlaySound(appData.soundSShout);
7562 PlaySound(appData.soundChannel1);
7565 PlaySound(appData.soundChannel);
7568 PlaySound(appData.soundKibitz);
7571 PlaySound(appData.soundTell);
7573 case ColorChallenge:
7574 PlaySound(appData.soundChallenge);
7577 PlaySound(appData.soundRequest);
7580 PlaySound(appData.soundSeek);
7591 return getpwuid(getuid())->pw_name;
7595 ExpandPathName(path)
7598 static char static_buf[4*MSG_SIZ];
7599 char *d, *s, buf[4*MSG_SIZ];
7605 while (*s && isspace(*s))
7614 if (*(s+1) == '/') {
7615 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7619 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7620 { char *p; if(p = strchr(buf, '/')) *p = 0; }
7621 pwd = getpwnam(buf);
7624 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7628 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7629 strcat(d, strchr(s+1, '/'));
7633 safeStrCpy(d, s, 4*MSG_SIZ );
7640 static char host_name[MSG_SIZ];
7642 #if HAVE_GETHOSTNAME
7643 gethostname(host_name, MSG_SIZ);
7645 #else /* not HAVE_GETHOSTNAME */
7646 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7647 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7649 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7651 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7652 #endif /* not HAVE_GETHOSTNAME */
7655 XtIntervalId delayedEventTimerXID = 0;
7656 DelayedEventCallback delayedEventCallback = 0;
7661 delayedEventTimerXID = 0;
7662 delayedEventCallback();
7666 ScheduleDelayedEvent(cb, millisec)
7667 DelayedEventCallback cb; long millisec;
7669 if(delayedEventTimerXID && delayedEventCallback == cb)
7670 // [HGM] alive: replace, rather than add or flush identical event
7671 XtRemoveTimeOut(delayedEventTimerXID);
7672 delayedEventCallback = cb;
7673 delayedEventTimerXID =
7674 XtAppAddTimeOut(appContext, millisec,
7675 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7678 DelayedEventCallback
7681 if (delayedEventTimerXID) {
7682 return delayedEventCallback;
7689 CancelDelayedEvent()
7691 if (delayedEventTimerXID) {
7692 XtRemoveTimeOut(delayedEventTimerXID);
7693 delayedEventTimerXID = 0;
7697 XtIntervalId loadGameTimerXID = 0;
7699 int LoadGameTimerRunning()
7701 return loadGameTimerXID != 0;
7704 int StopLoadGameTimer()
7706 if (loadGameTimerXID != 0) {
7707 XtRemoveTimeOut(loadGameTimerXID);
7708 loadGameTimerXID = 0;
7716 LoadGameTimerCallback(arg, id)
7720 loadGameTimerXID = 0;
7725 StartLoadGameTimer(millisec)
7729 XtAppAddTimeOut(appContext, millisec,
7730 (XtTimerCallbackProc) LoadGameTimerCallback,
7734 XtIntervalId analysisClockXID = 0;
7737 AnalysisClockCallback(arg, id)
7741 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7742 || appData.icsEngineAnalyze) { // [DM]
7743 AnalysisPeriodicEvent(0);
7744 StartAnalysisClock();
7749 StartAnalysisClock()
7752 XtAppAddTimeOut(appContext, 2000,
7753 (XtTimerCallbackProc) AnalysisClockCallback,
7757 XtIntervalId clockTimerXID = 0;
7759 int ClockTimerRunning()
7761 return clockTimerXID != 0;
7764 int StopClockTimer()
7766 if (clockTimerXID != 0) {
7767 XtRemoveTimeOut(clockTimerXID);
7776 ClockTimerCallback(arg, id)
7785 StartClockTimer(millisec)
7789 XtAppAddTimeOut(appContext, millisec,
7790 (XtTimerCallbackProc) ClockTimerCallback,
7795 DisplayTimerLabel(w, color, timer, highlight)
7804 /* check for low time warning */
7805 Pixel foregroundOrWarningColor = timerForegroundPixel;
7808 appData.lowTimeWarning &&
7809 (timer / 1000) < appData.icsAlarmTime)
7810 foregroundOrWarningColor = lowTimeWarningColor;
7812 if (appData.clockMode) {
7813 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7814 XtSetArg(args[0], XtNlabel, buf);
7816 snprintf(buf, MSG_SIZ, "%s ", color);
7817 XtSetArg(args[0], XtNlabel, buf);
7822 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7823 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7825 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7826 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7829 XtSetValues(w, args, 3);
7833 DisplayWhiteClock(timeRemaining, highlight)
7839 if(appData.noGUI) return;
7840 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7841 if (highlight && iconPixmap == bIconPixmap) {
7842 iconPixmap = wIconPixmap;
7843 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7844 XtSetValues(shellWidget, args, 1);
7849 DisplayBlackClock(timeRemaining, highlight)
7855 if(appData.noGUI) return;
7856 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7857 if (highlight && iconPixmap == wIconPixmap) {
7858 iconPixmap = bIconPixmap;
7859 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7860 XtSetValues(shellWidget, args, 1);
7878 int StartChildProcess(cmdLine, dir, pr)
7885 int to_prog[2], from_prog[2];
7889 if (appData.debugMode) {
7890 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7893 /* We do NOT feed the cmdLine to the shell; we just
7894 parse it into blank-separated arguments in the
7895 most simple-minded way possible.
7898 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7901 while(*p == ' ') p++;
7903 if(*p == '"' || *p == '\'')
7904 p = strchr(++argv[i-1], *p);
7905 else p = strchr(p, ' ');
7906 if (p == NULL) break;
7911 SetUpChildIO(to_prog, from_prog);
7913 if ((pid = fork()) == 0) {
7915 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7916 close(to_prog[1]); // first close the unused pipe ends
7917 close(from_prog[0]);
7918 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7919 dup2(from_prog[1], 1);
7920 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7921 close(from_prog[1]); // and closing again loses one of the pipes!
7922 if(fileno(stderr) >= 2) // better safe than sorry...
7923 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7925 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7930 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7932 execvp(argv[0], argv);
7934 /* If we get here, exec failed */
7939 /* Parent process */
7941 close(from_prog[1]);
7943 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7946 cp->fdFrom = from_prog[0];
7947 cp->fdTo = to_prog[1];
7952 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7953 static RETSIGTYPE AlarmCallBack(int n)
7959 DestroyChildProcess(pr, signalType)
7963 ChildProc *cp = (ChildProc *) pr;
7965 if (cp->kind != CPReal) return;
7967 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7968 signal(SIGALRM, AlarmCallBack);
7970 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7971 kill(cp->pid, SIGKILL); // kill it forcefully
7972 wait((int *) 0); // and wait again
7976 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7978 /* Process is exiting either because of the kill or because of
7979 a quit command sent by the backend; either way, wait for it to die.
7988 InterruptChildProcess(pr)
7991 ChildProc *cp = (ChildProc *) pr;
7993 if (cp->kind != CPReal) return;
7994 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7997 int OpenTelnet(host, port, pr)
8002 char cmdLine[MSG_SIZ];
8004 if (port[0] == NULLCHAR) {
8005 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
8007 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
8009 return StartChildProcess(cmdLine, "", pr);
8012 int OpenTCP(host, port, pr)
8018 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
8019 #else /* !OMIT_SOCKETS */
8021 struct sockaddr_in sa;
8023 unsigned short uport;
8026 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
8030 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
8031 sa.sin_family = AF_INET;
8032 sa.sin_addr.s_addr = INADDR_ANY;
8033 uport = (unsigned short) 0;
8034 sa.sin_port = htons(uport);
8035 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
8039 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
8040 if (!(hp = gethostbyname(host))) {
8042 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
8043 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
8044 hp->h_addrtype = AF_INET;
8046 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
8047 hp->h_addr_list[0] = (char *) malloc(4);
8048 hp->h_addr_list[0][0] = b0;
8049 hp->h_addr_list[0][1] = b1;
8050 hp->h_addr_list[0][2] = b2;
8051 hp->h_addr_list[0][3] = b3;
8056 sa.sin_family = hp->h_addrtype;
8057 uport = (unsigned short) atoi(port);
8058 sa.sin_port = htons(uport);
8059 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
8061 if (connect(s, (struct sockaddr *) &sa,
8062 sizeof(struct sockaddr_in)) < 0) {
8066 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8073 #endif /* !OMIT_SOCKETS */
8078 int OpenCommPort(name, pr)
8085 fd = open(name, 2, 0);
8086 if (fd < 0) return errno;
8088 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8098 int OpenLoopback(pr)
8104 SetUpChildIO(to, from);
8106 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8109 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
8116 int OpenRcmd(host, user, cmd, pr)
8117 char *host, *user, *cmd;
8120 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
8124 #define INPUT_SOURCE_BUF_SIZE 8192
8133 char buf[INPUT_SOURCE_BUF_SIZE];
8138 DoInputCallback(closure, source, xid)
8143 InputSource *is = (InputSource *) closure;
8148 if (is->lineByLine) {
8149 count = read(is->fd, is->unused,
8150 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
8152 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
8155 is->unused += count;
8157 while (p < is->unused) {
8158 q = memchr(p, '\n', is->unused - p);
8159 if (q == NULL) break;
8161 (is->func)(is, is->closure, p, q - p, 0);
8165 while (p < is->unused) {
8170 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8175 (is->func)(is, is->closure, is->buf, count, error);
8179 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8186 ChildProc *cp = (ChildProc *) pr;
8188 is = (InputSource *) calloc(1, sizeof(InputSource));
8189 is->lineByLine = lineByLine;
8193 is->fd = fileno(stdin);
8195 is->kind = cp->kind;
8196 is->fd = cp->fdFrom;
8199 is->unused = is->buf;
8202 is->xid = XtAppAddInput(appContext, is->fd,
8203 (XtPointer) (XtInputReadMask),
8204 (XtInputCallbackProc) DoInputCallback,
8206 is->closure = closure;
8207 return (InputSourceRef) is;
8211 RemoveInputSource(isr)
8214 InputSource *is = (InputSource *) isr;
8216 if (is->xid == 0) return;
8217 XtRemoveInput(is->xid);
8221 int OutputToProcess(pr, message, count, outError)
8227 static int line = 0;
8228 ChildProc *cp = (ChildProc *) pr;
8233 if (appData.noJoin || !appData.useInternalWrap)
8234 outCount = fwrite(message, 1, count, stdout);
8237 int width = get_term_width();
8238 int len = wrap(NULL, message, count, width, &line);
8239 char *msg = malloc(len);
8243 outCount = fwrite(message, 1, count, stdout);
8246 dbgchk = wrap(msg, message, count, width, &line);
8247 if (dbgchk != len && appData.debugMode)
8248 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8249 outCount = fwrite(msg, 1, dbgchk, stdout);
8255 outCount = write(cp->fdTo, message, count);
8265 /* Output message to process, with "ms" milliseconds of delay
8266 between each character. This is needed when sending the logon
8267 script to ICC, which for some reason doesn't like the
8268 instantaneous send. */
8269 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8276 ChildProc *cp = (ChildProc *) pr;
8281 r = write(cp->fdTo, message++, 1);
8294 /**** Animation code by Hugh Fisher, DCS, ANU.
8296 Known problem: if a window overlapping the board is
8297 moved away while a piece is being animated underneath,
8298 the newly exposed area won't be updated properly.
8299 I can live with this.
8301 Known problem: if you look carefully at the animation
8302 of pieces in mono mode, they are being drawn as solid
8303 shapes without interior detail while moving. Fixing
8304 this would be a major complication for minimal return.
8307 /* Masks for XPM pieces. Black and white pieces can have
8308 different shapes, but in the interest of retaining my
8309 sanity pieces must have the same outline on both light
8310 and dark squares, and all pieces must use the same
8311 background square colors/images. */
8313 static int xpmDone = 0;
8316 CreateAnimMasks (pieceDepth)
8323 unsigned long plane;
8326 /* Need a bitmap just to get a GC with right depth */
8327 buf = XCreatePixmap(xDisplay, xBoardWindow,
8329 values.foreground = 1;
8330 values.background = 0;
8331 /* Don't use XtGetGC, not read only */
8332 maskGC = XCreateGC(xDisplay, buf,
8333 GCForeground | GCBackground, &values);
8334 XFreePixmap(xDisplay, buf);
8336 buf = XCreatePixmap(xDisplay, xBoardWindow,
8337 squareSize, squareSize, pieceDepth);
8338 values.foreground = XBlackPixel(xDisplay, xScreen);
8339 values.background = XWhitePixel(xDisplay, xScreen);
8340 bufGC = XCreateGC(xDisplay, buf,
8341 GCForeground | GCBackground, &values);
8343 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8344 /* Begin with empty mask */
8345 if(!xpmDone) // [HGM] pieces: keep using existing
8346 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8347 squareSize, squareSize, 1);
8348 XSetFunction(xDisplay, maskGC, GXclear);
8349 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8350 0, 0, squareSize, squareSize);
8352 /* Take a copy of the piece */
8357 XSetFunction(xDisplay, bufGC, GXcopy);
8358 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8360 0, 0, squareSize, squareSize, 0, 0);
8362 /* XOR the background (light) over the piece */
8363 XSetFunction(xDisplay, bufGC, GXxor);
8365 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8366 0, 0, squareSize, squareSize, 0, 0);
8368 XSetForeground(xDisplay, bufGC, lightSquareColor);
8369 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8372 /* We now have an inverted piece image with the background
8373 erased. Construct mask by just selecting all the non-zero
8374 pixels - no need to reconstruct the original image. */
8375 XSetFunction(xDisplay, maskGC, GXor);
8377 /* Might be quicker to download an XImage and create bitmap
8378 data from it rather than this N copies per piece, but it
8379 only takes a fraction of a second and there is a much
8380 longer delay for loading the pieces. */
8381 for (n = 0; n < pieceDepth; n ++) {
8382 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8383 0, 0, squareSize, squareSize,
8389 XFreePixmap(xDisplay, buf);
8390 XFreeGC(xDisplay, bufGC);
8391 XFreeGC(xDisplay, maskGC);
8395 InitAnimState (anim, info)
8397 XWindowAttributes * info;
8402 /* Each buffer is square size, same depth as window */
8403 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8404 squareSize, squareSize, info->depth);
8405 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8406 squareSize, squareSize, info->depth);
8408 /* Create a plain GC for blitting */
8409 mask = GCForeground | GCBackground | GCFunction |
8410 GCPlaneMask | GCGraphicsExposures;
8411 values.foreground = XBlackPixel(xDisplay, xScreen);
8412 values.background = XWhitePixel(xDisplay, xScreen);
8413 values.function = GXcopy;
8414 values.plane_mask = AllPlanes;
8415 values.graphics_exposures = False;
8416 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8418 /* Piece will be copied from an existing context at
8419 the start of each new animation/drag. */
8420 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8422 /* Outline will be a read-only copy of an existing */
8423 anim->outlineGC = None;
8429 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8430 XWindowAttributes info;
8432 if (xpmDone && gameInfo.variant == old) return;
8433 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8434 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8436 InitAnimState(&game, &info);
8437 InitAnimState(&player, &info);
8439 /* For XPM pieces, we need bitmaps to use as masks. */
8441 CreateAnimMasks(info.depth);
8447 static Boolean frameWaiting;
8449 static RETSIGTYPE FrameAlarm (sig)
8452 frameWaiting = False;
8453 /* In case System-V style signals. Needed?? */
8454 signal(SIGALRM, FrameAlarm);
8461 struct itimerval delay;
8463 XSync(xDisplay, False);
8466 frameWaiting = True;
8467 signal(SIGALRM, FrameAlarm);
8468 delay.it_interval.tv_sec =
8469 delay.it_value.tv_sec = time / 1000;
8470 delay.it_interval.tv_usec =
8471 delay.it_value.tv_usec = (time % 1000) * 1000;
8472 setitimer(ITIMER_REAL, &delay, NULL);
8473 while (frameWaiting) pause();
8474 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8475 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8476 setitimer(ITIMER_REAL, &delay, NULL);
8486 XSync(xDisplay, False);
8488 usleep(time * 1000);
8493 /* Convert board position to corner of screen rect and color */
8496 ScreenSquare(column, row, pt, color)
8497 int column; int row; XPoint * pt; int * color;
8500 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8501 pt->y = lineGap + row * (squareSize + lineGap);
8503 pt->x = lineGap + column * (squareSize + lineGap);
8504 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8506 *color = SquareColor(row, column);
8509 /* Convert window coords to square */
8512 BoardSquare(x, y, column, row)
8513 int x; int y; int * column; int * row;
8515 *column = EventToSquare(x, BOARD_WIDTH);
8516 if (flipView && *column >= 0)
8517 *column = BOARD_WIDTH - 1 - *column;
8518 *row = EventToSquare(y, BOARD_HEIGHT);
8519 if (!flipView && *row >= 0)
8520 *row = BOARD_HEIGHT - 1 - *row;
8525 #undef Max /* just in case */
8527 #define Max(a, b) ((a) > (b) ? (a) : (b))
8528 #define Min(a, b) ((a) < (b) ? (a) : (b))
8531 SetRect(rect, x, y, width, height)
8532 XRectangle * rect; int x; int y; int width; int height;
8536 rect->width = width;
8537 rect->height = height;
8540 /* Test if two frames overlap. If they do, return
8541 intersection rect within old and location of
8542 that rect within new. */
8545 Intersect(old, new, size, area, pt)
8546 XPoint * old; XPoint * new;
8547 int size; XRectangle * area; XPoint * pt;
8549 if (old->x > new->x + size || new->x > old->x + size ||
8550 old->y > new->y + size || new->y > old->y + size) {
8553 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8554 size - abs(old->x - new->x), size - abs(old->y - new->y));
8555 pt->x = Max(old->x - new->x, 0);
8556 pt->y = Max(old->y - new->y, 0);
8561 /* For two overlapping frames, return the rect(s)
8562 in the old that do not intersect with the new. */
8565 CalcUpdateRects(old, new, size, update, nUpdates)
8566 XPoint * old; XPoint * new; int size;
8567 XRectangle update[]; int * nUpdates;
8571 /* If old = new (shouldn't happen) then nothing to draw */
8572 if (old->x == new->x && old->y == new->y) {
8576 /* Work out what bits overlap. Since we know the rects
8577 are the same size we don't need a full intersect calc. */
8579 /* Top or bottom edge? */
8580 if (new->y > old->y) {
8581 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8583 } else if (old->y > new->y) {
8584 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8585 size, old->y - new->y);
8588 /* Left or right edge - don't overlap any update calculated above. */
8589 if (new->x > old->x) {
8590 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8591 new->x - old->x, size - abs(new->y - old->y));
8593 } else if (old->x > new->x) {
8594 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8595 old->x - new->x, size - abs(new->y - old->y));
8602 /* Generate a series of frame coords from start->mid->finish.
8603 The movement rate doubles until the half way point is
8604 reached, then halves back down to the final destination,
8605 which gives a nice slow in/out effect. The algorithmn
8606 may seem to generate too many intermediates for short
8607 moves, but remember that the purpose is to attract the
8608 viewers attention to the piece about to be moved and
8609 then to where it ends up. Too few frames would be less
8613 Tween(start, mid, finish, factor, frames, nFrames)
8614 XPoint * start; XPoint * mid;
8615 XPoint * finish; int factor;
8616 XPoint frames[]; int * nFrames;
8618 int fraction, n, count;
8622 /* Slow in, stepping 1/16th, then 1/8th, ... */
8624 for (n = 0; n < factor; n++)
8626 for (n = 0; n < factor; n++) {
8627 frames[count].x = start->x + (mid->x - start->x) / fraction;
8628 frames[count].y = start->y + (mid->y - start->y) / fraction;
8630 fraction = fraction / 2;
8634 frames[count] = *mid;
8637 /* Slow out, stepping 1/2, then 1/4, ... */
8639 for (n = 0; n < factor; n++) {
8640 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8641 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8643 fraction = fraction * 2;
8648 /* Draw a piece on the screen without disturbing what's there */
8651 SelectGCMask(piece, clip, outline, mask)
8652 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8656 /* Bitmap for piece being moved. */
8657 if (appData.monoMode) {
8658 *mask = *pieceToSolid(piece);
8659 } else if (useImages) {
8661 *mask = xpmMask[piece];
8663 *mask = ximMaskPm[piece];
8666 *mask = *pieceToSolid(piece);
8669 /* GC for piece being moved. Square color doesn't matter, but
8670 since it gets modified we make a copy of the original. */
8672 if (appData.monoMode)
8677 if (appData.monoMode)
8682 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8684 /* Outline only used in mono mode and is not modified */
8686 *outline = bwPieceGC;
8688 *outline = wbPieceGC;
8692 OverlayPiece(piece, clip, outline, dest)
8693 ChessSquare piece; GC clip; GC outline; Drawable dest;
8698 /* Draw solid rectangle which will be clipped to shape of piece */
8699 XFillRectangle(xDisplay, dest, clip,
8700 0, 0, squareSize, squareSize);
8701 if (appData.monoMode)
8702 /* Also draw outline in contrasting color for black
8703 on black / white on white cases */
8704 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8705 0, 0, squareSize, squareSize, 0, 0, 1);
8707 /* Copy the piece */
8712 if(appData.upsideDown && flipView) kind ^= 2;
8713 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8715 0, 0, squareSize, squareSize,
8720 /* Animate the movement of a single piece */
8723 BeginAnimation(anim, piece, startColor, start)
8731 /* The old buffer is initialised with the start square (empty) */
8732 BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0);
8733 anim->prevFrame = *start;
8735 /* The piece will be drawn using its own bitmap as a matte */
8736 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8737 XSetClipMask(xDisplay, anim->pieceGC, mask);
8741 AnimationFrame(anim, frame, piece)
8746 XRectangle updates[4];
8751 /* Save what we are about to draw into the new buffer */
8752 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8753 frame->x, frame->y, squareSize, squareSize,
8756 /* Erase bits of the previous frame */
8757 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8758 /* Where the new frame overlapped the previous,
8759 the contents in newBuf are wrong. */
8760 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8761 overlap.x, overlap.y,
8762 overlap.width, overlap.height,
8764 /* Repaint the areas in the old that don't overlap new */
8765 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8766 for (i = 0; i < count; i++)
8767 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8768 updates[i].x - anim->prevFrame.x,
8769 updates[i].y - anim->prevFrame.y,
8770 updates[i].width, updates[i].height,
8771 updates[i].x, updates[i].y);
8773 /* Easy when no overlap */
8774 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8775 0, 0, squareSize, squareSize,
8776 anim->prevFrame.x, anim->prevFrame.y);
8779 /* Save this frame for next time round */
8780 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8781 0, 0, squareSize, squareSize,
8783 anim->prevFrame = *frame;
8785 /* Draw piece over original screen contents, not current,
8786 and copy entire rect. Wipes out overlapping piece images. */
8787 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8788 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8789 0, 0, squareSize, squareSize,
8790 frame->x, frame->y);
8794 EndAnimation (anim, finish)
8798 XRectangle updates[4];
8803 /* The main code will redraw the final square, so we
8804 only need to erase the bits that don't overlap. */
8805 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8806 CalcUpdateRects(&anim->prevFrame, finish, 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 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8815 0, 0, squareSize, squareSize,
8816 anim->prevFrame.x, anim->prevFrame.y);
8821 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8823 ChessSquare piece; int startColor;
8824 XPoint * start; XPoint * finish;
8825 XPoint frames[]; int nFrames;
8829 BeginAnimation(anim, piece, startColor, start);
8830 for (n = 0; n < nFrames; n++) {
8831 AnimationFrame(anim, &(frames[n]), piece);
8832 FrameDelay(appData.animSpeed);
8834 EndAnimation(anim, finish);
8838 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
8841 ChessSquare piece = board[fromY][toY];
8842 board[fromY][toY] = EmptySquare;
8843 DrawPosition(FALSE, board);
8845 x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap);
8846 y = lineGap + toY * (squareSize + lineGap);
8848 x = lineGap + toX * (squareSize + lineGap);
8849 y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap);
8851 for(i=1; i<4*kFactor; i++) {
8852 int r = squareSize * 9 * i/(20*kFactor - 5);
8853 XFillArc(xDisplay, xBoardWindow, highlineGC,
8854 x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360);
8855 FrameDelay(appData.animSpeed);
8857 board[fromY][toY] = piece;
8860 /* Main control logic for deciding what to animate and how */
8863 AnimateMove(board, fromX, fromY, toX, toY)
8872 XPoint start, finish, mid;
8873 XPoint frames[kFactor * 2 + 1];
8874 int nFrames, startColor, endColor;
8876 /* Are we animating? */
8877 if (!appData.animate || appData.blindfold)
8880 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8881 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8882 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8884 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8885 piece = board[fromY][fromX];
8886 if (piece >= EmptySquare) return;
8891 hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1;
8894 if (appData.debugMode) {
8895 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8896 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8897 piece, fromX, fromY, toX, toY); }
8899 ScreenSquare(fromX, fromY, &start, &startColor);
8900 ScreenSquare(toX, toY, &finish, &endColor);
8903 /* Knight: make straight movement then diagonal */
8904 if (abs(toY - fromY) < abs(toX - fromX)) {
8905 mid.x = start.x + (finish.x - start.x) / 2;
8909 mid.y = start.y + (finish.y - start.y) / 2;
8912 mid.x = start.x + (finish.x - start.x) / 2;
8913 mid.y = start.y + (finish.y - start.y) / 2;
8916 /* Don't use as many frames for very short moves */
8917 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8918 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8920 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8921 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8922 if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
8924 for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
8925 if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
8928 /* Be sure end square is redrawn */
8929 damage[0][toY][toX] = True;
8933 DragPieceBegin(x, y)
8936 int boardX, boardY, color;
8939 /* Are we animating? */
8940 if (!appData.animateDragging || appData.blindfold)
8943 /* Figure out which square we start in and the
8944 mouse position relative to top left corner. */
8945 BoardSquare(x, y, &boardX, &boardY);
8946 player.startBoardX = boardX;
8947 player.startBoardY = boardY;
8948 ScreenSquare(boardX, boardY, &corner, &color);
8949 player.startSquare = corner;
8950 player.startColor = color;
8951 /* As soon as we start dragging, the piece will jump slightly to
8952 be centered over the mouse pointer. */
8953 player.mouseDelta.x = squareSize/2;
8954 player.mouseDelta.y = squareSize/2;
8955 /* Initialise animation */
8956 player.dragPiece = PieceForSquare(boardX, boardY);
8958 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8959 player.dragActive = True;
8960 BeginAnimation(&player, player.dragPiece, color, &corner);
8961 /* Mark this square as needing to be redrawn. Note that
8962 we don't remove the piece though, since logically (ie
8963 as seen by opponent) the move hasn't been made yet. */
8964 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8965 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8966 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8967 corner.x, corner.y, squareSize, squareSize,
8968 0, 0); // [HGM] zh: unstack in stead of grab
8969 if(gatingPiece != EmptySquare) {
8970 /* Kludge alert: When gating we want the introduced
8971 piece to appear on the from square. To generate an
8972 image of it, we draw it on the board, copy the image,
8973 and draw the original piece again. */
8974 ChessSquare piece = boards[currentMove][boardY][boardX];
8975 DrawSquare(boardY, boardX, gatingPiece, 0);
8976 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8977 corner.x, corner.y, squareSize, squareSize, 0, 0);
8978 DrawSquare(boardY, boardX, piece, 0);
8980 damage[0][boardY][boardX] = True;
8982 player.dragActive = False;
8992 /* Are we animating? */
8993 if (!appData.animateDragging || appData.blindfold)
8997 if (! player.dragActive)
8999 /* Move piece, maintaining same relative position
9000 of mouse within square */
9001 corner.x = x - player.mouseDelta.x;
9002 corner.y = y - player.mouseDelta.y;
9003 AnimationFrame(&player, &corner, player.dragPiece);
9005 if (appData.highlightDragging) {
9007 BoardSquare(x, y, &boardX, &boardY);
9008 SetHighlights(fromX, fromY, boardX, boardY);
9017 int boardX, boardY, color;
9020 /* Are we animating? */
9021 if (!appData.animateDragging || appData.blindfold)
9025 if (! player.dragActive)
9027 /* Last frame in sequence is square piece is
9028 placed on, which may not match mouse exactly. */
9029 BoardSquare(x, y, &boardX, &boardY);
9030 ScreenSquare(boardX, boardY, &corner, &color);
9031 EndAnimation(&player, &corner);
9033 /* Be sure end square is redrawn */
9034 damage[0][boardY][boardX] = True;
9036 /* This prevents weird things happening with fast successive
9037 clicks which on my Sun at least can cause motion events
9038 without corresponding press/release. */
9039 player.dragActive = False;
9042 /* Handle expose event while piece being dragged */
9047 if (!player.dragActive || appData.blindfold)
9050 /* What we're doing: logically, the move hasn't been made yet,
9051 so the piece is still in it's original square. But visually
9052 it's being dragged around the board. So we erase the square
9053 that the piece is on and draw it at the last known drag point. */
9054 BlankSquare(player.startSquare.x, player.startSquare.y,
9055 player.startColor, EmptySquare, xBoardWindow, 1);
9056 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
9057 damage[0][player.startBoardY][player.startBoardX] = TRUE;
9060 #include <sys/ioctl.h>
9061 int get_term_width()
9063 int fd, default_width;
9066 default_width = 79; // this is FICS default anyway...
9068 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
9070 if (!ioctl(fd, TIOCGSIZE, &win))
9071 default_width = win.ts_cols;
9072 #elif defined(TIOCGWINSZ)
9074 if (!ioctl(fd, TIOCGWINSZ, &win))
9075 default_width = win.ws_col;
9077 return default_width;
9083 static int old_width = 0;
9084 int new_width = get_term_width();
9086 if (old_width != new_width)
9087 ics_printf("set width %d\n", new_width);
9088 old_width = new_width;
9091 void NotifyFrontendLogin()