2 * xboard.c -- X front end for XBoard
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
8 * 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
10 * The following terms apply to Digital Equipment Corporation's copyright
12 * ------------------------------------------------------------------------
15 * Permission to use, copy, modify, and distribute this software and its
16 * documentation for any purpose and without fee is hereby granted,
17 * provided that the above copyright notice appear in all copies and that
18 * both that copyright notice and this permission notice appear in
19 * supporting documentation, and that the name of Digital not be
20 * used in advertising or publicity pertaining to distribution of the
21 * software without specific, written prior permission.
23 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
30 * ------------------------------------------------------------------------
32 * The following terms apply to the enhanced version of XBoard
33 * distributed by the Free Software Foundation:
34 * ------------------------------------------------------------------------
36 * GNU XBoard is free software: you can redistribute it and/or modify
37 * it under the terms of the GNU General Public License as published by
38 * the Free Software Foundation, either version 3 of the License, or (at
39 * your option) any later version.
41 * GNU XBoard is distributed in the hope that it will be useful, but
42 * WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44 * General Public License for more details.
46 * You should have received a copy of the GNU General Public License
47 * along with this program. If not, see http://www.gnu.org/licenses/. *
49 *------------------------------------------------------------------------
50 ** See the file ChangeLog for a revision history. */
60 #include <sys/types.h>
66 # if HAVE_SYS_SOCKET_H
67 # include <sys/socket.h>
68 # include <netinet/in.h>
70 # else /* not HAVE_SYS_SOCKET_H */
71 # if HAVE_LAN_SOCKET_H
72 # include <lan/socket.h>
74 # include <lan/netdb.h>
75 # else /* not HAVE_LAN_SOCKET_H */
76 # define OMIT_SOCKETS 1
77 # endif /* not HAVE_LAN_SOCKET_H */
78 # endif /* not HAVE_SYS_SOCKET_H */
79 #endif /* !OMIT_SOCKETS */
84 #else /* not STDC_HEADERS */
85 extern char *getenv();
88 # else /* not HAVE_STRING_H */
90 # endif /* not HAVE_STRING_H */
91 #endif /* not STDC_HEADERS */
94 # include <sys/fcntl.h>
95 #else /* not HAVE_SYS_FCNTL_H */
98 # endif /* HAVE_FCNTL_H */
99 #endif /* not HAVE_SYS_FCNTL_H */
101 #if HAVE_SYS_SYSTEMINFO_H
102 # include <sys/systeminfo.h>
103 #endif /* HAVE_SYS_SYSTEMINFO_H */
105 #if TIME_WITH_SYS_TIME
106 # include <sys/time.h>
110 # include <sys/time.h>
121 # include <sys/wait.h>
126 # define NAMLEN(dirent) strlen((dirent)->d_name)
127 # define HAVE_DIR_STRUCT
129 # define dirent direct
130 # define NAMLEN(dirent) (dirent)->d_namlen
132 # include <sys/ndir.h>
133 # define HAVE_DIR_STRUCT
136 # include <sys/dir.h>
137 # define HAVE_DIR_STRUCT
141 # define HAVE_DIR_STRUCT
145 #include <X11/Intrinsic.h>
146 #include <X11/StringDefs.h>
147 #include <X11/Shell.h>
148 #include <X11/cursorfont.h>
149 #include <X11/Xatom.h>
150 #include <X11/Xmu/Atoms.h>
152 #include <X11/Xaw3d/Dialog.h>
153 #include <X11/Xaw3d/Form.h>
154 #include <X11/Xaw3d/List.h>
155 #include <X11/Xaw3d/Label.h>
156 #include <X11/Xaw3d/SimpleMenu.h>
157 #include <X11/Xaw3d/SmeBSB.h>
158 #include <X11/Xaw3d/SmeLine.h>
159 #include <X11/Xaw3d/Box.h>
160 #include <X11/Xaw3d/MenuButton.h>
161 #include <X11/Xaw3d/Text.h>
162 #include <X11/Xaw3d/AsciiText.h>
164 #include <X11/Xaw/Dialog.h>
165 #include <X11/Xaw/Form.h>
166 #include <X11/Xaw/List.h>
167 #include <X11/Xaw/Label.h>
168 #include <X11/Xaw/SimpleMenu.h>
169 #include <X11/Xaw/SmeBSB.h>
170 #include <X11/Xaw/SmeLine.h>
171 #include <X11/Xaw/Box.h>
172 #include <X11/Xaw/MenuButton.h>
173 #include <X11/Xaw/Text.h>
174 #include <X11/Xaw/AsciiText.h>
177 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
182 #include "pixmaps/pixmaps.h"
183 #define IMAGE_EXT "xpm"
185 #define IMAGE_EXT "xim"
186 #include "bitmaps/bitmaps.h"
189 #include "bitmaps/icon_white.bm"
190 #include "bitmaps/icon_black.bm"
191 #include "bitmaps/checkmark.bm"
193 #include "frontend.h"
195 #include "backendz.h"
199 #include "xgamelist.h"
200 #include "xhistory.h"
201 #include "xedittags.h"
204 // must be moved to xengineoutput.h
206 void EngineOutputProc P((Widget w, XEvent *event,
207 String *prms, Cardinal *nprms));
208 void EvalGraphProc P((Widget w, XEvent *event,
209 String *prms, Cardinal *nprms));
216 #define usleep(t) _sleep2(((t)+500)/1000)
220 # define _(s) gettext (s)
221 # define N_(s) gettext_noop (s)
239 int main P((int argc, char **argv));
240 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
241 char *init_path, char *mode, int (*show_entry)(), char **name_return));
242 RETSIGTYPE CmailSigHandler P((int sig));
243 RETSIGTYPE IntSigHandler P((int sig));
244 RETSIGTYPE TermSizeSigHandler P((int sig));
245 void CreateGCs P((int redo));
246 void CreateXIMPieces P((void));
247 void CreateXPMPieces P((void));
248 void CreateXPMBoard P((char *s, int n));
249 void CreatePieces P((void));
250 void CreatePieceMenus P((void));
251 Widget CreateMenuBar P((Menu *mb));
252 Widget CreateButtonBar P ((MenuItem *mi));
253 char *FindFont P((char *pattern, int targetPxlSize));
254 void PieceMenuPopup P((Widget w, XEvent *event,
255 String *params, Cardinal *num_params));
256 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
257 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
258 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
259 u_int wreq, u_int hreq));
260 void CreateGrid P((void));
261 int EventToSquare P((int x, int limit));
262 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
263 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
264 void HandleUserMove P((Widget w, XEvent *event,
265 String *prms, Cardinal *nprms));
266 void AnimateUserMove P((Widget w, XEvent * event,
267 String * params, Cardinal * nParams));
268 void HandlePV P((Widget w, XEvent * event,
269 String * params, Cardinal * nParams));
270 void SelectPV P((Widget w, XEvent * event,
271 String * params, Cardinal * nParams));
272 void StopPV P((Widget w, XEvent * event,
273 String * params, Cardinal * nParams));
274 void WhiteClock P((Widget w, XEvent *event,
275 String *prms, Cardinal *nprms));
276 void BlackClock P((Widget w, XEvent *event,
277 String *prms, Cardinal *nprms));
278 void DrawPositionProc P((Widget w, XEvent *event,
279 String *prms, Cardinal *nprms));
280 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
282 void CommentClick P((Widget w, XEvent * event,
283 String * params, Cardinal * nParams));
284 void CommentPopUp P((char *title, char *label));
285 void CommentPopDown P((void));
286 void CommentCallback P((Widget w, XtPointer client_data,
287 XtPointer call_data));
288 void ICSInputBoxPopUp P((void));
289 void ICSInputBoxPopDown P((void));
290 void FileNamePopUp P((char *label, char *def,
291 FileProc proc, char *openMode));
292 void FileNamePopDown P((void));
293 void FileNameCallback P((Widget w, XtPointer client_data,
294 XtPointer call_data));
295 void FileNameAction P((Widget w, XEvent *event,
296 String *prms, Cardinal *nprms));
297 void AskQuestionReplyAction P((Widget w, XEvent *event,
298 String *prms, Cardinal *nprms));
299 void AskQuestionProc P((Widget w, XEvent *event,
300 String *prms, Cardinal *nprms));
301 void AskQuestionPopDown P((void));
302 void PromotionPopDown P((void));
303 void PromotionCallback P((Widget w, XtPointer client_data,
304 XtPointer call_data));
305 void EditCommentPopDown P((void));
306 void EditCommentCallback P((Widget w, XtPointer client_data,
307 XtPointer call_data));
308 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
309 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
310 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
311 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
313 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
315 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
317 void LoadPositionProc P((Widget w, XEvent *event,
318 String *prms, Cardinal *nprms));
319 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
321 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
323 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
325 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
327 void PastePositionProc P((Widget w, XEvent *event, String *prms,
329 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
330 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
331 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
332 void SavePositionProc P((Widget w, XEvent *event,
333 String *prms, Cardinal *nprms));
334 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
335 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
337 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
338 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
339 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
341 void MachineWhiteProc P((Widget w, XEvent *event,
342 String *prms, Cardinal *nprms));
343 void AnalyzeModeProc P((Widget w, XEvent *event,
344 String *prms, Cardinal *nprms));
345 void AnalyzeFileProc P((Widget w, XEvent *event,
346 String *prms, Cardinal *nprms));
347 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
349 void IcsClientProc P((Widget w, XEvent *event, String *prms,
351 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
352 void EditPositionProc P((Widget w, XEvent *event,
353 String *prms, Cardinal *nprms));
354 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
355 void EditCommentProc P((Widget w, XEvent *event,
356 String *prms, Cardinal *nprms));
357 void IcsInputBoxProc P((Widget w, XEvent *event,
358 String *prms, Cardinal *nprms));
359 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
365 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
370 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
371 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
372 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
373 void StopObservingProc P((Widget w, XEvent *event, String *prms,
375 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
377 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
379 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
380 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
384 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
386 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
388 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
389 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
391 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
393 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
395 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
396 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
397 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
398 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
400 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
401 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
403 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
405 void HighlightArrowProc P((Widget w, XEvent *event, String *prms,
407 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
408 //void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
409 void OneClickProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
410 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
412 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
414 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
416 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
418 //void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
419 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
421 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
423 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
425 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
427 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
428 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
429 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
430 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
431 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
432 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
433 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
434 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
435 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
436 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void DisplayMove P((int moveNumber));
439 void DisplayTitle P((char *title));
440 void ICSInitScript P((void));
441 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
442 void ErrorPopUp P((char *title, char *text, int modal));
443 void ErrorPopDown P((void));
444 static char *ExpandPathName P((char *path));
445 static void CreateAnimVars P((void));
446 static void DragPieceMove P((int x, int y));
447 static void DrawDragPiece P((void));
448 char *ModeToWidgetName P((GameMode mode));
449 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
450 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
451 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
452 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
453 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
454 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
455 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
456 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
457 void IcsOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
458 void SoundOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
459 void BoardOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
460 void LoadOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
461 void SaveOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
462 void GameListOptionsPopDown P(());
463 void ShufflePopDown P(());
464 void TimeControlPopDown P(());
465 void NewVariantPopDown P(());
466 void SettingsPopDown P(());
467 void update_ics_width P(());
468 int get_term_width P(());
469 int CopyMemoProc P(());
470 void DrawArrowHighlight P((int fromX, int fromY, int toX,int toY));
471 Boolean IsDrawArrowEnabled P(());
474 * XBoard depends on Xt R4 or higher
476 int xtVersion = XtSpecificationRelease;
481 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
482 jailSquareColor, highlightSquareColor, premoveHighlightColor;
483 Pixel lowTimeWarningColor;
484 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
485 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
486 wjPieceGC, bjPieceGC, prelineGC, countGC;
487 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
488 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
489 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
490 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
491 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
492 ICSInputShell, fileNameShell, askQuestionShell;
493 Widget historyShell, evalGraphShell, gameListShell;
494 int hOffset; // [HGM] dual
495 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
496 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
497 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
498 Font clockFontID, coordFontID, countFontID;
499 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
500 XtAppContext appContext;
502 char *oldICSInteractionTitle;
506 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
508 Position commentX = -1, commentY = -1;
509 Dimension commentW, commentH;
510 typedef unsigned int BoardSize;
512 Boolean chessProgram;
514 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
515 int squareSize, smallLayout = 0, tinyLayout = 0,
516 marginW, marginH, // [HGM] for run-time resizing
517 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
518 ICSInputBoxUp = False, askQuestionUp = False,
519 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
520 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
521 Pixel timerForegroundPixel, timerBackgroundPixel;
522 Pixel buttonForegroundPixel, buttonBackgroundPixel;
523 char *chessDir, *programName, *programVersion,
524 *gameCopyFilename, *gamePasteFilename;
525 Boolean alwaysOnTop = False;
526 Boolean saveSettingsOnExit;
527 char *settingsFileName;
528 char *icsTextMenuString;
530 char *firstChessProgramNames;
531 char *secondChessProgramNames;
533 WindowPlacement wpMain;
534 WindowPlacement wpConsole;
535 WindowPlacement wpComment;
536 WindowPlacement wpMoveHistory;
537 WindowPlacement wpEvalGraph;
538 WindowPlacement wpEngineOutput;
539 WindowPlacement wpGameList;
540 WindowPlacement wpTags;
544 Pixmap pieceBitmap[2][(int)BlackPawn];
545 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
546 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
547 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
548 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
549 Pixmap xpmBoardBitmap[2];
550 int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
551 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
552 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
553 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
554 XImage *ximLightSquare, *ximDarkSquare;
557 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
558 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
560 #define White(piece) ((int)(piece) < (int)BlackPawn)
562 /* Variables for doing smooth animation. This whole thing
563 would be much easier if the board was double-buffered,
564 but that would require a fairly major rewrite. */
569 GC blitGC, pieceGC, outlineGC;
570 XPoint startSquare, prevFrame, mouseDelta;
574 int startBoardX, startBoardY;
577 /* There can be two pieces being animated at once: a player
578 can begin dragging a piece before the remote opponent has moved. */
580 static AnimState game, player;
582 /* Bitmaps for use as masks when drawing XPM pieces.
583 Need one for each black and white piece. */
584 static Pixmap xpmMask[BlackKing + 1];
586 /* This magic number is the number of intermediate frames used
587 in each half of the animation. For short moves it's reduced
588 by 1. The total number of frames will be factor * 2 + 1. */
591 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
593 MenuItem fileMenu[] = {
594 {N_("New Game Ctrl+N"), "New Game", ResetProc},
595 {N_("New Shuffle Game ..."), "New Shuffle Game", ShuffleMenuProc},
596 {N_("New Variant ... Alt+Shift+V"), "New Variant", NewVariantProc}, // [HGM] variant: not functional yet
597 {"----", NULL, NothingProc},
598 {N_("Load Game Ctrl+O"), "Load Game", LoadGameProc},
599 {N_("Load Position Ctrl+Shift+O"), "Load Position", LoadPositionProc},
600 // {N_("Load Next Game"), "Load Next Game", LoadNextGameProc},
601 // {N_("Load Previous Game"), "Load Previous Game", LoadPrevGameProc},
602 // {N_("Reload Same Game"), "Reload Same Game", ReloadGameProc},
603 {N_("Next Position Shift+PgDn"), "Load Next Position", LoadNextPositionProc},
604 {N_("Prev Position Shift+PgUp"), "Load Previous Position", LoadPrevPositionProc},
605 {"----", NULL, NothingProc},
606 // {N_("Reload Same Position"), "Reload Same Position", ReloadPositionProc},
607 {N_("Save Game Ctrl+S"), "Save Game", SaveGameProc},
608 {N_("Save Position Ctrl+Shift+S"), "Save Position", SavePositionProc},
609 {"----", NULL, NothingProc},
610 {N_("Mail Move"), "Mail Move", MailMoveProc},
611 {N_("Reload CMail Message"), "Reload CMail Message", ReloadCmailMsgProc},
612 {"----", NULL, NothingProc},
613 {N_("Quit Ctr+Q"), "Exit", QuitProc},
617 MenuItem editMenu[] = {
618 {N_("Copy Game Ctrl+C"), "Copy Game", CopyGameProc},
619 {N_("Copy Position Ctrl+Shift+C"), "Copy Position", CopyPositionProc},
620 {"----", NULL, NothingProc},
621 {N_("Paste Game Ctrl+V"), "Paste Game", PasteGameProc},
622 {N_("Paste Position Ctrl+Shift+V"), "Paste Position", PastePositionProc},
623 {"----", NULL, NothingProc},
624 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
625 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
626 {N_("Edit Tags"), "Edit Tags", EditTagsProc},
627 {N_("Edit Comment"), "Edit Comment", EditCommentProc},
628 {"----", NULL, NothingProc},
629 {N_("Revert Home"), "Revert", RevertProc},
630 {N_("Annotate"), "Annotate", AnnotateProc},
631 {N_("Truncate Game End"), "Truncate Game", TruncateGameProc},
632 {"----", NULL, NothingProc},
633 {N_("Backward Alt+Left"), "Backward", BackwardProc},
634 {N_("Forward Alt+Right"), "Forward", ForwardProc},
635 {N_("Back to Start Alt+Home"), "Back to Start", ToStartProc},
636 {N_("Forward to End Alt+End"), "Forward to End", ToEndProc},
640 MenuItem viewMenu[] = {
641 {N_("Flip View F2"), "Flip View", FlipViewProc},
642 {"----", NULL, NothingProc},
643 {N_("Engine Output Alt+Shift+O"), "Show Engine Output", EngineOutputProc},
644 {N_("Move History Alt+Shift+H"), "Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
645 {N_("Evaluation Graph Alt+Shift+E"), "Show Evaluation Graph", EvalGraphProc},
646 {N_("Game List Alt+Shift+G"), "Show Game List", ShowGameListProc},
647 {"----", NULL, NothingProc},
648 {N_("Tags"), "Show Tags", EditTagsProc},
649 {N_("Comments"), "Show Comments", EditCommentProc},
650 {N_("ICS Input Box"), "ICS Input Box", IcsInputBoxProc},
651 {"----", NULL, NothingProc},
652 {N_("Board..."), "Board Options", BoardOptionsProc},
653 {N_("Game List Tags..."), "Game List", GameListOptionsPopUp},
657 MenuItem modeMenu[] = {
658 {N_("Machine White Ctrl+W"), "Machine White", MachineWhiteProc},
659 {N_("Machine Black Ctrl+B"), "Machine Black", MachineBlackProc},
660 {N_("Two Machines Ctrl+T"), "Two Machines", TwoMachinesProc},
661 {N_("Analysis Mode Ctrl+A"), "Analysis Mode", AnalyzeModeProc},
662 {N_("Analyze File Ctrl+F"), "Analyze File", AnalyzeFileProc },
663 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
664 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
665 {N_("Training"), "Training", TrainingProc},
666 {N_("ICS Client"), "ICS Client", IcsClientProc},
667 {"----", NULL, NothingProc},
668 {N_("Pause Pause"), "Pause", PauseProc},
672 MenuItem actionMenu[] = {
673 {N_("Accept F3"), "Accept", AcceptProc},
674 {N_("Decline F4"), "Decline", DeclineProc},
675 {N_("Rematch F12"), "Rematch", RematchProc},
676 {"----", NULL, NothingProc},
677 {N_("Call Flag F5"), "Call Flag", CallFlagProc},
678 {N_("Draw F6"), "Draw", DrawProc},
679 {N_("Adjourn F7"), "Adjourn", AdjournProc},
680 {N_("Abort F8"),"Abort", AbortProc},
681 {N_("Resign F9"), "Resign", ResignProc},
682 {"----", NULL, NothingProc},
683 {N_("Stop Observing F10"), "Stop Observing", StopObservingProc},
684 {N_("Stop Examining F11"), "Stop Examining", StopExaminingProc},
685 {N_("Upload to Examine"), "Upload to Examine", UploadProc},
686 {"----", NULL, NothingProc},
687 {N_("Adjudicate to White"), "Adjudicate to White", AdjuWhiteProc},
688 {N_("Adjudicate to Black"), "Adjudicate to Black", AdjuBlackProc},
689 {N_("Adjudicate Draw"), "Adjudicate Draw", AdjuDrawProc},
693 MenuItem engineMenu[] = {
694 {N_("Engine #1 Settings ..."), "Engine #1 Settings", FirstSettingsProc},
695 {N_("Engine #2 Settings ..."), "Engine #2 Settings", SecondSettingsProc},
696 {"----", NULL, NothingProc},
697 {N_("Hint"), "Hint", HintProc},
698 {N_("Book"), "Book", BookProc},
699 {"----", NULL, NothingProc},
700 {N_("Move Now Ctrl+M"), "Move Now", MoveNowProc},
701 {N_("Retract Move Ctrl+X"), "Retract Move", RetractMoveProc},
705 MenuItem optionsMenu[] = {
706 {N_("Time Control ... Alt+Shift+T"), "Time Control", TimeControlProc},
707 {N_("Common Engine ... Alt+Shift+U"), "Common Engine", UciMenuProc},
708 {N_("Adjudications ... Alt+Shift+J"), "Adjudications", EngineMenuProc},
709 {N_("ICS ..."), "ICS", IcsOptionsProc},
710 {N_("Load Game ..."), "Load Game", LoadOptionsProc},
711 {N_("Save Game ..."), "Save Game", SaveOptionsProc},
712 // {N_(" ..."), "", OptionsProc},
713 {N_("Game List ..."), "Game List", GameListOptionsPopUp},
714 {N_("Sounds ..."), "Sounds", SoundOptionsProc},
715 {"----", NULL, NothingProc},
716 {N_("Always Queen Ctrl+Shift+Q"), "Always Queen", AlwaysQueenProc},
717 {N_("Animate Dragging"), "Animate Dragging", AnimateDraggingProc},
718 {N_("Animate Moving Ctrl+Shift+A"), "Animate Moving", AnimateMovingProc},
719 {N_("Auto Flag Ctrl+Shift+F"), "Auto Flag", AutoflagProc},
720 {N_("Auto Flip View"), "Auto Flip View", AutoflipProc},
721 {N_("Blindfold"), "Blindfold", BlindfoldProc},
722 {N_("Flash Moves"), "Flash Moves", FlashMovesProc},
724 {N_("Highlight Dragging"), "Highlight Dragging", HighlightDraggingProc},
726 {N_("Highlight Last Move"), "Highlight Last Move", HighlightLastMoveProc},
727 {N_("Highlight With Arrow"), "Arrow", HighlightArrowProc},
728 {N_("Move Sound"), "Move Sound", MoveSoundProc},
729 // {N_("ICS Alarm"), "ICS Alarm", IcsAlarmProc},
730 {N_("One-Click Moving"), "OneClick", OneClickProc},
731 {N_("Periodic Updates"), "Periodic Updates", PeriodicUpdatesProc},
732 {N_("Ponder Next Move Ctrl+Shift+P"), "Ponder Next Move", PonderNextMoveProc},
733 {N_("Popup Exit Message"), "Popup Exit Message", PopupExitMessageProc},
734 {N_("Popup Move Errors"), "Popup Move Errors", PopupMoveErrorsProc},
735 // {N_("Premove"), "Premove", PremoveProc},
736 {N_("Show Coords"), "Show Coords", ShowCoordsProc},
737 {N_("Hide Thinking Ctrl+Shift+H"), "Hide Thinking", HideThinkingProc},
738 {N_("Test Legality Ctrl+Shift+L"), "Test Legality", TestLegalityProc},
739 {"----", NULL, NothingProc},
740 {N_("Save Settings Now"), "Save Settings Now", SaveSettingsProc},
741 {N_("Save Settings on Exit"), "Save Settings on Exit", SaveOnExitProc},
745 MenuItem helpMenu[] = {
746 {N_("Info XBoard"), "Info XBoard", InfoProc},
747 {N_("Man XBoard F1"), "Man XBoard", ManProc},
748 {"----", NULL, NothingProc},
749 {N_("About XBoard"), "About XBoard", AboutProc},
754 {N_("File"), "File", fileMenu},
755 {N_("Edit"), "Edit", editMenu},
756 {N_("View"), "View", viewMenu},
757 {N_("Mode"), "Mode", modeMenu},
758 {N_("Action"), "Action", actionMenu},
759 {N_("Engine"), "Engine", engineMenu},
760 {N_("Options"), "Options", optionsMenu},
761 {N_("Help"), "Help", helpMenu},
765 #define PAUSE_BUTTON "P"
766 MenuItem buttonBar[] = {
767 {"<<", "<<", ToStartProc},
768 {"<", "<", BackwardProc},
769 {PAUSE_BUTTON, PAUSE_BUTTON, PauseProc},
770 {">", ">", ForwardProc},
771 {">>", ">>", ToEndProc},
775 #define PIECE_MENU_SIZE 18
776 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
777 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
778 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
779 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
780 N_("Empty square"), N_("Clear board") },
781 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
782 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
783 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
784 N_("Empty square"), N_("Clear board") }
786 /* must be in same order as PieceMenuStrings! */
787 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
788 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
789 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
790 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
791 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
792 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
793 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
794 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
795 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
798 #define DROP_MENU_SIZE 6
799 String dropMenuStrings[DROP_MENU_SIZE] = {
800 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
802 /* must be in same order as PieceMenuStrings! */
803 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
804 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
805 WhiteRook, WhiteQueen
813 DropMenuEnables dmEnables[] = {
831 { XtNborderWidth, 0 },
832 { XtNdefaultDistance, 0 },
836 { XtNborderWidth, 0 },
837 { XtNresizable, (XtArgVal) True },
841 { XtNborderWidth, 0 },
847 { XtNjustify, (XtArgVal) XtJustifyRight },
848 { XtNlabel, (XtArgVal) "..." },
849 { XtNresizable, (XtArgVal) True },
850 { XtNresize, (XtArgVal) False }
853 Arg messageArgs[] = {
854 { XtNjustify, (XtArgVal) XtJustifyLeft },
855 { XtNlabel, (XtArgVal) "..." },
856 { XtNresizable, (XtArgVal) True },
857 { XtNresize, (XtArgVal) False }
861 { XtNborderWidth, 0 },
862 { XtNjustify, (XtArgVal) XtJustifyLeft }
865 XtResource clientResources[] = {
866 { "flashCount", "flashCount", XtRInt, sizeof(int),
867 XtOffset(AppDataPtr, flashCount), XtRImmediate,
868 (XtPointer) FLASH_COUNT },
871 XrmOptionDescRec shellOptions[] = {
872 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
873 { "-flash", "flashCount", XrmoptionNoArg, "3" },
874 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
877 XtActionsRec boardActions[] = {
878 { "DrawPosition", DrawPositionProc },
879 { "HandleUserMove", HandleUserMove },
880 { "AnimateUserMove", AnimateUserMove },
881 { "HandlePV", HandlePV },
882 { "SelectPV", SelectPV },
883 { "StopPV", StopPV },
884 { "FileNameAction", FileNameAction },
885 { "AskQuestionProc", AskQuestionProc },
886 { "AskQuestionReplyAction", AskQuestionReplyAction },
887 { "PieceMenuPopup", PieceMenuPopup },
888 { "WhiteClock", WhiteClock },
889 { "BlackClock", BlackClock },
890 { "Iconify", Iconify },
891 { "ResetProc", ResetProc },
892 { "NewVariantProc", NewVariantProc },
893 { "LoadGameProc", LoadGameProc },
894 { "LoadNextGameProc", LoadNextGameProc },
895 { "LoadPrevGameProc", LoadPrevGameProc },
896 { "LoadSelectedProc", LoadSelectedProc },
897 { "SetFilterProc", SetFilterProc },
898 { "ReloadGameProc", ReloadGameProc },
899 { "LoadPositionProc", LoadPositionProc },
900 { "LoadNextPositionProc", LoadNextPositionProc },
901 { "LoadPrevPositionProc", LoadPrevPositionProc },
902 { "ReloadPositionProc", ReloadPositionProc },
903 { "CopyPositionProc", CopyPositionProc },
904 { "PastePositionProc", PastePositionProc },
905 { "CopyGameProc", CopyGameProc },
906 { "PasteGameProc", PasteGameProc },
907 { "SaveGameProc", SaveGameProc },
908 { "SavePositionProc", SavePositionProc },
909 { "MailMoveProc", MailMoveProc },
910 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
911 { "QuitProc", QuitProc },
912 { "MachineWhiteProc", MachineWhiteProc },
913 { "MachineBlackProc", MachineBlackProc },
914 { "AnalysisModeProc", AnalyzeModeProc },
915 { "AnalyzeFileProc", AnalyzeFileProc },
916 { "TwoMachinesProc", TwoMachinesProc },
917 { "IcsClientProc", IcsClientProc },
918 { "EditGameProc", EditGameProc },
919 { "EditPositionProc", EditPositionProc },
920 { "TrainingProc", EditPositionProc },
921 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
922 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
923 { "ShowGameListProc", ShowGameListProc },
924 { "ShowMoveListProc", HistoryShowProc},
925 { "EditTagsProc", EditCommentProc },
926 { "EditCommentProc", EditCommentProc },
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 { "BlindfoldProc", BlindfoldProc },
964 { "FlashMovesProc", FlashMovesProc },
965 { "FlipViewProc", FlipViewProc },
967 { "HighlightDraggingProc", HighlightDraggingProc },
969 { "HighlightLastMoveProc", HighlightLastMoveProc },
970 // { "IcsAlarmProc", IcsAlarmProc },
971 { "MoveSoundProc", MoveSoundProc },
972 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
973 { "PonderNextMoveProc", PonderNextMoveProc },
974 { "PopupExitMessageProc", PopupExitMessageProc },
975 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
976 // { "PremoveProc", PremoveProc },
977 { "ShowCoordsProc", ShowCoordsProc },
978 { "ShowThinkingProc", ShowThinkingProc },
979 { "HideThinkingProc", HideThinkingProc },
980 { "TestLegalityProc", TestLegalityProc },
981 { "SaveSettingsProc", SaveSettingsProc },
982 { "SaveOnExitProc", SaveOnExitProc },
983 { "InfoProc", InfoProc },
984 { "ManProc", ManProc },
985 { "HintProc", HintProc },
986 { "BookProc", BookProc },
987 { "AboutGameProc", AboutGameProc },
988 { "AboutProc", AboutProc },
989 { "DebugProc", DebugProc },
990 { "NothingProc", NothingProc },
991 { "CommentClick", (XtActionProc) CommentClick },
992 { "CommentPopDown", (XtActionProc) CommentPopDown },
993 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
994 { "TagsPopDown", (XtActionProc) TagsPopDown },
995 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
996 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
997 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
998 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
999 { "GameListPopDown", (XtActionProc) GameListPopDown },
1000 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
1001 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1002 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
1003 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1004 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1005 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
1006 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
1007 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
1008 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
1009 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1012 char globalTranslations[] =
1013 ":<Key>F9: ResignProc() \n \
1014 :Ctrl<Key>n: ResetProc() \n \
1015 :Meta<Key>V: NewVariantProc() \n \
1016 :Ctrl<Key>o: LoadGameProc() \n \
1017 :Meta<Key>Next: LoadNextGameProc() \n \
1018 :Meta<Key>Prior: LoadPrevGameProc() \n \
1019 :Ctrl<Key>s: SaveGameProc() \n \
1020 :Ctrl<Key>c: CopyGameProc() \n \
1021 :Ctrl<Key>v: PasteGameProc() \n \
1022 :Ctrl<Key>O: LoadPositionProc() \n \
1023 :Shift<Key>Next: LoadNextPositionProc() \n \
1024 :Shift<Key>Prior: LoadPrevPositionProc() \n \
1025 :Ctrl<Key>S: SavePositionProc() \n \
1026 :Ctrl<Key>C: CopyPositionProc() \n \
1027 :Ctrl<Key>V: PastePositionProc() \n \
1028 :Ctrl<Key>q: QuitProc() \n \
1029 :Ctrl<Key>w: MachineWhiteProc() \n \
1030 :Ctrl<Key>b: MachineBlackProc() \n \
1031 :Ctrl<Key>t: TwoMachinesProc() \n \
1032 :Ctrl<Key>a: AnalysisModeProc() \n \
1033 :Ctrl<Key>f: AnalyzeFileProc() \n \
1034 :Ctrl<Key>e: EditGameProc() \n \
1035 :Ctrl<Key>E: EditPositionProc() \n \
1036 :Meta<Key>O: EngineOutputProc() \n \
1037 :Meta<Key>E: EvalGraphProc() \n \
1038 :Meta<Key>G: ShowGameListProc() \n \
1039 :Meta<Key>H: ShowMoveListProc() \n \
1040 :<Key>Pause: PauseProc() \n \
1041 :<Key>F3: AcceptProc() \n \
1042 :<Key>F4: DeclineProc() \n \
1043 :<Key>F12: RematchProc() \n \
1044 :<Key>F5: CallFlagProc() \n \
1045 :<Key>F6: DrawProc() \n \
1046 :<Key>F7: AdjournProc() \n \
1047 :<Key>F8: AbortProc() \n \
1048 :<Key>F10: StopObservingProc() \n \
1049 :<Key>F11: StopExaminingProc() \n \
1050 :Meta Ctrl<Key>F12: DebugProc() \n \
1051 :Meta<Key>End: ToEndProc() \n \
1052 :Meta<Key>Right: ForwardProc() \n \
1053 :Meta<Key>Home: ToStartProc() \n \
1054 :Meta<Key>Left: BackwardProc() \n \
1055 :<Key>Home: RevertProc() \n \
1056 :<Key>End: TruncateGameProc() \n \
1057 :Ctrl<Key>m: MoveNowProc() \n \
1058 :Ctrl<Key>x: RetractMoveProc() \n \
1059 :Meta<Key>J: EngineMenuProc() \n \
1060 :Meta<Key>U: UciMenuProc() \n \
1061 :Meta<Key>T: TimeControlProc() \n \
1062 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1063 :Ctrl<Key>F: AutoflagProc() \n \
1064 :Ctrl<Key>A: AnimateMovingProc() \n \
1065 :Ctrl<Key>P: PonderNextMoveProc() \n \
1066 :Ctrl<Key>L: TestLegalityProc() \n \
1067 :Ctrl<Key>H: HideThinkingProc() \n \
1068 :<Key>-: Iconify() \n \
1069 :<Key>F1: ManProc() \n \
1070 :<Key>F2: FlipViewProc() \n \
1071 <KeyDown>.: BackwardProc() \n \
1072 <KeyUp>.: ForwardProc() \n \
1073 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1074 \"Send to chess program:\",,1) \n \
1075 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1076 \"Send to second chess program:\",,2) \n";
1078 char boardTranslations[] =
1079 "<Btn1Down>: HandleUserMove(0) \n \
1080 Shift<Btn1Up>: HandleUserMove(1) \n \
1081 <Btn1Up>: HandleUserMove(0) \n \
1082 <Btn1Motion>: AnimateUserMove() \n \
1083 <Btn3Motion>: HandlePV() \n \
1084 <Btn3Up>: PieceMenuPopup(menuB) \n \
1085 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1086 PieceMenuPopup(menuB) \n \
1087 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1088 PieceMenuPopup(menuW) \n \
1089 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1090 PieceMenuPopup(menuW) \n \
1091 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1092 PieceMenuPopup(menuB) \n";
1094 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1095 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1097 char ICSInputTranslations[] =
1098 "<Key>Up: UpKeyProc() \n "
1099 "<Key>Down: DownKeyProc() \n "
1100 "<Key>Return: EnterKeyProc() \n";
1102 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1103 // as the widget is destroyed before the up-click can call extend-end
1104 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1106 String xboardResources[] = {
1107 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1108 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1109 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1114 /* Max possible square size */
1115 #define MAXSQSIZE 256
1117 static int xpm_avail[MAXSQSIZE];
1119 #ifdef HAVE_DIR_STRUCT
1121 /* Extract piece size from filename */
1123 xpm_getsize(name, len, ext)
1134 if ((p=strchr(name, '.')) == NULL ||
1135 StrCaseCmp(p+1, ext) != 0)
1141 while (*p && isdigit(*p))
1148 /* Setup xpm_avail */
1150 xpm_getavail(dirname, ext)
1158 for (i=0; i<MAXSQSIZE; ++i)
1161 if (appData.debugMode)
1162 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1164 dir = opendir(dirname);
1167 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1168 programName, dirname);
1172 while ((ent=readdir(dir)) != NULL) {
1173 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1174 if (i > 0 && i < MAXSQSIZE)
1184 xpm_print_avail(fp, ext)
1190 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1191 for (i=1; i<MAXSQSIZE; ++i) {
1197 /* Return XPM piecesize closest to size */
1199 xpm_closest_to(dirname, size, ext)
1205 int sm_diff = MAXSQSIZE;
1209 xpm_getavail(dirname, ext);
1211 if (appData.debugMode)
1212 xpm_print_avail(stderr, ext);
1214 for (i=1; i<MAXSQSIZE; ++i) {
1217 diff = (diff<0) ? -diff : diff;
1218 if (diff < sm_diff) {
1226 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1232 #else /* !HAVE_DIR_STRUCT */
1233 /* If we are on a system without a DIR struct, we can't
1234 read the directory, so we can't collect a list of
1235 filenames, etc., so we can't do any size-fitting. */
1237 xpm_closest_to(dirname, size, ext)
1242 fprintf(stderr, _("\
1243 Warning: No DIR structure found on this system --\n\
1244 Unable to autosize for XPM/XIM pieces.\n\
1245 Please report this error to frankm@hiwaay.net.\n\
1246 Include system type & operating system in message.\n"));
1249 #endif /* HAVE_DIR_STRUCT */
1251 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1252 "magenta", "cyan", "white" };
1256 TextColors textColors[(int)NColorClasses];
1258 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1260 parse_color(str, which)
1264 char *p, buf[100], *d;
1267 if (strlen(str) > 99) /* watch bounds on buf */
1272 for (i=0; i<which; ++i) {
1279 /* Could be looking at something like:
1281 .. in which case we want to stop on a comma also */
1282 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1286 return -1; /* Use default for empty field */
1289 if (which == 2 || isdigit(*p))
1292 while (*p && isalpha(*p))
1297 for (i=0; i<8; ++i) {
1298 if (!StrCaseCmp(buf, cnames[i]))
1299 return which? (i+40) : (i+30);
1301 if (!StrCaseCmp(buf, "default")) return -1;
1303 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1308 parse_cpair(cc, str)
1312 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1313 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1318 /* bg and attr are optional */
1319 textColors[(int)cc].bg = parse_color(str, 1);
1320 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1321 textColors[(int)cc].attr = 0;
1327 /* Arrange to catch delete-window events */
1328 Atom wm_delete_window;
1330 CatchDeleteWindow(Widget w, String procname)
1333 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1334 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1335 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1342 XtSetArg(args[0], XtNiconic, False);
1343 XtSetValues(shellWidget, args, 1);
1345 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1348 //---------------------------------------------------------------------------------------------------------
1349 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1352 #define CW_USEDEFAULT (1<<31)
1353 #define ICS_TEXT_MENU_SIZE 90
1354 #define DEBUG_FILE "xboard.debug"
1355 #define SetCurrentDirectory chdir
1356 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1360 // these two must some day move to frontend.h, when they are implemented
1361 Boolean GameListIsUp();
1363 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1366 // front-end part of option handling
1368 // [HGM] This platform-dependent table provides the location for storing the color info
1369 extern char *crWhite, * crBlack;
1373 &appData.whitePieceColor,
1374 &appData.blackPieceColor,
1375 &appData.lightSquareColor,
1376 &appData.darkSquareColor,
1377 &appData.highlightSquareColor,
1378 &appData.premoveHighlightColor,
1379 &appData.lowTimeWarningColor,
1390 // [HGM] font: keep a font for each square size, even non-stndard ones
1391 #define NUM_SIZES 18
1392 #define MAX_SIZE 130
1393 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1394 char *fontTable[NUM_FONTS][MAX_SIZE];
1397 ParseFont(char *name, int number)
1398 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1400 if(sscanf(name, "size%d:", &size)) {
1401 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1402 // defer processing it until we know if it matches our board size
1403 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1404 fontTable[number][size] = strdup(strchr(name, ':')+1);
1405 fontValid[number][size] = True;
1410 case 0: // CLOCK_FONT
1411 appData.clockFont = strdup(name);
1413 case 1: // MESSAGE_FONT
1414 appData.font = strdup(name);
1416 case 2: // COORD_FONT
1417 appData.coordFont = strdup(name);
1422 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1427 { // only 2 fonts currently
1428 appData.clockFont = CLOCK_FONT_NAME;
1429 appData.coordFont = COORD_FONT_NAME;
1430 appData.font = DEFAULT_FONT_NAME;
1435 { // no-op, until we identify the code for this already in XBoard and move it here
1439 ParseColor(int n, char *name)
1440 { // in XBoard, just copy the color-name string
1441 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1445 ParseTextAttribs(ColorClass cc, char *s)
1447 (&appData.colorShout)[cc] = strdup(s);
1451 ParseBoardSize(void *addr, char *name)
1453 appData.boardSize = strdup(name);
1458 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1462 SetCommPortDefaults()
1463 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1466 // [HGM] args: these three cases taken out to stay in front-end
1468 SaveFontArg(FILE *f, ArgDescriptor *ad)
1471 int i, n = (int)(intptr_t)ad->argLoc;
1473 case 0: // CLOCK_FONT
1474 name = appData.clockFont;
1476 case 1: // MESSAGE_FONT
1477 name = appData.font;
1479 case 2: // COORD_FONT
1480 name = appData.coordFont;
1485 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1486 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1487 fontTable[n][squareSize] = strdup(name);
1488 fontValid[n][squareSize] = True;
1491 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1492 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1497 { // nothing to do, as the sounds are at all times represented by their text-string names already
1501 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1502 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1503 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
1507 SaveColor(FILE *f, ArgDescriptor *ad)
1508 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1509 if(colorVariable[(int)(intptr_t)ad->argLoc])
1510 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
1514 SaveBoardSize(FILE *f, char *name, void *addr)
1515 { // wrapper to shield back-end from BoardSize & sizeInfo
1516 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1520 ParseCommPortSettings(char *s)
1521 { // no such option in XBoard (yet)
1524 extern Widget engineOutputShell;
1525 extern Widget tagsShell, editTagsShell;
1527 GetActualPlacement(Widget wg, WindowPlacement *wp)
1537 XtSetArg(args[i], XtNx, &x); i++;
1538 XtSetArg(args[i], XtNy, &y); i++;
1539 XtSetArg(args[i], XtNwidth, &w); i++;
1540 XtSetArg(args[i], XtNheight, &h); i++;
1541 XtGetValues(wg, args, i);
1550 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1551 // In XBoard this will have to wait until awareness of window parameters is implemented
1552 GetActualPlacement(shellWidget, &wpMain);
1553 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1554 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1555 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1556 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1557 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1558 else GetActualPlacement(editShell, &wpComment);
1559 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1560 else GetActualPlacement(editTagsShell, &wpTags);
1564 PrintCommPortSettings(FILE *f, char *name)
1565 { // This option does not exist in XBoard
1569 MySearchPath(char *installDir, char *name, char *fullname)
1570 { // just append installDir and name. Perhaps ExpandPath should be used here?
1571 name = ExpandPathName(name);
1572 if(name && name[0] == '/')
1573 safeStrCpy(fullname, name, MSG_SIZ );
1575 sprintf(fullname, "%s%c%s", installDir, '/', name);
1581 MyGetFullPathName(char *name, char *fullname)
1582 { // should use ExpandPath?
1583 name = ExpandPathName(name);
1584 safeStrCpy(fullname, name, MSG_SIZ );
1589 EnsureOnScreen(int *x, int *y, int minX, int minY)
1596 { // [HGM] args: allows testing if main window is realized from back-end
1597 return xBoardWindow != 0;
1601 PopUpStartupDialog()
1602 { // start menu not implemented in XBoard
1606 ConvertToLine(int argc, char **argv)
1608 static char line[128*1024], buf[1024];
1612 for(i=1; i<argc; i++)
1614 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1615 && argv[i][0] != '{' )
1616 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1618 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1619 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1622 line[strlen(line)-1] = NULLCHAR;
1626 //--------------------------------------------------------------------------------------------
1628 extern Boolean twoBoards, partnerUp;
1631 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1633 #define BoardSize int
1634 void InitDrawingSizes(BoardSize boardSize, int flags)
1635 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1636 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1638 XtGeometryResult gres;
1641 if(!formWidget) return;
1644 * Enable shell resizing.
1646 shellArgs[0].value = (XtArgVal) &w;
1647 shellArgs[1].value = (XtArgVal) &h;
1648 XtGetValues(shellWidget, shellArgs, 2);
1650 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1651 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1652 XtSetValues(shellWidget, &shellArgs[2], 4);
1654 XtSetArg(args[0], XtNdefaultDistance, &sep);
1655 XtGetValues(formWidget, args, 1);
1657 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1658 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1659 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1661 hOffset = boardWidth + 10;
1662 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1663 secondSegments[i] = gridSegments[i];
1664 secondSegments[i].x1 += hOffset;
1665 secondSegments[i].x2 += hOffset;
1668 XtSetArg(args[0], XtNwidth, boardWidth);
1669 XtSetArg(args[1], XtNheight, boardHeight);
1670 XtSetValues(boardWidget, args, 2);
1672 timerWidth = (boardWidth - sep) / 2;
1673 XtSetArg(args[0], XtNwidth, timerWidth);
1674 XtSetValues(whiteTimerWidget, args, 1);
1675 XtSetValues(blackTimerWidget, args, 1);
1677 XawFormDoLayout(formWidget, False);
1679 if (appData.titleInWindow) {
1681 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1682 XtSetArg(args[i], XtNheight, &h); i++;
1683 XtGetValues(titleWidget, args, i);
1685 w = boardWidth - 2*bor;
1687 XtSetArg(args[0], XtNwidth, &w);
1688 XtGetValues(menuBarWidget, args, 1);
1689 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1692 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1693 if (gres != XtGeometryYes && appData.debugMode) {
1695 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1696 programName, gres, w, h, wr, hr);
1700 XawFormDoLayout(formWidget, True);
1703 * Inhibit shell resizing.
1705 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1706 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1707 shellArgs[4].value = shellArgs[2].value = w;
1708 shellArgs[5].value = shellArgs[3].value = h;
1709 XtSetValues(shellWidget, &shellArgs[0], 6);
1711 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1714 for(i=0; i<4; i++) {
1716 for(p=0; p<=(int)WhiteKing; p++)
1717 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1718 if(gameInfo.variant == VariantShogi) {
1719 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1720 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1721 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1722 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1723 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1726 if(gameInfo.variant == VariantGothic) {
1727 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1730 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1731 xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
1732 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1735 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1736 for(p=0; p<=(int)WhiteKing; p++)
1737 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1738 if(gameInfo.variant == VariantShogi) {
1739 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1740 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1741 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1742 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1743 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1746 if(gameInfo.variant == VariantGothic) {
1747 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1750 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1751 ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
1752 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1757 for(i=0; i<2; i++) {
1759 for(p=0; p<=(int)WhiteKing; p++)
1760 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1761 if(gameInfo.variant == VariantShogi) {
1762 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1763 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1764 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1765 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1766 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1769 if(gameInfo.variant == VariantGothic) {
1770 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1773 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1774 pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
1775 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1785 void ParseIcsTextColors()
1786 { // [HGM] tken out of main(), so it can be called from ICS-Options dialog
1787 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1788 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1789 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1790 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1791 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1792 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1793 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1794 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1795 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1796 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1798 if (appData.colorize) {
1800 _("%s: can't parse color names; disabling colorization\n"),
1803 appData.colorize = FALSE;
1808 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
1809 XrmValue vFrom, vTo;
1810 int forceMono = False;
1812 if (!appData.monoMode) {
1813 vFrom.addr = (caddr_t) appData.lightSquareColor;
1814 vFrom.size = strlen(appData.lightSquareColor);
1815 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1816 if (vTo.addr == NULL) {
1817 appData.monoMode = True;
1820 lightSquareColor = *(Pixel *) vTo.addr;
1823 if (!appData.monoMode) {
1824 vFrom.addr = (caddr_t) appData.darkSquareColor;
1825 vFrom.size = strlen(appData.darkSquareColor);
1826 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1827 if (vTo.addr == NULL) {
1828 appData.monoMode = True;
1831 darkSquareColor = *(Pixel *) vTo.addr;
1834 if (!appData.monoMode) {
1835 vFrom.addr = (caddr_t) appData.whitePieceColor;
1836 vFrom.size = strlen(appData.whitePieceColor);
1837 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1838 if (vTo.addr == NULL) {
1839 appData.monoMode = True;
1842 whitePieceColor = *(Pixel *) vTo.addr;
1845 if (!appData.monoMode) {
1846 vFrom.addr = (caddr_t) appData.blackPieceColor;
1847 vFrom.size = strlen(appData.blackPieceColor);
1848 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1849 if (vTo.addr == NULL) {
1850 appData.monoMode = True;
1853 blackPieceColor = *(Pixel *) vTo.addr;
1857 if (!appData.monoMode) {
1858 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1859 vFrom.size = strlen(appData.highlightSquareColor);
1860 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1861 if (vTo.addr == NULL) {
1862 appData.monoMode = True;
1865 highlightSquareColor = *(Pixel *) vTo.addr;
1869 if (!appData.monoMode) {
1870 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1871 vFrom.size = strlen(appData.premoveHighlightColor);
1872 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1873 if (vTo.addr == NULL) {
1874 appData.monoMode = True;
1877 premoveHighlightColor = *(Pixel *) vTo.addr;
1888 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1889 XSetWindowAttributes window_attributes;
1891 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1892 XrmValue vFrom, vTo;
1893 XtGeometryResult gres;
1896 int forceMono = False;
1898 srandom(time(0)); // [HGM] book: make random truly random
1900 setbuf(stdout, NULL);
1901 setbuf(stderr, NULL);
1904 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1905 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1909 programName = strrchr(argv[0], '/');
1910 if (programName == NULL)
1911 programName = argv[0];
1916 XtSetLanguageProc(NULL, NULL, NULL);
1917 bindtextdomain(PACKAGE, LOCALEDIR);
1918 textdomain(PACKAGE);
1922 XtAppInitialize(&appContext, "XBoard", shellOptions,
1923 XtNumber(shellOptions),
1924 &argc, argv, xboardResources, NULL, 0);
1925 appData.boardSize = "";
1926 InitAppData(ConvertToLine(argc, argv));
1928 if (p == NULL) p = "/tmp";
1929 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1930 gameCopyFilename = (char*) malloc(i);
1931 gamePasteFilename = (char*) malloc(i);
1932 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1933 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1935 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1936 clientResources, XtNumber(clientResources),
1939 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1940 static char buf[MSG_SIZ];
1941 EscapeExpand(buf, appData.initString);
1942 appData.initString = strdup(buf);
1943 EscapeExpand(buf, appData.secondInitString);
1944 appData.secondInitString = strdup(buf);
1945 EscapeExpand(buf, appData.firstComputerString);
1946 appData.firstComputerString = strdup(buf);
1947 EscapeExpand(buf, appData.secondComputerString);
1948 appData.secondComputerString = strdup(buf);
1951 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1954 if (chdir(chessDir) != 0) {
1955 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1961 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1962 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1963 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1964 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1967 setbuf(debugFP, NULL);
1970 /* [HGM,HR] make sure board size is acceptable */
1971 if(appData.NrFiles > BOARD_FILES ||
1972 appData.NrRanks > BOARD_RANKS )
1973 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1976 /* This feature does not work; animation needs a rewrite */
1977 appData.highlightDragging = FALSE;
1981 xDisplay = XtDisplay(shellWidget);
1982 xScreen = DefaultScreen(xDisplay);
1983 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1985 gameInfo.variant = StringToVariant(appData.variant);
1986 InitPosition(FALSE);
1989 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1991 if (isdigit(appData.boardSize[0])) {
1992 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1993 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1994 &fontPxlSize, &smallLayout, &tinyLayout);
1996 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1997 programName, appData.boardSize);
2001 /* Find some defaults; use the nearest known size */
2002 SizeDefaults *szd, *nearest;
2003 int distance = 99999;
2004 nearest = szd = sizeDefaults;
2005 while (szd->name != NULL) {
2006 if (abs(szd->squareSize - squareSize) < distance) {
2008 distance = abs(szd->squareSize - squareSize);
2009 if (distance == 0) break;
2013 if (i < 2) lineGap = nearest->lineGap;
2014 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
2015 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
2016 if (i < 5) fontPxlSize = nearest->fontPxlSize;
2017 if (i < 6) smallLayout = nearest->smallLayout;
2018 if (i < 7) tinyLayout = nearest->tinyLayout;
2021 SizeDefaults *szd = sizeDefaults;
2022 if (*appData.boardSize == NULLCHAR) {
2023 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
2024 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
2027 if (szd->name == NULL) szd--;
2028 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
2030 while (szd->name != NULL &&
2031 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
2032 if (szd->name == NULL) {
2033 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
2034 programName, appData.boardSize);
2038 squareSize = szd->squareSize;
2039 lineGap = szd->lineGap;
2040 clockFontPxlSize = szd->clockFontPxlSize;
2041 coordFontPxlSize = szd->coordFontPxlSize;
2042 fontPxlSize = szd->fontPxlSize;
2043 smallLayout = szd->smallLayout;
2044 tinyLayout = szd->tinyLayout;
2045 // [HGM] font: use defaults from settings file if available and not overruled
2047 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
2048 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
2049 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
2050 appData.font = fontTable[MESSAGE_FONT][squareSize];
2051 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
2052 appData.coordFont = fontTable[COORD_FONT][squareSize];
2054 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
2055 if (strlen(appData.pixmapDirectory) > 0) {
2056 p = ExpandPathName(appData.pixmapDirectory);
2058 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
2059 appData.pixmapDirectory);
2062 if (appData.debugMode) {
2063 fprintf(stderr, _("\
2064 XBoard square size (hint): %d\n\
2065 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
2067 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
2068 if (appData.debugMode) {
2069 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
2072 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
2074 /* [HR] height treated separately (hacked) */
2075 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
2076 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
2077 if (appData.showJail == 1) {
2078 /* Jail on top and bottom */
2079 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2080 XtSetArg(boardArgs[2], XtNheight,
2081 boardHeight + 2*(lineGap + squareSize));
2082 } else if (appData.showJail == 2) {
2084 XtSetArg(boardArgs[1], XtNwidth,
2085 boardWidth + 2*(lineGap + squareSize));
2086 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2089 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2090 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2094 * Determine what fonts to use.
2096 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2097 clockFontID = XLoadFont(xDisplay, appData.clockFont);
2098 clockFontStruct = XQueryFont(xDisplay, clockFontID);
2099 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2100 coordFontID = XLoadFont(xDisplay, appData.coordFont);
2101 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2102 appData.font = FindFont(appData.font, fontPxlSize);
2103 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
2104 countFontStruct = XQueryFont(xDisplay, countFontID);
2105 // appData.font = FindFont(appData.font, fontPxlSize);
2107 xdb = XtDatabase(xDisplay);
2108 XrmPutStringResource(&xdb, "*font", appData.font);
2111 * Detect if there are not enough colors available and adapt.
2113 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2114 appData.monoMode = True;
2117 forceMono = MakeColors();
2120 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2123 if (appData.bitmapDirectory == NULL ||
2124 appData.bitmapDirectory[0] == NULLCHAR)
2125 appData.bitmapDirectory = DEF_BITMAP_DIR;
2128 if (appData.lowTimeWarning && !appData.monoMode) {
2129 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2130 vFrom.size = strlen(appData.lowTimeWarningColor);
2131 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2132 if (vTo.addr == NULL)
2133 appData.monoMode = True;
2135 lowTimeWarningColor = *(Pixel *) vTo.addr;
2138 if (appData.monoMode && appData.debugMode) {
2139 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2140 (unsigned long) XWhitePixel(xDisplay, xScreen),
2141 (unsigned long) XBlackPixel(xDisplay, xScreen));
2144 ParseIcsTextColors();
2145 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2146 textColors[ColorNone].attr = 0;
2148 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2154 layoutName = "tinyLayout";
2155 } else if (smallLayout) {
2156 layoutName = "smallLayout";
2158 layoutName = "normalLayout";
2160 /* Outer layoutWidget is there only to provide a name for use in
2161 resources that depend on the layout style */
2163 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2164 layoutArgs, XtNumber(layoutArgs));
2166 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2167 formArgs, XtNumber(formArgs));
2168 XtSetArg(args[0], XtNdefaultDistance, &sep);
2169 XtGetValues(formWidget, args, 1);
2172 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2173 XtSetArg(args[0], XtNtop, XtChainTop);
2174 XtSetArg(args[1], XtNbottom, XtChainTop);
2175 XtSetArg(args[2], XtNright, XtChainLeft);
2176 XtSetValues(menuBarWidget, args, 3);
2178 widgetList[j++] = whiteTimerWidget =
2179 XtCreateWidget("whiteTime", labelWidgetClass,
2180 formWidget, timerArgs, XtNumber(timerArgs));
2181 XtSetArg(args[0], XtNfont, clockFontStruct);
2182 XtSetArg(args[1], XtNtop, XtChainTop);
2183 XtSetArg(args[2], XtNbottom, XtChainTop);
2184 XtSetValues(whiteTimerWidget, args, 3);
2186 widgetList[j++] = blackTimerWidget =
2187 XtCreateWidget("blackTime", labelWidgetClass,
2188 formWidget, timerArgs, XtNumber(timerArgs));
2189 XtSetArg(args[0], XtNfont, clockFontStruct);
2190 XtSetArg(args[1], XtNtop, XtChainTop);
2191 XtSetArg(args[2], XtNbottom, XtChainTop);
2192 XtSetValues(blackTimerWidget, args, 3);
2194 if (appData.titleInWindow) {
2195 widgetList[j++] = titleWidget =
2196 XtCreateWidget("title", labelWidgetClass, formWidget,
2197 titleArgs, XtNumber(titleArgs));
2198 XtSetArg(args[0], XtNtop, XtChainTop);
2199 XtSetArg(args[1], XtNbottom, XtChainTop);
2200 XtSetValues(titleWidget, args, 2);
2203 if (appData.showButtonBar) {
2204 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2205 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2206 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2207 XtSetArg(args[2], XtNtop, XtChainTop);
2208 XtSetArg(args[3], XtNbottom, XtChainTop);
2209 XtSetValues(buttonBarWidget, args, 4);
2212 widgetList[j++] = messageWidget =
2213 XtCreateWidget("message", labelWidgetClass, formWidget,
2214 messageArgs, XtNumber(messageArgs));
2215 XtSetArg(args[0], XtNtop, XtChainTop);
2216 XtSetArg(args[1], XtNbottom, XtChainTop);
2217 XtSetValues(messageWidget, args, 2);
2219 widgetList[j++] = boardWidget =
2220 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2221 XtNumber(boardArgs));
2223 XtManageChildren(widgetList, j);
2225 timerWidth = (boardWidth - sep) / 2;
2226 XtSetArg(args[0], XtNwidth, timerWidth);
2227 XtSetValues(whiteTimerWidget, args, 1);
2228 XtSetValues(blackTimerWidget, args, 1);
2230 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2231 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2232 XtGetValues(whiteTimerWidget, args, 2);
2234 if (appData.showButtonBar) {
2235 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2236 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2237 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2241 * formWidget uses these constraints but they are stored
2245 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2246 XtSetValues(menuBarWidget, args, i);
2247 if (appData.titleInWindow) {
2250 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2251 XtSetValues(whiteTimerWidget, args, i);
2253 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2254 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2255 XtSetValues(blackTimerWidget, args, i);
2257 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2258 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2259 XtSetValues(titleWidget, args, i);
2261 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2262 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2263 XtSetValues(messageWidget, args, i);
2264 if (appData.showButtonBar) {
2266 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2267 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2268 XtSetValues(buttonBarWidget, args, i);
2272 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2273 XtSetValues(whiteTimerWidget, args, i);
2275 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2276 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2277 XtSetValues(blackTimerWidget, args, i);
2279 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2280 XtSetValues(titleWidget, args, i);
2282 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2283 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2284 XtSetValues(messageWidget, args, i);
2285 if (appData.showButtonBar) {
2287 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2288 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2289 XtSetValues(buttonBarWidget, args, i);
2294 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2295 XtSetValues(whiteTimerWidget, args, i);
2297 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2298 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2299 XtSetValues(blackTimerWidget, args, i);
2301 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2302 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2303 XtSetValues(messageWidget, args, i);
2304 if (appData.showButtonBar) {
2306 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2307 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2308 XtSetValues(buttonBarWidget, args, i);
2312 XtSetArg(args[0], XtNfromVert, messageWidget);
2313 XtSetArg(args[1], XtNtop, XtChainTop);
2314 XtSetArg(args[2], XtNbottom, XtChainBottom);
2315 XtSetArg(args[3], XtNleft, XtChainLeft);
2316 XtSetArg(args[4], XtNright, XtChainRight);
2317 XtSetValues(boardWidget, args, 5);
2319 XtRealizeWidget(shellWidget);
2322 XtSetArg(args[0], XtNx, wpMain.x);
2323 XtSetArg(args[1], XtNy, wpMain.y);
2324 XtSetValues(shellWidget, args, 2);
2328 * Correct the width of the message and title widgets.
2329 * It is not known why some systems need the extra fudge term.
2330 * The value "2" is probably larger than needed.
2332 XawFormDoLayout(formWidget, False);
2334 #define WIDTH_FUDGE 2
2336 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2337 XtSetArg(args[i], XtNheight, &h); i++;
2338 XtGetValues(messageWidget, args, i);
2339 if (appData.showButtonBar) {
2341 XtSetArg(args[i], XtNwidth, &w); i++;
2342 XtGetValues(buttonBarWidget, args, i);
2343 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2345 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2348 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2349 if (gres != XtGeometryYes && appData.debugMode) {
2350 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2351 programName, gres, w, h, wr, hr);
2354 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2355 /* The size used for the child widget in layout lags one resize behind
2356 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2358 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2359 if (gres != XtGeometryYes && appData.debugMode) {
2360 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2361 programName, gres, w, h, wr, hr);
2364 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2365 XtSetArg(args[1], XtNright, XtChainRight);
2366 XtSetValues(messageWidget, args, 2);
2368 if (appData.titleInWindow) {
2370 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2371 XtSetArg(args[i], XtNheight, &h); i++;
2372 XtGetValues(titleWidget, args, i);
2374 w = boardWidth - 2*bor;
2376 XtSetArg(args[0], XtNwidth, &w);
2377 XtGetValues(menuBarWidget, args, 1);
2378 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2381 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2382 if (gres != XtGeometryYes && appData.debugMode) {
2384 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2385 programName, gres, w, h, wr, hr);
2388 XawFormDoLayout(formWidget, True);
2390 xBoardWindow = XtWindow(boardWidget);
2392 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2393 // not need to go into InitDrawingSizes().
2397 * Create X checkmark bitmap and initialize option menu checks.
2399 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2400 checkmark_bits, checkmark_width, checkmark_height);
2401 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2402 if (appData.alwaysPromoteToQueen) {
2403 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2406 if (appData.animateDragging) {
2407 XtSetValues(XtNameToWidget(menuBarWidget,
2408 "menuOptions.Animate Dragging"),
2411 if (appData.animate) {
2412 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2415 if (appData.autoCallFlag) {
2416 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2419 if (appData.autoFlipView) {
2420 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2423 if (appData.blindfold) {
2424 XtSetValues(XtNameToWidget(menuBarWidget,
2425 "menuOptions.Blindfold"), args, 1);
2427 if (appData.flashCount > 0) {
2428 XtSetValues(XtNameToWidget(menuBarWidget,
2429 "menuOptions.Flash Moves"),
2433 if (appData.highlightDragging) {
2434 XtSetValues(XtNameToWidget(menuBarWidget,
2435 "menuOptions.Highlight Dragging"),
2439 if (appData.highlightLastMove) {
2440 XtSetValues(XtNameToWidget(menuBarWidget,
2441 "menuOptions.Highlight Last Move"),
2444 if (appData.highlightMoveWithArrow) {
2445 XtSetValues(XtNameToWidget(menuBarWidget,
2446 "menuOptions.Arrow"),
2449 // if (appData.icsAlarm) {
2450 // XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2453 if (appData.ringBellAfterMoves) {
2454 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2457 if (appData.oneClick) {
2458 XtSetValues(XtNameToWidget(menuBarWidget,
2459 "menuOptions.OneClick"), args, 1);
2461 if (appData.periodicUpdates) {
2462 XtSetValues(XtNameToWidget(menuBarWidget,
2463 "menuOptions.Periodic Updates"), args, 1);
2465 if (appData.ponderNextMove) {
2466 XtSetValues(XtNameToWidget(menuBarWidget,
2467 "menuOptions.Ponder Next Move"), args, 1);
2469 if (appData.popupExitMessage) {
2470 XtSetValues(XtNameToWidget(menuBarWidget,
2471 "menuOptions.Popup Exit Message"), args, 1);
2473 if (appData.popupMoveErrors) {
2474 XtSetValues(XtNameToWidget(menuBarWidget,
2475 "menuOptions.Popup Move Errors"), args, 1);
2477 // if (appData.premove) {
2478 // XtSetValues(XtNameToWidget(menuBarWidget,
2479 // "menuOptions.Premove"), args, 1);
2481 if (appData.showCoords) {
2482 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2485 if (appData.hideThinkingFromHuman) {
2486 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2489 if (appData.testLegality) {
2490 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2493 if (saveSettingsOnExit) {
2494 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2501 ReadBitmap(&wIconPixmap, "icon_white.bm",
2502 icon_white_bits, icon_white_width, icon_white_height);
2503 ReadBitmap(&bIconPixmap, "icon_black.bm",
2504 icon_black_bits, icon_black_width, icon_black_height);
2505 iconPixmap = wIconPixmap;
2507 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2508 XtSetValues(shellWidget, args, i);
2511 * Create a cursor for the board widget.
2513 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2514 XChangeWindowAttributes(xDisplay, xBoardWindow,
2515 CWCursor, &window_attributes);
2518 * Inhibit shell resizing.
2520 shellArgs[0].value = (XtArgVal) &w;
2521 shellArgs[1].value = (XtArgVal) &h;
2522 XtGetValues(shellWidget, shellArgs, 2);
2523 shellArgs[4].value = shellArgs[2].value = w;
2524 shellArgs[5].value = shellArgs[3].value = h;
2525 XtSetValues(shellWidget, &shellArgs[2], 4);
2526 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2527 marginH = h - boardHeight;
2529 CatchDeleteWindow(shellWidget, "QuitProc");
2534 if (appData.bitmapDirectory[0] != NULLCHAR) {
2538 CreateXPMBoard(appData.liteBackTextureFile, 1);
2539 CreateXPMBoard(appData.darkBackTextureFile, 0);
2543 /* Create regular pieces */
2544 if (!useImages) CreatePieces();
2549 if (appData.animate || appData.animateDragging)
2552 XtAugmentTranslations(formWidget,
2553 XtParseTranslationTable(globalTranslations));
2554 XtAugmentTranslations(boardWidget,
2555 XtParseTranslationTable(boardTranslations));
2556 XtAugmentTranslations(whiteTimerWidget,
2557 XtParseTranslationTable(whiteTranslations));
2558 XtAugmentTranslations(blackTimerWidget,
2559 XtParseTranslationTable(blackTranslations));
2561 /* Why is the following needed on some versions of X instead
2562 * of a translation? */
2563 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2564 (XtEventHandler) EventProc, NULL);
2567 /* [AS] Restore layout */
2568 if( wpMoveHistory.visible ) {
2572 if( wpEvalGraph.visible )
2577 if( wpEngineOutput.visible ) {
2578 EngineOutputPopUp();
2583 if (errorExitStatus == -1) {
2584 if (appData.icsActive) {
2585 /* We now wait until we see "login:" from the ICS before
2586 sending the logon script (problems with timestamp otherwise) */
2587 /*ICSInitScript();*/
2588 if (appData.icsInputBox) ICSInputBoxPopUp();
2592 signal(SIGWINCH, TermSizeSigHandler);
2594 signal(SIGINT, IntSigHandler);
2595 signal(SIGTERM, IntSigHandler);
2596 if (*appData.cmailGameName != NULLCHAR) {
2597 signal(SIGUSR1, CmailSigHandler);
2600 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2602 XtSetKeyboardFocus(shellWidget, formWidget);
2604 XtAppMainLoop(appContext);
2605 if (appData.debugMode) fclose(debugFP); // [DM] debug
2612 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2613 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2615 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2616 unlink(gameCopyFilename);
2617 unlink(gamePasteFilename);
2620 RETSIGTYPE TermSizeSigHandler(int sig)
2633 CmailSigHandler(sig)
2639 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2641 /* Activate call-back function CmailSigHandlerCallBack() */
2642 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2644 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2648 CmailSigHandlerCallBack(isr, closure, message, count, error)
2656 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2658 /**** end signal code ****/
2664 /* try to open the icsLogon script, either in the location given
2665 * or in the users HOME directory
2672 f = fopen(appData.icsLogon, "r");
2675 homedir = getenv("HOME");
2676 if (homedir != NULL)
2678 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2679 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2680 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2681 f = fopen(buf, "r");
2686 ProcessICSInitScript(f);
2688 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2697 EditCommentPopDown();
2712 if (!menuBarWidget) return;
2713 w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2715 DisplayError("menuEdit.Revert", 0);
2717 XtSetSensitive(w, !grey);
2719 w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2721 DisplayError("menuEdit.Annotate", 0);
2723 XtSetSensitive(w, !grey);
2728 SetMenuEnables(enab)
2732 if (!menuBarWidget) return;
2733 while (enab->name != NULL) {
2734 w = XtNameToWidget(menuBarWidget, enab->name);
2736 DisplayError(enab->name, 0);
2738 XtSetSensitive(w, enab->value);
2744 Enables icsEnables[] = {
2745 { "menuFile.Mail Move", False },
2746 { "menuFile.Reload CMail Message", False },
2747 { "menuMode.Machine Black", False },
2748 { "menuMode.Machine White", False },
2749 { "menuMode.Analysis Mode", False },
2750 { "menuMode.Analyze File", False },
2751 { "menuMode.Two Machines", False },
2753 { "menuEngine.Hint", False },
2754 { "menuEngine.Book", False },
2755 { "menuEngine.Move Now", False },
2756 { "menuOptions.Periodic Updates", False },
2757 { "menuOptions.Hide Thinking", False },
2758 { "menuOptions.Ponder Next Move", False },
2759 { "menuEngine.Engine #1 Settings", False },
2761 { "menuEngine.Engine #2 Settings", False },
2762 { "menuEdit.Annotate", False },
2766 Enables ncpEnables[] = {
2767 { "menuFile.Mail Move", False },
2768 { "menuFile.Reload CMail Message", False },
2769 { "menuMode.Machine White", False },
2770 { "menuMode.Machine Black", False },
2771 { "menuMode.Analysis Mode", False },
2772 { "menuMode.Analyze File", False },
2773 { "menuMode.Two Machines", False },
2774 { "menuMode.ICS Client", False },
2775 { "menuView.ICS Input Box", False },
2776 { "Action", False },
2777 { "menuEdit.Revert", False },
2778 { "menuEdit.Annotate", False },
2779 { "menuEngine.Engine #1 Settings", False },
2780 { "menuEngine.Engine #2 Settings", False },
2781 { "menuEngine.Move Now", False },
2782 { "menuEngine.Retract Move", False },
2783 { "menuOptions.Auto Flag", False },
2784 { "menuOptions.Auto Flip View", False },
2785 { "menuOptions.ICS", False },
2786 // { "menuOptions.ICS Alarm", False },
2787 { "menuOptions.Move Sound", False },
2788 { "menuOptions.Hide Thinking", False },
2789 { "menuOptions.Periodic Updates", False },
2790 { "menuOptions.Ponder Next Move", False },
2791 { "menuEngine.Hint", False },
2792 { "menuEngine.Book", False },
2796 Enables gnuEnables[] = {
2797 { "menuMode.ICS Client", False },
2798 { "menuView.ICS Input Box", False },
2799 { "menuAction.Accept", False },
2800 { "menuAction.Decline", False },
2801 { "menuAction.Rematch", False },
2802 { "menuAction.Adjourn", False },
2803 { "menuAction.Stop Examining", False },
2804 { "menuAction.Stop Observing", False },
2805 { "menuAction.Upload to Examine", False },
2806 { "menuEdit.Revert", False },
2807 { "menuEdit.Annotate", False },
2808 { "menuOptions.ICS", False },
2810 /* The next two options rely on SetCmailMode being called *after* */
2811 /* SetGNUMode so that when GNU is being used to give hints these */
2812 /* menu options are still available */
2814 { "menuFile.Mail Move", False },
2815 { "menuFile.Reload CMail Message", False },
2819 Enables cmailEnables[] = {
2821 { "menuAction.Call Flag", False },
2822 { "menuAction.Draw", True },
2823 { "menuAction.Adjourn", False },
2824 { "menuAction.Abort", False },
2825 { "menuAction.Stop Observing", False },
2826 { "menuAction.Stop Examining", False },
2827 { "menuFile.Mail Move", True },
2828 { "menuFile.Reload CMail Message", True },
2832 Enables trainingOnEnables[] = {
2833 { "menuMode.Edit Comment", False },
2834 { "menuMode.Pause", False },
2835 { "menuEdit.Forward", False },
2836 { "menuEdit.Backward", False },
2837 { "menuEdit.Forward to End", False },
2838 { "menuEdit.Back to Start", False },
2839 { "menuEngine.Move Now", False },
2840 { "menuEdit.Truncate Game", False },
2844 Enables trainingOffEnables[] = {
2845 { "menuMode.Edit Comment", True },
2846 { "menuMode.Pause", True },
2847 { "menuEdit.Forward", True },
2848 { "menuEdit.Backward", True },
2849 { "menuEdit.Forward to End", True },
2850 { "menuEdit.Back to Start", True },
2851 { "menuEngine.Move Now", True },
2852 { "menuEdit.Truncate Game", True },
2856 Enables machineThinkingEnables[] = {
2857 { "menuFile.Load Game", False },
2858 // { "menuFile.Load Next Game", False },
2859 // { "menuFile.Load Previous Game", False },
2860 // { "menuFile.Reload Same Game", False },
2861 { "menuEdit.Paste Game", False },
2862 { "menuFile.Load Position", False },
2863 // { "menuFile.Load Next Position", False },
2864 // { "menuFile.Load Previous Position", False },
2865 // { "menuFile.Reload Same Position", False },
2866 { "menuEdit.Paste Position", False },
2867 { "menuMode.Machine White", False },
2868 { "menuMode.Machine Black", False },
2869 { "menuMode.Two Machines", False },
2870 { "menuEngine.Retract Move", False },
2874 Enables userThinkingEnables[] = {
2875 { "menuFile.Load Game", True },
2876 // { "menuFile.Load Next Game", True },
2877 // { "menuFile.Load Previous Game", True },
2878 // { "menuFile.Reload Same Game", True },
2879 { "menuEdit.Paste Game", True },
2880 { "menuFile.Load Position", True },
2881 // { "menuFile.Load Next Position", True },
2882 // { "menuFile.Load Previous Position", True },
2883 // { "menuFile.Reload Same Position", True },
2884 { "menuEdit.Paste Position", True },
2885 { "menuMode.Machine White", True },
2886 { "menuMode.Machine Black", True },
2887 { "menuMode.Two Machines", True },
2888 { "menuEngine.Retract Move", True },
2894 SetMenuEnables(icsEnables);
2897 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2898 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2905 SetMenuEnables(ncpEnables);
2911 SetMenuEnables(gnuEnables);
2917 SetMenuEnables(cmailEnables);
2923 SetMenuEnables(trainingOnEnables);
2924 if (appData.showButtonBar) {
2925 XtSetSensitive(buttonBarWidget, False);
2931 SetTrainingModeOff()
2933 SetMenuEnables(trainingOffEnables);
2934 if (appData.showButtonBar) {
2935 XtSetSensitive(buttonBarWidget, True);
2940 SetUserThinkingEnables()
2942 if (appData.noChessProgram) return;
2943 SetMenuEnables(userThinkingEnables);
2947 SetMachineThinkingEnables()
2949 if (appData.noChessProgram) return;
2950 SetMenuEnables(machineThinkingEnables);
2952 case MachinePlaysBlack:
2953 case MachinePlaysWhite:
2954 case TwoMachinesPlay:
2955 XtSetSensitive(XtNameToWidget(menuBarWidget,
2956 ModeToWidgetName(gameMode)), True);
2963 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2964 #define HISTORY_SIZE 64
2965 static char *history[HISTORY_SIZE];
2966 int histIn = 0, histP = 0;
2969 SaveInHistory(char *cmd)
2971 if (history[histIn] != NULL) {
2972 free(history[histIn]);
2973 history[histIn] = NULL;
2975 if (*cmd == NULLCHAR) return;
2976 history[histIn] = StrSave(cmd);
2977 histIn = (histIn + 1) % HISTORY_SIZE;
2978 if (history[histIn] != NULL) {
2979 free(history[histIn]);
2980 history[histIn] = NULL;
2986 PrevInHistory(char *cmd)
2989 if (histP == histIn) {
2990 if (history[histIn] != NULL) free(history[histIn]);
2991 history[histIn] = StrSave(cmd);
2993 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
2994 if (newhp == histIn || history[newhp] == NULL) return NULL;
2996 return history[histP];
3002 if (histP == histIn) return NULL;
3003 histP = (histP + 1) % HISTORY_SIZE;
3004 return history[histP];
3006 // end of borrowed code
3008 #define Abs(n) ((n)<0 ? -(n) : (n))
3011 * Find a font that matches "pattern" that is as close as
3012 * possible to the targetPxlSize. Prefer fonts that are k
3013 * pixels smaller to fonts that are k pixels larger. The
3014 * pattern must be in the X Consortium standard format,
3015 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3016 * The return value should be freed with XtFree when no
3020 FindFont(pattern, targetPxlSize)
3024 char **fonts, *p, *best, *scalable, *scalableTail;
3025 int i, j, nfonts, minerr, err, pxlSize;
3028 char **missing_list;
3030 char *def_string, *base_fnt_lst, strInt[3];
3032 XFontStruct **fnt_list;
3034 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3035 snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
3036 p = strstr(pattern, "--");
3037 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3038 strcat(base_fnt_lst, strInt);
3039 strcat(base_fnt_lst, strchr(p + 2, '-'));
3041 if ((fntSet = XCreateFontSet(xDisplay,
3045 &def_string)) == NULL) {
3047 fprintf(stderr, _("Unable to create font set.\n"));
3051 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3053 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3055 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3056 programName, pattern);
3064 for (i=0; i<nfonts; i++) {
3067 if (*p != '-') continue;
3069 if (*p == NULLCHAR) break;
3070 if (*p++ == '-') j++;
3072 if (j < 7) continue;
3075 scalable = fonts[i];
3078 err = pxlSize - targetPxlSize;
3079 if (Abs(err) < Abs(minerr) ||
3080 (minerr > 0 && err < 0 && -err == minerr)) {
3086 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3087 /* If the error is too big and there is a scalable font,
3088 use the scalable font. */
3089 int headlen = scalableTail - scalable;
3090 p = (char *) XtMalloc(strlen(scalable) + 10);
3091 while (isdigit(*scalableTail)) scalableTail++;
3092 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3094 p = (char *) XtMalloc(strlen(best) + 2);
3095 safeStrCpy(p, best, strlen(best)+1 );
3097 if (appData.debugMode) {
3098 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3099 pattern, targetPxlSize, p);
3102 if (missing_count > 0)
3103 XFreeStringList(missing_list);
3104 XFreeFontSet(xDisplay, fntSet);
3106 XFreeFontNames(fonts);
3112 { // [HGM] deletes GCs that are to be remade, to prevent resource leak;
3113 // must be called before all non-first callse to CreateGCs()
3114 XtReleaseGC(shellWidget, highlineGC);
3115 XtReleaseGC(shellWidget, lightSquareGC);
3116 XtReleaseGC(shellWidget, darkSquareGC);
3117 if (appData.monoMode) {
3118 if (DefaultDepth(xDisplay, xScreen) == 1) {
3119 XtReleaseGC(shellWidget, wbPieceGC);
3121 XtReleaseGC(shellWidget, bwPieceGC);
3124 XtReleaseGC(shellWidget, prelineGC);
3125 XtReleaseGC(shellWidget, jailSquareGC);
3126 XtReleaseGC(shellWidget, wdPieceGC);
3127 XtReleaseGC(shellWidget, wlPieceGC);
3128 XtReleaseGC(shellWidget, wjPieceGC);
3129 XtReleaseGC(shellWidget, bdPieceGC);
3130 XtReleaseGC(shellWidget, blPieceGC);
3131 XtReleaseGC(shellWidget, bjPieceGC);
3135 void CreateGCs(int redo)
3137 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3138 | GCBackground | GCFunction | GCPlaneMask;
3139 XGCValues gc_values;
3142 gc_values.plane_mask = AllPlanes;
3143 gc_values.line_width = lineGap;
3144 gc_values.line_style = LineSolid;
3145 gc_values.function = GXcopy;
3148 DeleteGCs(); // called a second time; clean up old GCs first
3149 } else { // [HGM] grid and font GCs created on first call only
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 black)
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));
3293 /* create Pixmap of piece */
3294 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3296 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3299 /* create Pixmap of clipmask
3300 Note: We assume the white/black pieces have the same
3301 outline, so we make only 6 masks. This is okay
3302 since the XPM clipmask routines do the same. */
3304 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3306 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3309 /* now create the 1-bit version */
3310 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3313 values.foreground = 1;
3314 values.background = 0;
3316 /* Don't use XtGetGC, not read only */
3317 maskGC = XCreateGC(xDisplay, *mask,
3318 GCForeground | GCBackground, &values);
3319 XCopyPlane(xDisplay, temp, *mask, maskGC,
3320 0, 0, squareSize, squareSize, 0, 0, 1);
3321 XFreePixmap(xDisplay, temp);
3326 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3328 void CreateXIMPieces()
3333 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3338 /* The XSynchronize calls were copied from CreatePieces.
3339 Not sure if needed, but can't hurt */
3340 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3343 /* temp needed by loadXIM() */
3344 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3345 0, 0, ss, ss, AllPlanes, XYPixmap);
3347 if (strlen(appData.pixmapDirectory) == 0) {
3351 if (appData.monoMode) {
3352 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3356 fprintf(stderr, _("\nLoading XIMs...\n"));
3358 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3359 fprintf(stderr, "%d", piece+1);
3360 for (kind=0; kind<4; kind++) {
3361 fprintf(stderr, ".");
3362 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3363 ExpandPathName(appData.pixmapDirectory),
3364 piece <= (int) WhiteKing ? "" : "w",
3365 pieceBitmapNames[piece],
3367 ximPieceBitmap[kind][piece] =
3368 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3369 0, 0, ss, ss, AllPlanes, XYPixmap);
3370 if (appData.debugMode)
3371 fprintf(stderr, _("(File:%s:) "), buf);
3372 loadXIM(ximPieceBitmap[kind][piece],
3374 &(xpmPieceBitmap2[kind][piece]),
3375 &(ximMaskPm2[piece]));
3376 if(piece <= (int)WhiteKing)
3377 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3379 fprintf(stderr," ");
3381 /* Load light and dark squares */
3382 /* If the LSQ and DSQ pieces don't exist, we will
3383 draw them with solid squares. */
3384 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3385 if (access(buf, 0) != 0) {
3389 fprintf(stderr, _("light square "));
3391 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3392 0, 0, ss, ss, AllPlanes, XYPixmap);
3393 if (appData.debugMode)
3394 fprintf(stderr, _("(File:%s:) "), buf);
3396 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3397 fprintf(stderr, _("dark square "));
3398 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3399 ExpandPathName(appData.pixmapDirectory), ss);
3400 if (appData.debugMode)
3401 fprintf(stderr, _("(File:%s:) "), buf);
3403 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3404 0, 0, ss, ss, AllPlanes, XYPixmap);
3405 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3406 xpmJailSquare = xpmLightSquare;
3408 fprintf(stderr, _("Done.\n"));
3410 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3414 void CreateXPMBoard(char *s, int kind)
3418 if(s == NULL || *s == 0 || *s == '*') { useTexture &= ~(kind+1); return; }
3419 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3420 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3424 void FreeXPMPieces()
3425 { // [HGM] to prevent resoucre leak on calling CreaeXPMPieces() a second time,
3426 // thisroutine has to be called t free the old piece pixmaps
3428 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++)
3429 for (kind=0; kind<4; kind++) XFreePixmap(xDisplay, xpmPieceBitmap2[kind][piece]);
3431 XFreePixmap(xDisplay, xpmLightSquare);
3432 XFreePixmap(xDisplay, xpmDarkSquare);
3436 void CreateXPMPieces()
3440 u_int ss = squareSize;
3442 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3443 XpmColorSymbol symbols[4];
3444 static int redo = False;
3446 if(redo) FreeXPMPieces(); else redo = 1;
3448 /* The XSynchronize calls were copied from CreatePieces.
3449 Not sure if needed, but can't hurt */
3450 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3452 /* Setup translations so piece colors match square colors */
3453 symbols[0].name = "light_piece";
3454 symbols[0].value = appData.whitePieceColor;
3455 symbols[1].name = "dark_piece";
3456 symbols[1].value = appData.blackPieceColor;
3457 symbols[2].name = "light_square";
3458 symbols[2].value = appData.lightSquareColor;
3459 symbols[3].name = "dark_square";
3460 symbols[3].value = appData.darkSquareColor;
3462 attr.valuemask = XpmColorSymbols;
3463 attr.colorsymbols = symbols;
3464 attr.numsymbols = 4;
3466 if (appData.monoMode) {
3467 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3471 if (strlen(appData.pixmapDirectory) == 0) {
3472 XpmPieces* pieces = builtInXpms;
3475 while (pieces->size != squareSize && pieces->size) pieces++;
3476 if (!pieces->size) {
3477 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3480 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3481 for (kind=0; kind<4; kind++) {
3483 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3484 pieces->xpm[piece][kind],
3485 &(xpmPieceBitmap2[kind][piece]),
3486 NULL, &attr)) != 0) {
3487 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3491 if(piece <= (int) WhiteKing)
3492 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3496 xpmJailSquare = xpmLightSquare;
3500 fprintf(stderr, _("\nLoading XPMs...\n"));
3503 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3504 fprintf(stderr, "%d ", piece+1);
3505 for (kind=0; kind<4; kind++) {
3506 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3507 ExpandPathName(appData.pixmapDirectory),
3508 piece > (int) WhiteKing ? "w" : "",
3509 pieceBitmapNames[piece],
3511 if (appData.debugMode) {
3512 fprintf(stderr, _("(File:%s:) "), buf);
3514 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3515 &(xpmPieceBitmap2[kind][piece]),
3516 NULL, &attr)) != 0) {
3517 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3518 // [HGM] missing: read of unorthodox piece failed; substitute King.
3519 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3520 ExpandPathName(appData.pixmapDirectory),
3522 if (appData.debugMode) {
3523 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3525 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3526 &(xpmPieceBitmap2[kind][piece]),
3530 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3535 if(piece <= (int) WhiteKing)
3536 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3539 /* Load light and dark squares */
3540 /* If the LSQ and DSQ pieces don't exist, we will
3541 draw them with solid squares. */
3542 fprintf(stderr, _("light square "));
3543 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3544 if (access(buf, 0) != 0) {
3548 if (appData.debugMode)
3549 fprintf(stderr, _("(File:%s:) "), buf);
3551 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3552 &xpmLightSquare, NULL, &attr)) != 0) {
3553 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3556 fprintf(stderr, _("dark square "));
3557 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3558 ExpandPathName(appData.pixmapDirectory), ss);
3559 if (appData.debugMode) {
3560 fprintf(stderr, _("(File:%s:) "), buf);
3562 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3563 &xpmDarkSquare, NULL, &attr)) != 0) {
3564 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3568 xpmJailSquare = xpmLightSquare;
3569 fprintf(stderr, _("Done.\n"));
3571 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3574 #endif /* HAVE_LIBXPM */
3577 /* No built-in bitmaps */
3582 u_int ss = squareSize;
3584 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3587 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3588 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3589 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3590 pieceBitmapNames[piece],
3591 ss, kind == SOLID ? 's' : 'o');
3592 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3593 if(piece <= (int)WhiteKing)
3594 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3598 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3602 /* With built-in bitmaps */
3605 BuiltInBits* bib = builtInBits;
3608 u_int ss = squareSize;
3610 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3613 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3615 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3616 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3617 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3618 pieceBitmapNames[piece],
3619 ss, kind == SOLID ? 's' : 'o');
3620 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3621 bib->bits[kind][piece], ss, ss);
3622 if(piece <= (int)WhiteKing)
3623 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3627 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3632 void ReadBitmap(pm, name, bits, wreq, hreq)
3635 unsigned char bits[];
3641 char msg[MSG_SIZ], fullname[MSG_SIZ];
3643 if (*appData.bitmapDirectory != NULLCHAR) {
3644 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3645 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3646 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3647 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3648 &w, &h, pm, &x_hot, &y_hot);
3649 fprintf(stderr, "load %s\n", name);
3650 if (errcode != BitmapSuccess) {
3652 case BitmapOpenFailed:
3653 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3655 case BitmapFileInvalid:
3656 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3658 case BitmapNoMemory:
3659 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3663 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3667 fprintf(stderr, _("%s: %s...using built-in\n"),
3669 } else if (w != wreq || h != hreq) {
3671 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3672 programName, fullname, w, h, wreq, hreq);
3678 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3687 if (lineGap == 0) return;
3689 /* [HR] Split this into 2 loops for non-square boards. */
3691 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3692 gridSegments[i].x1 = 0;
3693 gridSegments[i].x2 =
3694 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3695 gridSegments[i].y1 = gridSegments[i].y2
3696 = lineGap / 2 + (i * (squareSize + lineGap));
3699 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3700 gridSegments[j + i].y1 = 0;
3701 gridSegments[j + i].y2 =
3702 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3703 gridSegments[j + i].x1 = gridSegments[j + i].x2
3704 = lineGap / 2 + (j * (squareSize + lineGap));
3708 static void MenuBarSelect(w, addr, index)
3713 XtActionProc proc = (XtActionProc) addr;
3715 (proc)(NULL, NULL, NULL, NULL);
3718 void CreateMenuBarPopup(parent, name, mb)
3728 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3731 XtSetArg(args[j], XtNleftMargin, 20); j++;
3732 XtSetArg(args[j], XtNrightMargin, 20); j++;
3734 while (mi->string != NULL) {
3735 if (strcmp(mi->string, "----") == 0) {
3736 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3739 XtSetArg(args[j], XtNlabel, XtNewString(mi->string));
3740 entry = XtCreateManagedWidget(mi->ref, smeBSBObjectClass,
3742 XtAddCallback(entry, XtNcallback,
3743 (XtCallbackProc) MenuBarSelect,
3744 (caddr_t) mi->proc);
3750 Widget CreateMenuBar(mb)
3754 Widget anchor, menuBar;
3756 char menuName[MSG_SIZ];
3759 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3760 XtSetArg(args[j], XtNvSpace, 0); j++;
3761 XtSetArg(args[j], XtNborderWidth, 0); j++;
3762 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3763 formWidget, args, j);
3765 while (mb->name != NULL) {
3766 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3767 strncat(menuName, mb->ref, MSG_SIZ - strlen(menuName) - 1);
3769 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3772 shortName[0] = mb->name[0];
3773 shortName[1] = NULLCHAR;
3774 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3777 XtSetArg(args[j], XtNlabel, XtNewString(mb->name)); j++;
3780 XtSetArg(args[j], XtNborderWidth, 0); j++;
3781 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3783 CreateMenuBarPopup(menuBar, menuName, mb);
3789 Widget CreateButtonBar(mi)
3793 Widget button, buttonBar;
3797 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3799 XtSetArg(args[j], XtNhSpace, 0); j++;
3801 XtSetArg(args[j], XtNborderWidth, 0); j++;
3802 XtSetArg(args[j], XtNvSpace, 0); j++;
3803 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3804 formWidget, args, j);
3806 while (mi->string != NULL) {
3809 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3810 XtSetArg(args[j], XtNborderWidth, 0); j++;
3812 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3813 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3814 buttonBar, args, j);
3815 XtAddCallback(button, XtNcallback,
3816 (XtCallbackProc) MenuBarSelect,
3817 (caddr_t) mi->proc);
3824 CreatePieceMenu(name, color)
3831 ChessSquare selection;
3833 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3834 boardWidget, args, 0);
3836 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3837 String item = pieceMenuStrings[color][i];
3839 if (strcmp(item, "----") == 0) {
3840 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3843 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3844 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3846 selection = pieceMenuTranslation[color][i];
3847 XtAddCallback(entry, XtNcallback,
3848 (XtCallbackProc) PieceMenuSelect,
3849 (caddr_t) selection);
3850 if (selection == WhitePawn || selection == BlackPawn) {
3851 XtSetArg(args[0], XtNpopupOnEntry, entry);
3852 XtSetValues(menu, args, 1);
3865 ChessSquare selection;
3867 whitePieceMenu = CreatePieceMenu("menuW", 0);
3868 blackPieceMenu = CreatePieceMenu("menuB", 1);
3870 XtRegisterGrabAction(PieceMenuPopup, True,
3871 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3872 GrabModeAsync, GrabModeAsync);
3874 XtSetArg(args[0], XtNlabel, _("Drop"));
3875 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3876 boardWidget, args, 1);
3877 for (i = 0; i < DROP_MENU_SIZE; i++) {
3878 String item = dropMenuStrings[i];
3880 if (strcmp(item, "----") == 0) {
3881 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3884 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3885 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3887 selection = dropMenuTranslation[i];
3888 XtAddCallback(entry, XtNcallback,
3889 (XtCallbackProc) DropMenuSelect,
3890 (caddr_t) selection);
3895 void SetupDropMenu()
3903 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3904 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3905 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3906 dmEnables[i].piece);
3907 XtSetSensitive(entry, p != NULL || !appData.testLegality
3908 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3909 && !appData.icsActive));
3911 while (p && *p++ == dmEnables[i].piece) count++;
3912 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3914 XtSetArg(args[j], XtNlabel, label); j++;
3915 XtSetValues(entry, args, j);
3919 void PieceMenuPopup(w, event, params, num_params)
3923 Cardinal *num_params;
3925 String whichMenu; int menuNr;
3926 if (event->type == ButtonRelease)
3927 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3928 else if (event->type == ButtonPress)
3929 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3931 case 0: whichMenu = params[0]; break;
3932 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3934 case -1: if (errorUp) ErrorPopDown();
3937 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3940 static void PieceMenuSelect(w, piece, junk)
3945 if (pmFromX < 0 || pmFromY < 0) return;
3946 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3949 static void DropMenuSelect(w, piece, junk)
3954 if (pmFromX < 0 || pmFromY < 0) return;
3955 DropMenuEvent(piece, pmFromX, pmFromY);
3958 void WhiteClock(w, event, prms, nprms)
3967 void BlackClock(w, event, prms, nprms)
3978 * If the user selects on a border boundary, return -1; if off the board,
3979 * return -2. Otherwise map the event coordinate to the square.
3981 int EventToSquare(x, limit)
3989 if ((x % (squareSize + lineGap)) >= squareSize)
3991 x /= (squareSize + lineGap);
3997 static void do_flash_delay(msec)
4003 static void drawHighlight(file, rank, gc)
4009 if (lineGap == 0) return;
4012 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
4013 (squareSize + lineGap);
4014 y = lineGap/2 + rank * (squareSize + lineGap);
4016 x = lineGap/2 + file * (squareSize + lineGap);
4017 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
4018 (squareSize + lineGap);
4021 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
4022 squareSize+lineGap, squareSize+lineGap);
4025 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
4026 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4029 SetHighlights(fromX, fromY, toX, toY)
4030 int fromX, fromY, toX, toY;
4032 if (hi1X != fromX || hi1Y != fromY) {
4033 if (hi1X >= 0 && hi1Y >= 0) {
4034 drawHighlight(hi1X, hi1Y, lineGC);
4036 } // [HGM] first erase both, then draw new!
4037 if (hi2X != toX || hi2Y != toY) {
4038 if (hi2X >= 0 && hi2Y >= 0) {
4039 drawHighlight(hi2X, hi2Y, lineGC);
4042 if (hi1X != fromX || hi1Y != fromY) {
4043 if (fromX >= 0 && fromY >= 0) {
4044 drawHighlight(fromX, fromY, highlineGC);
4047 if (hi2X != toX || hi2Y != toY) {
4048 if (toX >= 0 && toY >= 0) {
4049 drawHighlight(toX, toY, highlineGC);
4061 SetHighlights(-1, -1, -1, -1);
4066 SetPremoveHighlights(fromX, fromY, toX, toY)
4067 int fromX, fromY, toX, toY;
4069 if (pm1X != fromX || pm1Y != fromY) {
4070 if (pm1X >= 0 && pm1Y >= 0) {
4071 drawHighlight(pm1X, pm1Y, lineGC);
4073 if (fromX >= 0 && fromY >= 0) {
4074 drawHighlight(fromX, fromY, prelineGC);
4077 if (pm2X != toX || pm2Y != toY) {
4078 if (pm2X >= 0 && pm2Y >= 0) {
4079 drawHighlight(pm2X, pm2Y, lineGC);
4081 if (toX >= 0 && toY >= 0) {
4082 drawHighlight(toX, toY, prelineGC);
4092 ClearPremoveHighlights()
4094 SetPremoveHighlights(-1, -1, -1, -1);
4097 static int CutOutSquare(x, y, x0, y0, kind)
4098 int x, y, *x0, *y0, kind;
4100 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
4101 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
4103 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
4104 if(textureW[kind] < W*squareSize)
4105 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
4107 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
4108 if(textureH[kind] < H*squareSize)
4109 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
4111 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
4115 static void BlankSquare(x, y, color, piece, dest, fac)
4116 int x, y, color, fac;
4119 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
4121 if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
4122 XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
4123 squareSize, squareSize, x*fac, y*fac);
4125 if (useImages && useImageSqs) {
4129 pm = xpmLightSquare;
4134 case 2: /* neutral */
4139 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4140 squareSize, squareSize, x*fac, y*fac);
4150 case 2: /* neutral */
4155 XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
4160 I split out the routines to draw a piece so that I could
4161 make a generic flash routine.
4163 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4165 int square_color, x, y;
4168 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4169 switch (square_color) {
4171 case 2: /* neutral */
4173 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4174 ? *pieceToOutline(piece)
4175 : *pieceToSolid(piece),
4176 dest, bwPieceGC, 0, 0,
4177 squareSize, squareSize, x, y);
4180 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4181 ? *pieceToSolid(piece)
4182 : *pieceToOutline(piece),
4183 dest, wbPieceGC, 0, 0,
4184 squareSize, squareSize, x, y);
4189 static void monoDrawPiece(piece, square_color, x, y, dest)
4191 int square_color, x, y;
4194 switch (square_color) {
4196 case 2: /* neutral */
4198 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4199 ? *pieceToOutline(piece)
4200 : *pieceToSolid(piece),
4201 dest, bwPieceGC, 0, 0,
4202 squareSize, squareSize, x, y, 1);
4205 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4206 ? *pieceToSolid(piece)
4207 : *pieceToOutline(piece),
4208 dest, wbPieceGC, 0, 0,
4209 squareSize, squareSize, x, y, 1);
4214 static void colorDrawPiece(piece, square_color, x, y, dest)
4216 int square_color, x, y;
4219 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4220 switch (square_color) {
4222 XCopyPlane(xDisplay, *pieceToSolid(piece),
4223 dest, (int) piece < (int) BlackPawn
4224 ? wlPieceGC : blPieceGC, 0, 0,
4225 squareSize, squareSize, x, y, 1);
4228 XCopyPlane(xDisplay, *pieceToSolid(piece),
4229 dest, (int) piece < (int) BlackPawn
4230 ? wdPieceGC : bdPieceGC, 0, 0,
4231 squareSize, squareSize, x, y, 1);
4233 case 2: /* neutral */
4235 XCopyPlane(xDisplay, *pieceToSolid(piece),
4236 dest, (int) piece < (int) BlackPawn
4237 ? wjPieceGC : bjPieceGC, 0, 0,
4238 squareSize, squareSize, x, y, 1);
4243 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4245 int square_color, x, y;
4248 int kind, p = piece;
4250 switch (square_color) {
4252 case 2: /* neutral */
4254 if ((int)piece < (int) BlackPawn) {
4262 if ((int)piece < (int) BlackPawn) {
4270 if(appData.upsideDown && flipView) { kind ^= 2; p += p < BlackPawn ? BlackPawn : -BlackPawn; }// swap white and black pieces
4271 if(useTexture & square_color+1) {
4272 BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
4273 XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
4274 XSetClipOrigin(xDisplay, wlPieceGC, x, y);
4275 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);
4276 XSetClipMask(xDisplay, wlPieceGC, None);
4277 XSetClipOrigin(xDisplay, wlPieceGC, 0, 0);
4279 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4280 dest, wlPieceGC, 0, 0,
4281 squareSize, squareSize, x, y);
4284 typedef void (*DrawFunc)();
4286 DrawFunc ChooseDrawFunc()
4288 if (appData.monoMode) {
4289 if (DefaultDepth(xDisplay, xScreen) == 1) {
4290 return monoDrawPiece_1bit;
4292 return monoDrawPiece;
4296 return colorDrawPieceImage;
4298 return colorDrawPiece;
4302 /* [HR] determine square color depending on chess variant. */
4303 static int SquareColor(row, column)
4308 if (gameInfo.variant == VariantXiangqi) {
4309 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4311 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4313 } else if (row <= 4) {
4319 square_color = ((column + row) % 2) == 1;
4322 /* [hgm] holdings: next line makes all holdings squares light */
4323 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4325 return square_color;
4328 void DrawSquare(row, column, piece, do_flash)
4329 int row, column, do_flash;
4332 int square_color, x, y, direction, font_ascent, font_descent;
4335 XCharStruct overall;
4339 /* Calculate delay in milliseconds (2-delays per complete flash) */
4340 flash_delay = 500 / appData.flashRate;
4343 x = lineGap + ((BOARD_WIDTH-1)-column) *
4344 (squareSize + lineGap);
4345 y = lineGap + row * (squareSize + lineGap);
4347 x = lineGap + column * (squareSize + lineGap);
4348 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4349 (squareSize + lineGap);
4352 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4354 square_color = SquareColor(row, column);
4356 if ( // [HGM] holdings: blank out area between board and holdings
4357 column == BOARD_LEFT-1 || column == BOARD_RGHT
4358 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4359 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4360 BlankSquare(x, y, 2, EmptySquare, xBoardWindow, 1);
4362 // [HGM] print piece counts next to holdings
4363 string[1] = NULLCHAR;
4364 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4365 string[0] = '0' + piece;
4366 XTextExtents(countFontStruct, string, 1, &direction,
4367 &font_ascent, &font_descent, &overall);
4368 if (appData.monoMode) {
4369 XDrawImageString(xDisplay, xBoardWindow, countGC,
4370 x + squareSize - overall.width - 2,
4371 y + font_ascent + 1, string, 1);
4373 XDrawString(xDisplay, xBoardWindow, countGC,
4374 x + squareSize - overall.width - 2,
4375 y + font_ascent + 1, string, 1);
4378 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4379 string[0] = '0' + piece;
4380 XTextExtents(countFontStruct, string, 1, &direction,
4381 &font_ascent, &font_descent, &overall);
4382 if (appData.monoMode) {
4383 XDrawImageString(xDisplay, xBoardWindow, countGC,
4384 x + 2, y + font_ascent + 1, string, 1);
4386 XDrawString(xDisplay, xBoardWindow, countGC,
4387 x + 2, y + font_ascent + 1, string, 1);
4391 if (piece == EmptySquare || appData.blindfold) {
4392 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4394 drawfunc = ChooseDrawFunc();
4395 if (do_flash && appData.flashCount > 0) {
4396 for (i=0; i<appData.flashCount; ++i) {
4398 drawfunc(piece, square_color, x, y, xBoardWindow);
4399 XSync(xDisplay, False);
4400 do_flash_delay(flash_delay);
4402 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4403 XSync(xDisplay, False);
4404 do_flash_delay(flash_delay);
4407 drawfunc(piece, square_color, x, y, xBoardWindow);
4411 string[1] = NULLCHAR;
4412 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4413 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4414 string[0] = 'a' + column - BOARD_LEFT;
4415 XTextExtents(coordFontStruct, string, 1, &direction,
4416 &font_ascent, &font_descent, &overall);
4417 if (appData.monoMode) {
4418 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4419 x + squareSize - overall.width - 2,
4420 y + squareSize - font_descent - 1, string, 1);
4422 XDrawString(xDisplay, xBoardWindow, coordGC,
4423 x + squareSize - overall.width - 2,
4424 y + squareSize - font_descent - 1, string, 1);
4427 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4428 string[0] = ONE + row;
4429 XTextExtents(coordFontStruct, string, 1, &direction,
4430 &font_ascent, &font_descent, &overall);
4431 if (appData.monoMode) {
4432 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4433 x + 2, y + font_ascent + 1, string, 1);
4435 XDrawString(xDisplay, xBoardWindow, coordGC,
4436 x + 2, y + font_ascent + 1, string, 1);
4439 if(!partnerUp && marker[row][column]) {
4440 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4441 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4446 /* Why is this needed on some versions of X? */
4447 void EventProc(widget, unused, event)
4452 if (!XtIsRealized(widget))
4455 switch (event->type) {
4457 if (event->xexpose.count > 0) return; /* no clipping is done */
4458 XDrawPosition(widget, True, NULL);
4459 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4460 flipView = !flipView; partnerUp = !partnerUp;
4461 XDrawPosition(widget, True, NULL);
4462 flipView = !flipView; partnerUp = !partnerUp;
4466 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
4473 void DrawPosition(fullRedraw, board)
4474 /*Boolean*/int fullRedraw;
4477 XDrawPosition(boardWidget, fullRedraw, board);
4480 /* Returns 1 if there are "too many" differences between b1 and b2
4481 (i.e. more than 1 move was made) */
4482 static int too_many_diffs(b1, b2)
4488 for (i=0; i<BOARD_HEIGHT; ++i) {
4489 for (j=0; j<BOARD_WIDTH; ++j) {
4490 if (b1[i][j] != b2[i][j]) {
4491 if (++c > 4) /* Castling causes 4 diffs */
4500 /* Matrix describing castling maneuvers */
4501 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4502 static int castling_matrix[4][5] = {
4503 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4504 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4505 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4506 { 7, 7, 4, 5, 6 } /* 0-0, black */
4509 /* Checks whether castling occurred. If it did, *rrow and *rcol
4510 are set to the destination (row,col) of the rook that moved.
4512 Returns 1 if castling occurred, 0 if not.
4514 Note: Only handles a max of 1 castling move, so be sure
4515 to call too_many_diffs() first.
4517 static int check_castle_draw(newb, oldb, rrow, rcol)
4524 /* For each type of castling... */
4525 for (i=0; i<4; ++i) {
4526 r = castling_matrix[i];
4528 /* Check the 4 squares involved in the castling move */
4530 for (j=1; j<=4; ++j) {
4531 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4538 /* All 4 changed, so it must be a castling move */
4547 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4548 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4550 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4553 void DrawSeekBackground( int left, int top, int right, int bottom )
4555 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4558 void DrawSeekText(char *buf, int x, int y)
4560 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4563 void DrawSeekDot(int x, int y, int colorNr)
4565 int square = colorNr & 0x80;
4568 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4570 XFillRectangle(xDisplay, xBoardWindow, color,
4571 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4573 XFillArc(xDisplay, xBoardWindow, color,
4574 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4577 static int damage[2][BOARD_RANKS][BOARD_FILES];
4580 * event handler for redrawing the board
4582 void XDrawPosition(w, repaint, board)
4584 /*Boolean*/int repaint;
4588 static int lastFlipView = 0;
4589 static int lastBoardValid[2] = {0, 0};
4590 static Board lastBoard[2];
4593 int nr = twoBoards*partnerUp;
4595 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4597 if (board == NULL) {
4598 if (!lastBoardValid[nr]) return;
4599 board = lastBoard[nr];
4601 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4602 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4603 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Flip View"),
4608 * It would be simpler to clear the window with XClearWindow()
4609 * but this causes a very distracting flicker.
4612 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4614 if ( lineGap && IsDrawArrowEnabled())
4615 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4616 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4618 /* If too much changes (begin observing new game, etc.), don't
4620 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4622 /* Special check for castling so we don't flash both the king
4623 and the rook (just flash the king). */
4625 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4626 /* Draw rook with NO flashing. King will be drawn flashing later */
4627 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4628 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4632 /* First pass -- Draw (newly) empty squares and repair damage.
4633 This prevents you from having a piece show up twice while it
4634 is flashing on its new square */
4635 for (i = 0; i < BOARD_HEIGHT; i++)
4636 for (j = 0; j < BOARD_WIDTH; j++)
4637 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4638 || damage[nr][i][j]) {
4639 DrawSquare(i, j, board[i][j], 0);
4640 damage[nr][i][j] = False;
4643 /* Second pass -- Draw piece(s) in new position and flash them */
4644 for (i = 0; i < BOARD_HEIGHT; i++)
4645 for (j = 0; j < BOARD_WIDTH; j++)
4646 if (board[i][j] != lastBoard[nr][i][j]) {
4647 DrawSquare(i, j, board[i][j], do_flash);
4651 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4652 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4653 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4655 for (i = 0; i < BOARD_HEIGHT; i++)
4656 for (j = 0; j < BOARD_WIDTH; j++) {
4657 DrawSquare(i, j, board[i][j], 0);
4658 damage[nr][i][j] = False;
4662 CopyBoard(lastBoard[nr], board);
4663 lastBoardValid[nr] = 1;
4664 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4665 lastFlipView = flipView;
4667 /* Draw highlights */
4668 if (pm1X >= 0 && pm1Y >= 0) {
4669 drawHighlight(pm1X, pm1Y, prelineGC);
4671 if (pm2X >= 0 && pm2Y >= 0) {
4672 drawHighlight(pm2X, pm2Y, prelineGC);
4674 if (hi1X >= 0 && hi1Y >= 0) {
4675 drawHighlight(hi1X, hi1Y, highlineGC);
4677 if (hi2X >= 0 && hi2Y >= 0) {
4678 drawHighlight(hi2X, hi2Y, highlineGC);
4680 DrawArrowHighlight(hi1X, hi1Y, hi2X, hi2Y);
4682 /* If piece being dragged around board, must redraw that too */
4685 XSync(xDisplay, False);
4690 * event handler for redrawing the board
4692 void DrawPositionProc(w, event, prms, nprms)
4698 XDrawPosition(w, True, NULL);
4703 * event handler for parsing user moves
4705 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4706 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4707 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4708 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4709 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4710 // and at the end FinishMove() to perform the move after optional promotion popups.
4711 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4712 void HandleUserMove(w, event, prms, nprms)
4718 if (w != boardWidget || errorExitStatus != -1) return;
4719 if(nprms) shiftKey = !strcmp(prms[0], "1");
4722 if (event->type == ButtonPress) {
4723 XtPopdown(promotionShell);
4724 XtDestroyWidget(promotionShell);
4725 promotionUp = False;
4733 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4734 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4735 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4738 void AnimateUserMove (Widget w, XEvent * event,
4739 String * params, Cardinal * nParams)
4741 DragPieceMove(event->xmotion.x, event->xmotion.y);
4744 void HandlePV (Widget w, XEvent * event,
4745 String * params, Cardinal * nParams)
4746 { // [HGM] pv: walk PV
4747 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4750 Widget CommentCreate(name, text, mutable, callback, lines)
4752 int /*Boolean*/ mutable;
4753 XtCallbackProc callback;
4757 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4762 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4763 XtGetValues(boardWidget, args, j);
4766 XtSetArg(args[j], XtNresizable, True); j++;
4769 XtCreatePopupShell(name, topLevelShellWidgetClass,
4770 shellWidget, args, j);
4773 XtCreatePopupShell(name, transientShellWidgetClass,
4774 shellWidget, args, j);
4777 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4778 layoutArgs, XtNumber(layoutArgs));
4780 XtCreateManagedWidget("form", formWidgetClass, layout,
4781 formArgs, XtNumber(formArgs));
4785 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4786 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4788 XtSetArg(args[j], XtNstring, text); j++;
4789 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4790 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4791 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4792 XtSetArg(args[j], XtNright, XtChainRight); j++;
4793 XtSetArg(args[j], XtNresizable, True); j++;
4794 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4795 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4796 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4797 XtSetArg(args[j], XtNautoFill, True); j++;
4798 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4800 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4801 XtOverrideTranslations(edit, XtParseTranslationTable(commentTranslations));
4805 XtSetArg(args[j], XtNfromVert, edit); j++;
4806 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4807 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4808 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4809 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4811 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4812 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4815 XtSetArg(args[j], XtNfromVert, edit); j++;
4816 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4817 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4818 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4819 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4820 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4822 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4823 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4826 XtSetArg(args[j], XtNfromVert, edit); j++;
4827 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4828 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4829 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4830 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4831 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4833 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4834 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4837 XtSetArg(args[j], XtNfromVert, edit); j++;
4838 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4839 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4840 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4841 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4843 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4844 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4847 XtSetArg(args[j], XtNfromVert, edit); j++;
4848 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4849 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4850 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4851 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4852 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4854 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4855 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4858 XtRealizeWidget(shell);
4860 if (commentX == -1) {
4863 Dimension pw_height;
4864 Dimension ew_height;
4867 XtSetArg(args[j], XtNheight, &ew_height); j++;
4868 XtGetValues(edit, args, j);
4871 XtSetArg(args[j], XtNheight, &pw_height); j++;
4872 XtGetValues(shell, args, j);
4873 commentH = pw_height + (lines - 1) * ew_height;
4874 commentW = bw_width - 16;
4876 XSync(xDisplay, False);
4878 /* This code seems to tickle an X bug if it is executed too soon
4879 after xboard starts up. The coordinates get transformed as if
4880 the main window was positioned at (0, 0).
4882 XtTranslateCoords(shellWidget,
4883 (bw_width - commentW) / 2, 0 - commentH / 2,
4884 &commentX, &commentY);
4886 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4887 RootWindowOfScreen(XtScreen(shellWidget)),
4888 (bw_width - commentW) / 2, 0 - commentH / 2,
4893 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4896 if(wpComment.width > 0) {
4897 commentX = wpComment.x;
4898 commentY = wpComment.y;
4899 commentW = wpComment.width;
4900 commentH = wpComment.height;
4904 XtSetArg(args[j], XtNheight, commentH); j++;
4905 XtSetArg(args[j], XtNwidth, commentW); j++;
4906 XtSetArg(args[j], XtNx, commentX); j++;
4907 XtSetArg(args[j], XtNy, commentY); j++;
4908 XtSetValues(shell, args, j);
4909 XtSetKeyboardFocus(shell, edit);
4914 /* Used for analysis window and ICS input window */
4915 Widget MiscCreate(name, text, mutable, callback, lines)
4917 int /*Boolean*/ mutable;
4918 XtCallbackProc callback;
4922 Widget shell, layout, form, edit;
4924 Dimension bw_width, pw_height, ew_height, w, h;
4930 XtSetArg(args[j], XtNresizable, True); j++;
4933 XtCreatePopupShell(name, topLevelShellWidgetClass,
4934 shellWidget, args, j);
4937 XtCreatePopupShell(name, transientShellWidgetClass,
4938 shellWidget, args, j);
4941 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4942 layoutArgs, XtNumber(layoutArgs));
4944 XtCreateManagedWidget("form", formWidgetClass, layout,
4945 formArgs, XtNumber(formArgs));
4949 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4950 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4952 XtSetArg(args[j], XtNstring, text); j++;
4953 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4954 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4955 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4956 XtSetArg(args[j], XtNright, XtChainRight); j++;
4957 XtSetArg(args[j], XtNresizable, True); j++;
4958 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4959 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4960 XtSetArg(args[j], XtNautoFill, True); j++;
4961 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4963 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4965 XtRealizeWidget(shell);
4968 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4969 XtGetValues(boardWidget, args, j);
4972 XtSetArg(args[j], XtNheight, &ew_height); j++;
4973 XtGetValues(edit, args, j);
4976 XtSetArg(args[j], XtNheight, &pw_height); j++;
4977 XtGetValues(shell, args, j);
4978 h = pw_height + (lines - 1) * ew_height;
4981 XSync(xDisplay, False);
4983 /* This code seems to tickle an X bug if it is executed too soon
4984 after xboard starts up. The coordinates get transformed as if
4985 the main window was positioned at (0, 0).
4987 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4989 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4990 RootWindowOfScreen(XtScreen(shellWidget)),
4991 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4995 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4998 XtSetArg(args[j], XtNheight, h); j++;
4999 XtSetArg(args[j], XtNwidth, w); j++;
5000 XtSetArg(args[j], XtNx, x); j++;
5001 XtSetArg(args[j], XtNy, y); j++;
5002 XtSetValues(shell, args, j);
5008 static int savedIndex; /* gross that this is global */
5010 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
5013 XawTextPosition index, dummy;
5016 XawTextGetSelectionPos(w, &index, &dummy);
5017 XtSetArg(arg, XtNstring, &val);
5018 XtGetValues(w, &arg, 1);
5019 ReplaceComment(savedIndex, val);
5020 if(savedIndex != currentMove) ToNrEvent(savedIndex);
5021 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
5024 void EditCommentPopUp(index, title, text)
5033 if (text == NULL) text = "";
5035 if (editShell == NULL) {
5037 CommentCreate(title, text, True, EditCommentCallback, 4);
5038 XtRealizeWidget(editShell);
5039 CatchDeleteWindow(editShell, "EditCommentPopDown");
5041 edit = XtNameToWidget(editShell, "*form.text");
5043 XtSetArg(args[j], XtNstring, text); j++;
5044 XtSetValues(edit, args, j);
5046 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5047 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5048 XtSetValues(editShell, args, j);
5051 XtPopup(editShell, XtGrabNone);
5055 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5056 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"),
5058 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"),
5062 void EditCommentCallback(w, client_data, call_data)
5064 XtPointer client_data, call_data;
5072 XtSetArg(args[j], XtNlabel, &name); j++;
5073 XtGetValues(w, args, j);
5075 if (strcmp(name, _("ok")) == 0) {
5076 edit = XtNameToWidget(editShell, "*form.text");
5078 XtSetArg(args[j], XtNstring, &val); j++;
5079 XtGetValues(edit, args, j);
5080 ReplaceComment(savedIndex, val);
5081 EditCommentPopDown();
5082 } else if (strcmp(name, _("cancel")) == 0) {
5083 EditCommentPopDown();
5084 } else if (strcmp(name, _("clear")) == 0) {
5085 edit = XtNameToWidget(editShell, "*form.text");
5086 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5087 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5091 void EditCommentPopDown()
5096 if (!editUp) return;
5098 XtSetArg(args[j], XtNx, &commentX); j++;
5099 XtSetArg(args[j], XtNy, &commentY); j++;
5100 XtSetArg(args[j], XtNheight, &commentH); j++;
5101 XtSetArg(args[j], XtNwidth, &commentW); j++;
5102 XtGetValues(editShell, args, j);
5103 XtPopdown(editShell);
5106 XtSetArg(args[j], XtNleftBitmap, None); j++;
5107 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"),
5109 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"),
5113 void ICSInputBoxPopUp()
5118 char *title = _("ICS Input");
5121 if (ICSInputShell == NULL) {
5122 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
5123 tr = XtParseTranslationTable(ICSInputTranslations);
5124 edit = XtNameToWidget(ICSInputShell, "*form.text");
5125 XtOverrideTranslations(edit, tr);
5126 XtRealizeWidget(ICSInputShell);
5127 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
5130 edit = XtNameToWidget(ICSInputShell, "*form.text");
5132 XtSetArg(args[j], XtNstring, ""); j++;
5133 XtSetValues(edit, args, j);
5135 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5136 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5137 XtSetValues(ICSInputShell, args, j);
5140 XtPopup(ICSInputShell, XtGrabNone);
5141 XtSetKeyboardFocus(ICSInputShell, edit);
5143 ICSInputBoxUp = True;
5145 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5146 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.ICS Input Box"),
5150 void ICSInputSendText()
5157 edit = XtNameToWidget(ICSInputShell, "*form.text");
5159 XtSetArg(args[j], XtNstring, &val); j++;
5160 XtGetValues(edit, args, j);
5162 SendMultiLineToICS(val);
5163 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5164 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5167 void ICSInputBoxPopDown()
5172 if (!ICSInputBoxUp) return;
5174 XtPopdown(ICSInputShell);
5175 ICSInputBoxUp = False;
5177 XtSetArg(args[j], XtNleftBitmap, None); j++;
5178 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.ICS Input Box"),
5182 void CommentPopUp(title, text)
5189 savedIndex = currentMove; // [HGM] vari
5190 if (commentShell == NULL) {
5192 CommentCreate(title, text, False, CommentCallback, 4);
5193 XtRealizeWidget(commentShell);
5194 CatchDeleteWindow(commentShell, "CommentPopDown");
5196 edit = XtNameToWidget(commentShell, "*form.text");
5198 XtSetArg(args[j], XtNstring, text); j++;
5199 XtSetValues(edit, args, j);
5201 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5202 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5203 XtSetValues(commentShell, args, j);
5206 XtPopup(commentShell, XtGrabNone);
5207 XSync(xDisplay, False);
5212 void CommentCallback(w, client_data, call_data)
5214 XtPointer client_data, call_data;
5221 XtSetArg(args[j], XtNlabel, &name); j++;
5222 XtGetValues(w, args, j);
5224 if (strcmp(name, _("close")) == 0) {
5226 } else if (strcmp(name, _("edit")) == 0) {
5233 void CommentPopDown()
5238 if (!commentUp) return;
5240 XtSetArg(args[j], XtNx, &commentX); j++;
5241 XtSetArg(args[j], XtNy, &commentY); j++;
5242 XtSetArg(args[j], XtNwidth, &commentW); j++;
5243 XtSetArg(args[j], XtNheight, &commentH); j++;
5244 XtGetValues(commentShell, args, j);
5245 XtPopdown(commentShell);
5246 XSync(xDisplay, False);
5250 void FileNamePopUp(label, def, proc, openMode)
5256 fileProc = proc; /* I can't see a way not */
5257 fileOpenMode = openMode; /* to use globals here */
5258 { // [HGM] use file-selector dialog stolen from Ghostview
5260 int index; // this is not supported yet
5262 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5263 def, openMode, NULL, &name))
5264 (void) (*fileProc)(f, index=0, name);
5268 void FileNamePopDown()
5270 if (!filenameUp) return;
5271 XtPopdown(fileNameShell);
5272 XtDestroyWidget(fileNameShell);
5277 void FileNameCallback(w, client_data, call_data)
5279 XtPointer client_data, call_data;
5284 XtSetArg(args[0], XtNlabel, &name);
5285 XtGetValues(w, args, 1);
5287 if (strcmp(name, _("cancel")) == 0) {
5292 FileNameAction(w, NULL, NULL, NULL);
5295 void FileNameAction(w, event, prms, nprms)
5307 name = XawDialogGetValueString(w = XtParent(w));
5309 if ((name != NULL) && (*name != NULLCHAR)) {
5310 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
5311 XtPopdown(w = XtParent(XtParent(w)));
5315 p = strrchr(buf, ' ');
5322 fullname = ExpandPathName(buf);
5324 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5327 f = fopen(fullname, fileOpenMode);
5329 DisplayError(_("Failed to open file"), errno);
5331 (void) (*fileProc)(f, index, buf);
5338 XtPopdown(w = XtParent(XtParent(w)));
5344 void PromotionPopUp()
5347 Widget dialog, layout;
5349 Dimension bw_width, pw_width;
5353 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5354 XtGetValues(boardWidget, args, j);
5357 XtSetArg(args[j], XtNresizable, True); j++;
5358 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5360 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5361 shellWidget, args, j);
5363 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5364 layoutArgs, XtNumber(layoutArgs));
5367 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5368 XtSetArg(args[j], XtNborderWidth, 0); j++;
5369 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5372 if(gameInfo.variant != VariantShogi) {
5373 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) {
5374 XawDialogAddButton(dialog, _("Warlord"), PromotionCallback,
5375 (XtPointer) dialog);
5376 XawDialogAddButton(dialog, _("General"), PromotionCallback,
5377 (XtPointer) dialog);
5378 XawDialogAddButton(dialog, _("Lieutenant"), PromotionCallback,
5379 (XtPointer) dialog);
5380 XawDialogAddButton(dialog, _("Captain"), PromotionCallback,
5381 (XtPointer) dialog);
5383 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5384 (XtPointer) dialog);
5385 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5386 (XtPointer) dialog);
5387 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5388 (XtPointer) dialog);
5389 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5390 (XtPointer) dialog);
5392 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5393 gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
\r
5394 gameInfo.variant == VariantGiveaway) {
5395 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5396 (XtPointer) dialog);
5398 if(gameInfo.variant == VariantCapablanca ||
5399 gameInfo.variant == VariantGothic ||
5400 gameInfo.variant == VariantCapaRandom) {
5401 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5402 (XtPointer) dialog);
5403 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5404 (XtPointer) dialog);
5406 } else // [HGM] shogi
5408 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5409 (XtPointer) dialog);
5410 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5411 (XtPointer) dialog);
5413 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5414 (XtPointer) dialog);
5416 XtRealizeWidget(promotionShell);
5417 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5420 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5421 XtGetValues(promotionShell, args, j);
5423 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5424 lineGap + squareSize/3 +
5425 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5426 0 : 6*(squareSize + lineGap)), &x, &y);
5429 XtSetArg(args[j], XtNx, x); j++;
5430 XtSetArg(args[j], XtNy, y); j++;
5431 XtSetValues(promotionShell, args, j);
5433 XtPopup(promotionShell, XtGrabNone);
5438 void PromotionPopDown()
5440 if (!promotionUp) return;
5441 XtPopdown(promotionShell);
5442 XtDestroyWidget(promotionShell);
5443 promotionUp = False;
5446 void PromotionCallback(w, client_data, call_data)
5448 XtPointer client_data, call_data;
5454 XtSetArg(args[0], XtNlabel, &name);
5455 XtGetValues(w, args, 1);
5459 if (fromX == -1) return;
5461 if (strcmp(name, _("cancel")) == 0) {
5465 } else if (strcmp(name, _("Knight")) == 0) {
5467 } else if (strcmp(name, _("Promote")) == 0) {
5469 } else if (strcmp(name, _("Defer")) == 0) {
5472 promoChar = ToLower(name[0]);
5475 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5477 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5478 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5483 void ErrorCallback(w, client_data, call_data)
5485 XtPointer client_data, call_data;
5488 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5490 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5496 if (!errorUp) return;
5498 XtPopdown(errorShell);
5499 XtDestroyWidget(errorShell);
5500 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5503 void ErrorPopUp(title, label, modal)
5504 char *title, *label;
5508 Widget dialog, layout;
5512 Dimension bw_width, pw_width;
5513 Dimension pw_height;
5517 XtSetArg(args[i], XtNresizable, True); i++;
5518 XtSetArg(args[i], XtNtitle, title); i++;
5520 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5521 shellWidget, args, i);
5523 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5524 layoutArgs, XtNumber(layoutArgs));
5527 XtSetArg(args[i], XtNlabel, label); i++;
5528 XtSetArg(args[i], XtNborderWidth, 0); i++;
5529 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5532 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5534 XtRealizeWidget(errorShell);
5535 CatchDeleteWindow(errorShell, "ErrorPopDown");
5538 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5539 XtGetValues(boardWidget, args, i);
5541 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5542 XtSetArg(args[i], XtNheight, &pw_height); i++;
5543 XtGetValues(errorShell, args, i);
5546 /* This code seems to tickle an X bug if it is executed too soon
5547 after xboard starts up. The coordinates get transformed as if
5548 the main window was positioned at (0, 0).
5550 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5551 0 - pw_height + squareSize / 3, &x, &y);
5553 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5554 RootWindowOfScreen(XtScreen(boardWidget)),
5555 (bw_width - pw_width) / 2,
5556 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5560 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5563 XtSetArg(args[i], XtNx, x); i++;
5564 XtSetArg(args[i], XtNy, y); i++;
5565 XtSetValues(errorShell, args, i);
5568 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5571 /* Disable all user input other than deleting the window */
5572 static int frozen = 0;
5576 /* Grab by a widget that doesn't accept input */
5577 XtAddGrab(messageWidget, TRUE, FALSE);
5581 /* Undo a FreezeUI */
5584 if (!frozen) return;
5585 XtRemoveGrab(messageWidget);
5589 char *ModeToWidgetName(mode)
5593 case BeginningOfGame:
5594 if (appData.icsActive)
5595 return "menuMode.ICS Client";
5596 else if (appData.noChessProgram ||
5597 *appData.cmailGameName != NULLCHAR)
5598 return "menuMode.Edit Game";
5600 return "menuMode.Machine Black";
5601 case MachinePlaysBlack:
5602 return "menuMode.Machine Black";
5603 case MachinePlaysWhite:
5604 return "menuMode.Machine White";
5606 return "menuMode.Analysis Mode";
5608 return "menuMode.Analyze File";
5609 case TwoMachinesPlay:
5610 return "menuMode.Two Machines";
5612 return "menuMode.Edit Game";
5613 case PlayFromGameFile:
5614 return "menuFile.Load Game";
5616 return "menuMode.Edit Position";
5618 return "menuMode.Training";
5619 case IcsPlayingWhite:
5620 case IcsPlayingBlack:
5624 return "menuMode.ICS Client";
5631 void ModeHighlight()
5634 static int oldPausing = FALSE;
5635 static GameMode oldmode = (GameMode) -1;
5638 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5640 if (pausing != oldPausing) {
5641 oldPausing = pausing;
5643 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5645 XtSetArg(args[0], XtNleftBitmap, None);
5647 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5650 if (appData.showButtonBar) {
5651 /* Always toggle, don't set. Previous code messes up when
5652 invoked while the button is pressed, as releasing it
5653 toggles the state again. */
5656 XtSetArg(args[0], XtNbackground, &oldbg);
5657 XtSetArg(args[1], XtNforeground, &oldfg);
5658 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5660 XtSetArg(args[0], XtNbackground, oldfg);
5661 XtSetArg(args[1], XtNforeground, oldbg);
5663 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5667 wname = ModeToWidgetName(oldmode);
5668 if (wname != NULL) {
5669 XtSetArg(args[0], XtNleftBitmap, None);
5670 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5672 wname = ModeToWidgetName(gameMode);
5673 if (wname != NULL) {
5674 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5675 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5679 /* Maybe all the enables should be handled here, not just this one */
5680 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5681 gameMode == Training || gameMode == PlayFromGameFile);
5686 * Button/menu procedures
5688 void ResetProc(w, event, prms, nprms)
5697 int LoadGamePopUp(f, gameNumber, title)
5702 cmailMsgLoaded = FALSE;
5703 if (gameNumber == 0) {
5704 int error = GameListBuild(f);
5706 DisplayError(_("Cannot build game list"), error);
5707 } else if (!ListEmpty(&gameList) &&
5708 ((ListGame *) gameList.tailPred)->number > 1) {
5709 GameListPopUp(f, title);
5715 return LoadGame(f, gameNumber, title, FALSE);
5718 void LoadGameProc(w, event, prms, nprms)
5724 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5727 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5730 void LoadNextGameProc(w, event, prms, nprms)
5739 void LoadPrevGameProc(w, event, prms, nprms)
5748 void ReloadGameProc(w, event, prms, nprms)
5757 void LoadNextPositionProc(w, event, prms, nprms)
5766 void LoadPrevPositionProc(w, event, prms, nprms)
5775 void ReloadPositionProc(w, event, prms, nprms)
5784 void LoadPositionProc(w, event, prms, nprms)
5790 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5793 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5796 void SaveGameProc(w, event, prms, nprms)
5802 FileNamePopUp(_("Save game file name?"),
5803 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5807 void SavePositionProc(w, event, prms, nprms)
5813 FileNamePopUp(_("Save position file name?"),
5814 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5818 void ReloadCmailMsgProc(w, event, prms, nprms)
5824 ReloadCmailMsgEvent(FALSE);
5827 void MailMoveProc(w, event, prms, nprms)
5836 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5837 char *selected_fen_position=NULL;
5840 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5841 Atom *type_return, XtPointer *value_return,
5842 unsigned long *length_return, int *format_return)
5844 char *selection_tmp;
5846 if (!selected_fen_position) return False; /* should never happen */
5847 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5848 /* note: since no XtSelectionDoneProc was registered, Xt will
5849 * automatically call XtFree on the value returned. So have to
5850 * make a copy of it allocated with XtMalloc */
5851 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5852 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
5854 *value_return=selection_tmp;
5855 *length_return=strlen(selection_tmp);
5856 *type_return=*target;
5857 *format_return = 8; /* bits per byte */
5859 } else if (*target == XA_TARGETS(xDisplay)) {
5860 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5861 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5862 targets_tmp[1] = XA_STRING;
5863 *value_return = targets_tmp;
5864 *type_return = XA_ATOM;
5866 *format_return = 8 * sizeof(Atom);
5867 if (*format_return > 32) {
5868 *length_return *= *format_return / 32;
5869 *format_return = 32;
5877 /* note: when called from menu all parameters are NULL, so no clue what the
5878 * Widget which was clicked on was, or what the click event was
5880 void CopyPositionProc(w, event, prms, nprms)
5887 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5888 * have a notion of a position that is selected but not copied.
5889 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5891 if(gameMode == EditPosition) EditPositionDone(TRUE);
5892 if (selected_fen_position) free(selected_fen_position);
5893 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5894 if (!selected_fen_position) return;
5895 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5897 SendPositionSelection,
5898 NULL/* lose_ownership_proc */ ,
5899 NULL/* transfer_done_proc */);
5900 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5902 SendPositionSelection,
5903 NULL/* lose_ownership_proc */ ,
5904 NULL/* transfer_done_proc */);
5907 /* function called when the data to Paste is ready */
5909 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5910 Atom *type, XtPointer value, unsigned long *len, int *format)
5913 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5914 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5915 EditPositionPasteFEN(fenstr);
5919 /* called when Paste Position button is pressed,
5920 * all parameters will be NULL */
5921 void PastePositionProc(w, event, prms, nprms)
5927 XtGetSelectionValue(menuBarWidget,
5928 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5929 /* (XtSelectionCallbackProc) */ PastePositionCB,
5930 NULL, /* client_data passed to PastePositionCB */
5932 /* better to use the time field from the event that triggered the
5933 * call to this function, but that isn't trivial to get
5941 SendGameSelection(Widget w, Atom *selection, Atom *target,
5942 Atom *type_return, XtPointer *value_return,
5943 unsigned long *length_return, int *format_return)
5945 char *selection_tmp;
5947 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5948 FILE* f = fopen(gameCopyFilename, "r");
5951 if (f == NULL) return False;
5955 selection_tmp = XtMalloc(len + 1);
5956 count = fread(selection_tmp, 1, len, f);
5959 XtFree(selection_tmp);
5962 selection_tmp[len] = NULLCHAR;
5963 *value_return = selection_tmp;
5964 *length_return = len;
5965 *type_return = *target;
5966 *format_return = 8; /* bits per byte */
5968 } else if (*target == XA_TARGETS(xDisplay)) {
5969 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5970 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5971 targets_tmp[1] = XA_STRING;
5972 *value_return = targets_tmp;
5973 *type_return = XA_ATOM;
5975 *format_return = 8 * sizeof(Atom);
5976 if (*format_return > 32) {
5977 *length_return *= *format_return / 32;
5978 *format_return = 32;
5986 /* note: when called from menu all parameters are NULL, so no clue what the
5987 * Widget which was clicked on was, or what the click event was
5989 void CopyGameProc(w, event, prms, nprms)
5997 ret = SaveGameToFile(gameCopyFilename, FALSE);
6001 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
6002 * have a notion of a game that is selected but not copied.
6003 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
6005 XtOwnSelection(menuBarWidget, XA_PRIMARY,
6008 NULL/* lose_ownership_proc */ ,
6009 NULL/* transfer_done_proc */);
6010 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
6013 NULL/* lose_ownership_proc */ ,
6014 NULL/* transfer_done_proc */);
6017 /* function called when the data to Paste is ready */
6019 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
6020 Atom *type, XtPointer value, unsigned long *len, int *format)
6023 if (value == NULL || *len == 0) {
6024 return; /* nothing had been selected to copy */
6026 f = fopen(gamePasteFilename, "w");
6028 DisplayError(_("Can't open temp file"), errno);
6031 fwrite(value, 1, *len, f);
6034 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
6037 /* called when Paste Game button is pressed,
6038 * all parameters will be NULL */
6039 void PasteGameProc(w, event, prms, nprms)
6045 XtGetSelectionValue(menuBarWidget,
6046 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
6047 /* (XtSelectionCallbackProc) */ PasteGameCB,
6048 NULL, /* client_data passed to PasteGameCB */
6050 /* better to use the time field from the event that triggered the
6051 * call to this function, but that isn't trivial to get
6061 SaveGameProc(NULL, NULL, NULL, NULL);
6065 void QuitProc(w, event, prms, nprms)
6074 void PauseProc(w, event, prms, nprms)
6084 void MachineBlackProc(w, event, prms, nprms)
6090 MachineBlackEvent();
6093 void MachineWhiteProc(w, event, prms, nprms)
6099 MachineWhiteEvent();
6102 void AnalyzeModeProc(w, event, prms, nprms)
6110 if (!first.analysisSupport) {
6111 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6112 DisplayError(buf, 0);
6115 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
6116 if (appData.icsActive) {
6117 if (gameMode != IcsObserving) {
6118 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
6119 DisplayError(buf, 0);
6121 if (appData.icsEngineAnalyze) {
6122 if (appData.debugMode)
6123 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
6129 /* if enable, use want disable icsEngineAnalyze */
6130 if (appData.icsEngineAnalyze) {
6135 appData.icsEngineAnalyze = TRUE;
6136 if (appData.debugMode)
6137 fprintf(debugFP, _("ICS engine analyze starting... \n"));
6139 if (!appData.showThinking)
6140 ShowThinkingProc(w,event,prms,nprms);
6145 void AnalyzeFileProc(w, event, prms, nprms)
6151 if (!first.analysisSupport) {
6153 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6154 DisplayError(buf, 0);
6159 if (!appData.showThinking)
6160 ShowThinkingProc(w,event,prms,nprms);
6163 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
6164 AnalysisPeriodicEvent(1);
6167 void TwoMachinesProc(w, event, prms, nprms)
6176 void IcsClientProc(w, event, prms, nprms)
6185 void EditGameProc(w, event, prms, nprms)
6194 void EditPositionProc(w, event, prms, nprms)
6200 EditPositionEvent();
6203 void TrainingProc(w, event, prms, nprms)
6212 void EditCommentProc(w, event, prms, nprms)
6219 EditCommentPopDown();
6225 void IcsInputBoxProc(w, event, prms, nprms)
6231 if (ICSInputBoxUp) {
6232 ICSInputBoxPopDown();
6238 void AcceptProc(w, event, prms, nprms)
6247 void DeclineProc(w, event, prms, nprms)
6256 void RematchProc(w, event, prms, nprms)
6265 void CallFlagProc(w, event, prms, nprms)
6274 void DrawProc(w, event, prms, nprms)
6283 void AbortProc(w, event, prms, nprms)
6292 void AdjournProc(w, event, prms, nprms)
6301 void ResignProc(w, event, prms, nprms)
6310 void AdjuWhiteProc(w, event, prms, nprms)
6316 UserAdjudicationEvent(+1);
6319 void AdjuBlackProc(w, event, prms, nprms)
6325 UserAdjudicationEvent(-1);
6328 void AdjuDrawProc(w, event, prms, nprms)
6334 UserAdjudicationEvent(0);
6337 void EnterKeyProc(w, event, prms, nprms)
6343 if (ICSInputBoxUp == True)
6347 void UpKeyProc(w, event, prms, nprms)
6352 { // [HGM] input: let up-arrow recall previous line from history
6359 if (!ICSInputBoxUp) return;
6360 edit = XtNameToWidget(ICSInputShell, "*form.text");
6362 XtSetArg(args[j], XtNstring, &val); j++;
6363 XtGetValues(edit, args, j);
6364 val = PrevInHistory(val);
6365 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6366 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6368 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6369 XawTextReplace(edit, 0, 0, &t);
6370 XawTextSetInsertionPoint(edit, 9999);
6374 void DownKeyProc(w, event, prms, nprms)
6379 { // [HGM] input: let down-arrow recall next line from history
6384 if (!ICSInputBoxUp) return;
6385 edit = XtNameToWidget(ICSInputShell, "*form.text");
6386 val = NextInHistory();
6387 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6388 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6390 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6391 XawTextReplace(edit, 0, 0, &t);
6392 XawTextSetInsertionPoint(edit, 9999);
6396 void StopObservingProc(w, event, prms, nprms)
6402 StopObservingEvent();
6405 void StopExaminingProc(w, event, prms, nprms)
6411 StopExaminingEvent();
6414 void UploadProc(w, event, prms, nprms)
6424 void ForwardProc(w, event, prms, nprms)
6434 void BackwardProc(w, event, prms, nprms)
6443 void ToStartProc(w, event, prms, nprms)
6452 void ToEndProc(w, event, prms, nprms)
6461 void RevertProc(w, event, prms, nprms)
6470 void AnnotateProc(w, event, prms, nprms)
6479 void TruncateGameProc(w, event, prms, nprms)
6485 TruncateGameEvent();
6487 void RetractMoveProc(w, event, prms, nprms)
6496 void MoveNowProc(w, event, prms, nprms)
6506 void AlwaysQueenProc(w, event, prms, nprms)
6514 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6516 if (appData.alwaysPromoteToQueen) {
6517 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6519 XtSetArg(args[0], XtNleftBitmap, None);
6521 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6525 void AnimateDraggingProc(w, event, prms, nprms)
6533 appData.animateDragging = !appData.animateDragging;
6535 if (appData.animateDragging) {
6536 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6539 XtSetArg(args[0], XtNleftBitmap, None);
6541 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6545 void AnimateMovingProc(w, event, prms, nprms)
6553 appData.animate = !appData.animate;
6555 if (appData.animate) {
6556 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6559 XtSetArg(args[0], XtNleftBitmap, None);
6561 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6565 void AutoflagProc(w, event, prms, nprms)
6573 appData.autoCallFlag = !appData.autoCallFlag;
6575 if (appData.autoCallFlag) {
6576 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6578 XtSetArg(args[0], XtNleftBitmap, None);
6580 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6584 void AutoflipProc(w, event, prms, nprms)
6592 appData.autoFlipView = !appData.autoFlipView;
6594 if (appData.autoFlipView) {
6595 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6597 XtSetArg(args[0], XtNleftBitmap, None);
6599 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6603 void BlindfoldProc(w, event, prms, nprms)
6611 appData.blindfold = !appData.blindfold;
6613 if (appData.blindfold) {
6614 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6616 XtSetArg(args[0], XtNleftBitmap, None);
6618 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6621 DrawPosition(True, NULL);
6624 void TestLegalityProc(w, event, prms, nprms)
6632 appData.testLegality = !appData.testLegality;
6634 if (appData.testLegality) {
6635 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6637 XtSetArg(args[0], XtNleftBitmap, None);
6639 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6644 void FlashMovesProc(w, event, prms, nprms)
6652 if (appData.flashCount == 0) {
6653 appData.flashCount = 3;
6655 appData.flashCount = -appData.flashCount;
6658 if (appData.flashCount > 0) {
6659 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6661 XtSetArg(args[0], XtNleftBitmap, None);
6663 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6667 void FlipViewProc(w, event, prms, nprms)
6673 flipView = !flipView;
6674 DrawPosition(True, NULL);
6678 void HighlightDraggingProc(w, event, prms, nprms)
6686 appData.highlightDragging = !appData.highlightDragging;
6688 if (appData.highlightDragging) {
6689 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6691 XtSetArg(args[0], XtNleftBitmap, None);
6693 XtSetValues(XtNameToWidget(menuBarWidget,
6694 "menuOptions.Highlight Dragging"), args, 1);
6698 void HighlightLastMoveProc(w, event, prms, nprms)
6706 appData.highlightLastMove = !appData.highlightLastMove;
6708 if (appData.highlightLastMove) {
6709 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6711 XtSetArg(args[0], XtNleftBitmap, None);
6713 XtSetValues(XtNameToWidget(menuBarWidget,
6714 "menuOptions.Highlight Last Move"), args, 1);
6717 void HighlightArrowProc(w, event, prms, nprms)
6725 appData.highlightMoveWithArrow = !appData.highlightMoveWithArrow;
6727 if (appData.highlightMoveWithArrow) {
6728 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6730 XtSetArg(args[0], XtNleftBitmap, None);
6732 XtSetValues(XtNameToWidget(menuBarWidget,
6733 "menuOptions.Arrow"), args, 1);
6737 void IcsAlarmProc(w, event, prms, nprms)
6745 appData.icsAlarm = !appData.icsAlarm;
6747 if (appData.icsAlarm) {
6748 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6750 XtSetArg(args[0], XtNleftBitmap, None);
6752 XtSetValues(XtNameToWidget(menuBarWidget,
6753 "menuOptions.ICS Alarm"), args, 1);
6757 void MoveSoundProc(w, event, prms, nprms)
6765 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6767 if (appData.ringBellAfterMoves) {
6768 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6770 XtSetArg(args[0], XtNleftBitmap, None);
6772 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6776 void OneClickProc(w, event, prms, nprms)
6784 appData.oneClick = !appData.oneClick;
6786 if (appData.oneClick) {
6787 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6789 XtSetArg(args[0], XtNleftBitmap, None);
6791 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.OneClick"),
6795 void PeriodicUpdatesProc(w, event, prms, nprms)
6803 PeriodicUpdatesEvent(!appData.periodicUpdates);
6805 if (appData.periodicUpdates) {
6806 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6808 XtSetArg(args[0], XtNleftBitmap, None);
6810 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6814 void PonderNextMoveProc(w, event, prms, nprms)
6822 PonderNextMoveEvent(!appData.ponderNextMove);
6824 if (appData.ponderNextMove) {
6825 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6827 XtSetArg(args[0], XtNleftBitmap, None);
6829 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6833 void PopupExitMessageProc(w, event, prms, nprms)
6841 appData.popupExitMessage = !appData.popupExitMessage;
6843 if (appData.popupExitMessage) {
6844 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6846 XtSetArg(args[0], XtNleftBitmap, None);
6848 XtSetValues(XtNameToWidget(menuBarWidget,
6849 "menuOptions.Popup Exit Message"), args, 1);
6852 void PopupMoveErrorsProc(w, event, prms, nprms)
6860 appData.popupMoveErrors = !appData.popupMoveErrors;
6862 if (appData.popupMoveErrors) {
6863 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6865 XtSetArg(args[0], XtNleftBitmap, None);
6867 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6872 void PremoveProc(w, event, prms, nprms)
6880 appData.premove = !appData.premove;
6882 if (appData.premove) {
6883 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6885 XtSetArg(args[0], XtNleftBitmap, None);
6887 XtSetValues(XtNameToWidget(menuBarWidget,
6888 "menuOptions.Premove"), args, 1);
6892 void ShowCoordsProc(w, event, prms, nprms)
6900 appData.showCoords = !appData.showCoords;
6902 if (appData.showCoords) {
6903 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6905 XtSetArg(args[0], XtNleftBitmap, None);
6907 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6910 DrawPosition(True, NULL);
6913 void ShowThinkingProc(w, event, prms, nprms)
6919 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6920 ShowThinkingEvent();
6923 void HideThinkingProc(w, event, prms, nprms)
6931 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6932 ShowThinkingEvent();
6934 if (appData.hideThinkingFromHuman) {
6935 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6937 XtSetArg(args[0], XtNleftBitmap, None);
6939 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6943 void SaveOnExitProc(w, event, prms, nprms)
6951 saveSettingsOnExit = !saveSettingsOnExit;
6953 if (saveSettingsOnExit) {
6954 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6956 XtSetArg(args[0], XtNleftBitmap, None);
6958 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6962 void SaveSettingsProc(w, event, prms, nprms)
6968 SaveSettings(settingsFileName);
6971 void InfoProc(w, event, prms, nprms)
6978 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6983 void ManProc(w, event, prms, nprms)
6991 if (nprms && *nprms > 0)
6995 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6999 void HintProc(w, event, prms, nprms)
7008 void BookProc(w, event, prms, nprms)
7017 void AboutProc(w, event, prms, nprms)
7025 char *zippy = " (with Zippy code)";
7029 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
7030 programVersion, zippy,
7031 "Copyright 1991 Digital Equipment Corporation",
7032 "Enhancements Copyright 1992-2009 Free Software Foundation",
7033 "Enhancements Copyright 2005 Alessandro Scotti",
7034 PACKAGE, " is free software and carries NO WARRANTY;",
7035 "see the file COPYING for more information.");
7036 ErrorPopUp(_("About XBoard"), buf, FALSE);
7039 void DebugProc(w, event, prms, nprms)
7045 appData.debugMode = !appData.debugMode;
7048 void AboutGameProc(w, event, prms, nprms)
7057 void NothingProc(w, event, prms, nprms)
7066 void Iconify(w, event, prms, nprms)
7075 XtSetArg(args[0], XtNiconic, True);
7076 XtSetValues(shellWidget, args, 1);
7079 void DisplayMessage(message, extMessage)
7080 char *message, *extMessage;
7082 /* display a message in the message widget */
7091 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
7096 message = extMessage;
7100 /* need to test if messageWidget already exists, since this function
7101 can also be called during the startup, if for example a Xresource
7102 is not set up correctly */
7105 XtSetArg(arg, XtNlabel, message);
7106 XtSetValues(messageWidget, &arg, 1);
7112 void DisplayTitle(text)
7117 char title[MSG_SIZ];
7120 if (text == NULL) text = "";
7122 if (appData.titleInWindow) {
7124 XtSetArg(args[i], XtNlabel, text); i++;
7125 XtSetValues(titleWidget, args, i);
7128 if (*text != NULLCHAR) {
7129 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
7130 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
7131 } else if (appData.icsActive) {
7132 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7133 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7134 } else if (appData.cmailGameName[0] != NULLCHAR) {
7135 snprintf(icon, sizeof(icon), "%s", "CMail");
7136 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7138 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7139 } else if (gameInfo.variant == VariantGothic) {
7140 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7141 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
7144 } else if (gameInfo.variant == VariantFalcon) {
7145 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7146 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
7148 } else if (appData.noChessProgram) {
7149 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7150 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
7152 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
7153 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7156 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7157 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7158 XtSetValues(shellWidget, args, i);
7163 DisplayError(message, error)
7170 if (appData.debugMode || appData.matchMode) {
7171 fprintf(stderr, "%s: %s\n", programName, message);
7174 if (appData.debugMode || appData.matchMode) {
7175 fprintf(stderr, "%s: %s: %s\n",
7176 programName, message, strerror(error));
7178 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7181 ErrorPopUp(_("Error"), message, FALSE);
7185 void DisplayMoveError(message)
7190 DrawPosition(FALSE, NULL);
7191 if (appData.debugMode || appData.matchMode) {
7192 fprintf(stderr, "%s: %s\n", programName, message);
7194 if (appData.popupMoveErrors) {
7195 ErrorPopUp(_("Error"), message, FALSE);
7197 DisplayMessage(message, "");
7202 void DisplayFatalError(message, error, status)
7208 errorExitStatus = status;
7210 fprintf(stderr, "%s: %s\n", programName, message);
7212 fprintf(stderr, "%s: %s: %s\n",
7213 programName, message, strerror(error));
7214 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7217 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7218 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7224 void DisplayInformation(message)
7228 ErrorPopUp(_("Information"), message, TRUE);
7231 void DisplayNote(message)
7235 ErrorPopUp(_("Note"), message, FALSE);
7239 NullXErrorCheck(dpy, error_event)
7241 XErrorEvent *error_event;
7246 void DisplayIcsInteractionTitle(message)
7249 if (oldICSInteractionTitle == NULL) {
7250 /* Magic to find the old window title, adapted from vim */
7251 char *wina = getenv("WINDOWID");
7253 Window win = (Window) atoi(wina);
7254 Window root, parent, *children;
7255 unsigned int nchildren;
7256 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7258 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7259 if (!XQueryTree(xDisplay, win, &root, &parent,
7260 &children, &nchildren)) break;
7261 if (children) XFree((void *)children);
7262 if (parent == root || parent == 0) break;
7265 XSetErrorHandler(oldHandler);
7267 if (oldICSInteractionTitle == NULL) {
7268 oldICSInteractionTitle = "xterm";
7271 printf("\033]0;%s\007", message);
7275 char pendingReplyPrefix[MSG_SIZ];
7276 ProcRef pendingReplyPR;
7278 void AskQuestionProc(w, event, prms, nprms)
7285 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7289 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7292 void AskQuestionPopDown()
7294 if (!askQuestionUp) return;
7295 XtPopdown(askQuestionShell);
7296 XtDestroyWidget(askQuestionShell);
7297 askQuestionUp = False;
7300 void AskQuestionReplyAction(w, event, prms, nprms)
7310 reply = XawDialogGetValueString(w = XtParent(w));
7311 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
7312 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
7313 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
7314 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
7315 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7316 AskQuestionPopDown();
7318 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7321 void AskQuestionCallback(w, client_data, call_data)
7323 XtPointer client_data, call_data;
7328 XtSetArg(args[0], XtNlabel, &name);
7329 XtGetValues(w, args, 1);
7331 if (strcmp(name, _("cancel")) == 0) {
7332 AskQuestionPopDown();
7334 AskQuestionReplyAction(w, NULL, NULL, NULL);
7338 void AskQuestion(title, question, replyPrefix, pr)
7339 char *title, *question, *replyPrefix;
7343 Widget popup, layout, dialog, edit;
7349 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
7350 pendingReplyPR = pr;
7353 XtSetArg(args[i], XtNresizable, True); i++;
7354 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7355 askQuestionShell = popup =
7356 XtCreatePopupShell(title, transientShellWidgetClass,
7357 shellWidget, args, i);
7360 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7361 layoutArgs, XtNumber(layoutArgs));
7364 XtSetArg(args[i], XtNlabel, question); i++;
7365 XtSetArg(args[i], XtNvalue, ""); i++;
7366 XtSetArg(args[i], XtNborderWidth, 0); i++;
7367 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7370 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7371 (XtPointer) dialog);
7372 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7373 (XtPointer) dialog);
7375 XtRealizeWidget(popup);
7376 CatchDeleteWindow(popup, "AskQuestionPopDown");
7378 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7379 &x, &y, &win_x, &win_y, &mask);
7381 XtSetArg(args[0], XtNx, x - 10);
7382 XtSetArg(args[1], XtNy, y - 30);
7383 XtSetValues(popup, args, 2);
7385 XtPopup(popup, XtGrabExclusive);
7386 askQuestionUp = True;
7388 edit = XtNameToWidget(dialog, "*value");
7389 XtSetKeyboardFocus(popup, edit);
7397 if (*name == NULLCHAR) {
7399 } else if (strcmp(name, "$") == 0) {
7400 putc(BELLCHAR, stderr);
7403 char *prefix = "", *sep = "";
7404 if(!strchr(name, '/')) { prefix = appData.soundDirectory; sep = "/"; }
7405 snprintf(buf, sizeof(buf), "%s '%s%s%s' &", appData.soundProgram, prefix, sep, name);
7413 PlaySound(appData.soundMove);
7419 PlaySound(appData.soundIcsWin);
7425 PlaySound(appData.soundIcsLoss);
7431 PlaySound(appData.soundIcsDraw);
7435 PlayIcsUnfinishedSound()
7437 PlaySound(appData.soundIcsUnfinished);
7443 PlaySound(appData.soundIcsAlarm);
7449 system("stty echo");
7455 system("stty -echo");
7459 Colorize(cc, continuation)
7464 int count, outCount, error;
7466 if (textColors[(int)cc].bg > 0) {
7467 if (textColors[(int)cc].fg > 0) {
7468 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7469 textColors[(int)cc].fg, textColors[(int)cc].bg);
7471 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7472 textColors[(int)cc].bg);
7475 if (textColors[(int)cc].fg > 0) {
7476 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7477 textColors[(int)cc].fg);
7479 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7482 count = strlen(buf);
7483 outCount = OutputToProcess(NoProc, buf, count, &error);
7484 if (outCount < count) {
7485 DisplayFatalError(_("Error writing to display"), error, 1);
7488 if (continuation) return;
7491 PlaySound(appData.soundShout);
7494 PlaySound(appData.soundSShout);
7497 PlaySound(appData.soundChannel1);
7500 PlaySound(appData.soundChannel);
7503 PlaySound(appData.soundKibitz);
7506 PlaySound(appData.soundTell);
7508 case ColorChallenge:
7509 PlaySound(appData.soundChallenge);
7512 PlaySound(appData.soundRequest);
7515 PlaySound(appData.soundSeek);
7526 return getpwuid(getuid())->pw_name;
7530 ExpandPathName(path)
7533 static char static_buf[4*MSG_SIZ];
7534 char *d, *s, buf[4*MSG_SIZ];
7540 while (*s && isspace(*s))
7549 if (*(s+1) == '/') {
7550 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7554 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7555 { char *p; if(p = strchr(buf, '/')) *p = 0; }
7556 pwd = getpwnam(buf);
7559 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7563 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7564 strcat(d, strchr(s+1, '/'));
7568 safeStrCpy(d, s, 4*MSG_SIZ );
7575 static char host_name[MSG_SIZ];
7577 #if HAVE_GETHOSTNAME
7578 gethostname(host_name, MSG_SIZ);
7580 #else /* not HAVE_GETHOSTNAME */
7581 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7582 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7584 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7586 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7587 #endif /* not HAVE_GETHOSTNAME */
7590 XtIntervalId delayedEventTimerXID = 0;
7591 DelayedEventCallback delayedEventCallback = 0;
7596 delayedEventTimerXID = 0;
7597 delayedEventCallback();
7601 ScheduleDelayedEvent(cb, millisec)
7602 DelayedEventCallback cb; long millisec;
7604 if(delayedEventTimerXID && delayedEventCallback == cb)
7605 // [HGM] alive: replace, rather than add or flush identical event
7606 XtRemoveTimeOut(delayedEventTimerXID);
7607 delayedEventCallback = cb;
7608 delayedEventTimerXID =
7609 XtAppAddTimeOut(appContext, millisec,
7610 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7613 DelayedEventCallback
7616 if (delayedEventTimerXID) {
7617 return delayedEventCallback;
7624 CancelDelayedEvent()
7626 if (delayedEventTimerXID) {
7627 XtRemoveTimeOut(delayedEventTimerXID);
7628 delayedEventTimerXID = 0;
7632 XtIntervalId loadGameTimerXID = 0;
7634 int LoadGameTimerRunning()
7636 return loadGameTimerXID != 0;
7639 int StopLoadGameTimer()
7641 if (loadGameTimerXID != 0) {
7642 XtRemoveTimeOut(loadGameTimerXID);
7643 loadGameTimerXID = 0;
7651 LoadGameTimerCallback(arg, id)
7655 loadGameTimerXID = 0;
7660 StartLoadGameTimer(millisec)
7664 XtAppAddTimeOut(appContext, millisec,
7665 (XtTimerCallbackProc) LoadGameTimerCallback,
7669 XtIntervalId analysisClockXID = 0;
7672 AnalysisClockCallback(arg, id)
7676 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7677 || appData.icsEngineAnalyze) { // [DM]
7678 AnalysisPeriodicEvent(0);
7679 StartAnalysisClock();
7684 StartAnalysisClock()
7687 XtAppAddTimeOut(appContext, 2000,
7688 (XtTimerCallbackProc) AnalysisClockCallback,
7692 XtIntervalId clockTimerXID = 0;
7694 int ClockTimerRunning()
7696 return clockTimerXID != 0;
7699 int StopClockTimer()
7701 if (clockTimerXID != 0) {
7702 XtRemoveTimeOut(clockTimerXID);
7711 ClockTimerCallback(arg, id)
7720 StartClockTimer(millisec)
7724 XtAppAddTimeOut(appContext, millisec,
7725 (XtTimerCallbackProc) ClockTimerCallback,
7730 DisplayTimerLabel(w, color, timer, highlight)
7739 /* check for low time warning */
7740 Pixel foregroundOrWarningColor = timerForegroundPixel;
7743 appData.lowTimeWarning &&
7744 (timer / 1000) < appData.icsAlarmTime)
7745 foregroundOrWarningColor = lowTimeWarningColor;
7747 if (appData.clockMode) {
7748 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7749 XtSetArg(args[0], XtNlabel, buf);
7751 snprintf(buf, MSG_SIZ, "%s ", color);
7752 XtSetArg(args[0], XtNlabel, buf);
7757 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7758 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7760 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7761 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7764 XtSetValues(w, args, 3);
7768 DisplayWhiteClock(timeRemaining, highlight)
7774 if(appData.noGUI) return;
7775 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7776 if (highlight && iconPixmap == bIconPixmap) {
7777 iconPixmap = wIconPixmap;
7778 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7779 XtSetValues(shellWidget, args, 1);
7784 DisplayBlackClock(timeRemaining, highlight)
7790 if(appData.noGUI) return;
7791 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7792 if (highlight && iconPixmap == wIconPixmap) {
7793 iconPixmap = bIconPixmap;
7794 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7795 XtSetValues(shellWidget, args, 1);
7813 int StartChildProcess(cmdLine, dir, pr)
7820 int to_prog[2], from_prog[2];
7824 if (appData.debugMode) {
7825 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7828 /* We do NOT feed the cmdLine to the shell; we just
7829 parse it into blank-separated arguments in the
7830 most simple-minded way possible.
7833 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7836 while(*p == ' ') p++;
7838 if(*p == '"' || *p == '\'')
7839 p = strchr(++argv[i-1], *p);
7840 else p = strchr(p, ' ');
7841 if (p == NULL) break;
7846 SetUpChildIO(to_prog, from_prog);
7848 if ((pid = fork()) == 0) {
7850 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7851 close(to_prog[1]); // first close the unused pipe ends
7852 close(from_prog[0]);
7853 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7854 dup2(from_prog[1], 1);
7855 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7856 close(from_prog[1]); // and closing again loses one of the pipes!
7857 if(fileno(stderr) >= 2) // better safe than sorry...
7858 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7860 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7865 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7867 execvp(argv[0], argv);
7869 /* If we get here, exec failed */
7874 /* Parent process */
7876 close(from_prog[1]);
7878 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7881 cp->fdFrom = from_prog[0];
7882 cp->fdTo = to_prog[1];
7887 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7888 static RETSIGTYPE AlarmCallBack(int n)
7894 DestroyChildProcess(pr, signalType)
7898 ChildProc *cp = (ChildProc *) pr;
7900 if (cp->kind != CPReal) return;
7902 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7903 signal(SIGALRM, AlarmCallBack);
7905 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7906 kill(cp->pid, SIGKILL); // kill it forcefully
7907 wait((int *) 0); // and wait again
7911 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7913 /* Process is exiting either because of the kill or because of
7914 a quit command sent by the backend; either way, wait for it to die.
7923 InterruptChildProcess(pr)
7926 ChildProc *cp = (ChildProc *) pr;
7928 if (cp->kind != CPReal) return;
7929 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7932 int OpenTelnet(host, port, pr)
7937 char cmdLine[MSG_SIZ];
7939 if (port[0] == NULLCHAR) {
7940 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7942 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7944 return StartChildProcess(cmdLine, "", pr);
7947 int OpenTCP(host, port, pr)
7953 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7954 #else /* !OMIT_SOCKETS */
7956 struct sockaddr_in sa;
7958 unsigned short uport;
7961 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7965 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7966 sa.sin_family = AF_INET;
7967 sa.sin_addr.s_addr = INADDR_ANY;
7968 uport = (unsigned short) 0;
7969 sa.sin_port = htons(uport);
7970 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7974 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7975 if (!(hp = gethostbyname(host))) {
7977 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7978 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7979 hp->h_addrtype = AF_INET;
7981 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7982 hp->h_addr_list[0] = (char *) malloc(4);
7983 hp->h_addr_list[0][0] = b0;
7984 hp->h_addr_list[0][1] = b1;
7985 hp->h_addr_list[0][2] = b2;
7986 hp->h_addr_list[0][3] = b3;
7991 sa.sin_family = hp->h_addrtype;
7992 uport = (unsigned short) atoi(port);
7993 sa.sin_port = htons(uport);
7994 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7996 if (connect(s, (struct sockaddr *) &sa,
7997 sizeof(struct sockaddr_in)) < 0) {
8001 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8008 #endif /* !OMIT_SOCKETS */
8013 int OpenCommPort(name, pr)
8020 fd = open(name, 2, 0);
8021 if (fd < 0) return errno;
8023 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8033 int OpenLoopback(pr)
8039 SetUpChildIO(to, from);
8041 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8044 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
8051 int OpenRcmd(host, user, cmd, pr)
8052 char *host, *user, *cmd;
8055 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
8059 #define INPUT_SOURCE_BUF_SIZE 8192
8068 char buf[INPUT_SOURCE_BUF_SIZE];
8073 DoInputCallback(closure, source, xid)
8078 InputSource *is = (InputSource *) closure;
8083 if (is->lineByLine) {
8084 count = read(is->fd, is->unused,
8085 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
8087 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
8090 is->unused += count;
8092 while (p < is->unused) {
8093 q = memchr(p, '\n', is->unused - p);
8094 if (q == NULL) break;
8096 (is->func)(is, is->closure, p, q - p, 0);
8100 while (p < is->unused) {
8105 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8110 (is->func)(is, is->closure, is->buf, count, error);
8114 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8121 ChildProc *cp = (ChildProc *) pr;
8123 is = (InputSource *) calloc(1, sizeof(InputSource));
8124 is->lineByLine = lineByLine;
8128 is->fd = fileno(stdin);
8130 is->kind = cp->kind;
8131 is->fd = cp->fdFrom;
8134 is->unused = is->buf;
8137 is->xid = XtAppAddInput(appContext, is->fd,
8138 (XtPointer) (XtInputReadMask),
8139 (XtInputCallbackProc) DoInputCallback,
8141 is->closure = closure;
8142 return (InputSourceRef) is;
8146 RemoveInputSource(isr)
8149 InputSource *is = (InputSource *) isr;
8151 if (is->xid == 0) return;
8152 XtRemoveInput(is->xid);
8156 int OutputToProcess(pr, message, count, outError)
8162 static int line = 0;
8163 ChildProc *cp = (ChildProc *) pr;
8168 if (appData.noJoin || !appData.useInternalWrap)
8169 outCount = fwrite(message, 1, count, stdout);
8172 int width = get_term_width();
8173 int len = wrap(NULL, message, count, width, &line);
8174 char *msg = malloc(len);
8178 outCount = fwrite(message, 1, count, stdout);
8181 dbgchk = wrap(msg, message, count, width, &line);
8182 if (dbgchk != len && appData.debugMode)
8183 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8184 outCount = fwrite(msg, 1, dbgchk, stdout);
8190 outCount = write(cp->fdTo, message, count);
8200 /* Output message to process, with "ms" milliseconds of delay
8201 between each character. This is needed when sending the logon
8202 script to ICC, which for some reason doesn't like the
8203 instantaneous send. */
8204 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8211 ChildProc *cp = (ChildProc *) pr;
8216 r = write(cp->fdTo, message++, 1);
8229 /**** Animation code by Hugh Fisher, DCS, ANU.
8231 Known problem: if a window overlapping the board is
8232 moved away while a piece is being animated underneath,
8233 the newly exposed area won't be updated properly.
8234 I can live with this.
8236 Known problem: if you look carefully at the animation
8237 of pieces in mono mode, they are being drawn as solid
8238 shapes without interior detail while moving. Fixing
8239 this would be a major complication for minimal return.
8242 /* Masks for XPM pieces. Black and white pieces can have
8243 different shapes, but in the interest of retaining my
8244 sanity pieces must have the same outline on both light
8245 and dark squares, and all pieces must use the same
8246 background square colors/images. */
8248 static int xpmDone = 0;
8251 CreateAnimMasks (pieceDepth)
8258 unsigned long plane;
8261 /* Need a bitmap just to get a GC with right depth */
8262 buf = XCreatePixmap(xDisplay, xBoardWindow,
8264 values.foreground = 1;
8265 values.background = 0;
8266 /* Don't use XtGetGC, not read only */
8267 maskGC = XCreateGC(xDisplay, buf,
8268 GCForeground | GCBackground, &values);
8269 XFreePixmap(xDisplay, buf);
8271 buf = XCreatePixmap(xDisplay, xBoardWindow,
8272 squareSize, squareSize, pieceDepth);
8273 values.foreground = XBlackPixel(xDisplay, xScreen);
8274 values.background = XWhitePixel(xDisplay, xScreen);
8275 bufGC = XCreateGC(xDisplay, buf,
8276 GCForeground | GCBackground, &values);
8278 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8279 /* Begin with empty mask */
8280 if(!xpmDone) // [HGM] pieces: keep using existing
8281 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8282 squareSize, squareSize, 1);
8283 XSetFunction(xDisplay, maskGC, GXclear);
8284 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8285 0, 0, squareSize, squareSize);
8287 /* Take a copy of the piece */
8292 XSetFunction(xDisplay, bufGC, GXcopy);
8293 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8295 0, 0, squareSize, squareSize, 0, 0);
8297 /* XOR the background (light) over the piece */
8298 XSetFunction(xDisplay, bufGC, GXxor);
8300 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8301 0, 0, squareSize, squareSize, 0, 0);
8303 XSetForeground(xDisplay, bufGC, lightSquareColor);
8304 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8307 /* We now have an inverted piece image with the background
8308 erased. Construct mask by just selecting all the non-zero
8309 pixels - no need to reconstruct the original image. */
8310 XSetFunction(xDisplay, maskGC, GXor);
8312 /* Might be quicker to download an XImage and create bitmap
8313 data from it rather than this N copies per piece, but it
8314 only takes a fraction of a second and there is a much
8315 longer delay for loading the pieces. */
8316 for (n = 0; n < pieceDepth; n ++) {
8317 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8318 0, 0, squareSize, squareSize,
8324 XFreePixmap(xDisplay, buf);
8325 XFreeGC(xDisplay, bufGC);
8326 XFreeGC(xDisplay, maskGC);
8330 InitAnimState (anim, info)
8332 XWindowAttributes * info;
8337 /* Each buffer is square size, same depth as window */
8338 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8339 squareSize, squareSize, info->depth);
8340 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8341 squareSize, squareSize, info->depth);
8343 /* Create a plain GC for blitting */
8344 mask = GCForeground | GCBackground | GCFunction |
8345 GCPlaneMask | GCGraphicsExposures;
8346 values.foreground = XBlackPixel(xDisplay, xScreen);
8347 values.background = XWhitePixel(xDisplay, xScreen);
8348 values.function = GXcopy;
8349 values.plane_mask = AllPlanes;
8350 values.graphics_exposures = False;
8351 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8353 /* Piece will be copied from an existing context at
8354 the start of each new animation/drag. */
8355 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8357 /* Outline will be a read-only copy of an existing */
8358 anim->outlineGC = None;
8364 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8365 XWindowAttributes info;
8367 if (xpmDone && gameInfo.variant == old) return;
8368 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8369 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8371 InitAnimState(&game, &info);
8372 InitAnimState(&player, &info);
8374 /* For XPM pieces, we need bitmaps to use as masks. */
8376 CreateAnimMasks(info.depth);
8382 static Boolean frameWaiting;
8384 static RETSIGTYPE FrameAlarm (sig)
8387 frameWaiting = False;
8388 /* In case System-V style signals. Needed?? */
8389 signal(SIGALRM, FrameAlarm);
8396 struct itimerval delay;
8398 XSync(xDisplay, False);
8401 frameWaiting = True;
8402 signal(SIGALRM, FrameAlarm);
8403 delay.it_interval.tv_sec =
8404 delay.it_value.tv_sec = time / 1000;
8405 delay.it_interval.tv_usec =
8406 delay.it_value.tv_usec = (time % 1000) * 1000;
8407 setitimer(ITIMER_REAL, &delay, NULL);
8408 while (frameWaiting) pause();
8409 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8410 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8411 setitimer(ITIMER_REAL, &delay, NULL);
8421 XSync(xDisplay, False);
8423 usleep(time * 1000);
8428 /* Convert board position to corner of screen rect and color */
8431 ScreenSquare(column, row, pt, color)
8432 int column; int row; XPoint * pt; int * color;
8435 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8436 pt->y = lineGap + row * (squareSize + lineGap);
8438 pt->x = lineGap + column * (squareSize + lineGap);
8439 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8441 *color = SquareColor(row, column);
8444 /* Convert window coords to square */
8447 BoardSquare(x, y, column, row)
8448 int x; int y; int * column; int * row;
8450 *column = EventToSquare(x, BOARD_WIDTH);
8451 if (flipView && *column >= 0)
8452 *column = BOARD_WIDTH - 1 - *column;
8453 *row = EventToSquare(y, BOARD_HEIGHT);
8454 if (!flipView && *row >= 0)
8455 *row = BOARD_HEIGHT - 1 - *row;
8460 #undef Max /* just in case */
8462 #define Max(a, b) ((a) > (b) ? (a) : (b))
8463 #define Min(a, b) ((a) < (b) ? (a) : (b))
8466 SetRect(rect, x, y, width, height)
8467 XRectangle * rect; int x; int y; int width; int height;
8471 rect->width = width;
8472 rect->height = height;
8475 /* Test if two frames overlap. If they do, return
8476 intersection rect within old and location of
8477 that rect within new. */
8480 Intersect(old, new, size, area, pt)
8481 XPoint * old; XPoint * new;
8482 int size; XRectangle * area; XPoint * pt;
8484 if (old->x > new->x + size || new->x > old->x + size ||
8485 old->y > new->y + size || new->y > old->y + size) {
8488 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8489 size - abs(old->x - new->x), size - abs(old->y - new->y));
8490 pt->x = Max(old->x - new->x, 0);
8491 pt->y = Max(old->y - new->y, 0);
8496 /* For two overlapping frames, return the rect(s)
8497 in the old that do not intersect with the new. */
8500 CalcUpdateRects(old, new, size, update, nUpdates)
8501 XPoint * old; XPoint * new; int size;
8502 XRectangle update[]; int * nUpdates;
8506 /* If old = new (shouldn't happen) then nothing to draw */
8507 if (old->x == new->x && old->y == new->y) {
8511 /* Work out what bits overlap. Since we know the rects
8512 are the same size we don't need a full intersect calc. */
8514 /* Top or bottom edge? */
8515 if (new->y > old->y) {
8516 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8518 } else if (old->y > new->y) {
8519 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8520 size, old->y - new->y);
8523 /* Left or right edge - don't overlap any update calculated above. */
8524 if (new->x > old->x) {
8525 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8526 new->x - old->x, size - abs(new->y - old->y));
8528 } else if (old->x > new->x) {
8529 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8530 old->x - new->x, size - abs(new->y - old->y));
8537 /* Generate a series of frame coords from start->mid->finish.
8538 The movement rate doubles until the half way point is
8539 reached, then halves back down to the final destination,
8540 which gives a nice slow in/out effect. The algorithmn
8541 may seem to generate too many intermediates for short
8542 moves, but remember that the purpose is to attract the
8543 viewers attention to the piece about to be moved and
8544 then to where it ends up. Too few frames would be less
8548 Tween(start, mid, finish, factor, frames, nFrames)
8549 XPoint * start; XPoint * mid;
8550 XPoint * finish; int factor;
8551 XPoint frames[]; int * nFrames;
8553 int fraction, n, count;
8557 /* Slow in, stepping 1/16th, then 1/8th, ... */
8559 for (n = 0; n < factor; n++)
8561 for (n = 0; n < factor; n++) {
8562 frames[count].x = start->x + (mid->x - start->x) / fraction;
8563 frames[count].y = start->y + (mid->y - start->y) / fraction;
8565 fraction = fraction / 2;
8569 frames[count] = *mid;
8572 /* Slow out, stepping 1/2, then 1/4, ... */
8574 for (n = 0; n < factor; n++) {
8575 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8576 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8578 fraction = fraction * 2;
8583 /* Draw a piece on the screen without disturbing what's there */
8586 SelectGCMask(piece, clip, outline, mask)
8587 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8591 /* Bitmap for piece being moved. */
8592 if (appData.monoMode) {
8593 *mask = *pieceToSolid(piece);
8594 } else if (useImages) {
8596 *mask = xpmMask[piece];
8598 *mask = ximMaskPm[piece];
8601 *mask = *pieceToSolid(piece);
8604 /* GC for piece being moved. Square color doesn't matter, but
8605 since it gets modified we make a copy of the original. */
8607 if (appData.monoMode)
8612 if (appData.monoMode)
8617 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8619 /* Outline only used in mono mode and is not modified */
8621 *outline = bwPieceGC;
8623 *outline = wbPieceGC;
8627 OverlayPiece(piece, clip, outline, dest)
8628 ChessSquare piece; GC clip; GC outline; Drawable dest;
8633 /* Draw solid rectangle which will be clipped to shape of piece */
8634 XFillRectangle(xDisplay, dest, clip,
8635 0, 0, squareSize, squareSize);
8636 if (appData.monoMode)
8637 /* Also draw outline in contrasting color for black
8638 on black / white on white cases */
8639 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8640 0, 0, squareSize, squareSize, 0, 0, 1);
8642 /* Copy the piece */
8647 if(appData.upsideDown && flipView) kind ^= 2;
8648 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8650 0, 0, squareSize, squareSize,
8655 /* Animate the movement of a single piece */
8658 BeginAnimation(anim, piece, startColor, start)
8666 if(appData.upsideDown && flipView) piece += piece < BlackPawn ? BlackPawn : -BlackPawn;
8667 /* The old buffer is initialised with the start square (empty) */
8668 BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0);
8669 anim->prevFrame = *start;
8671 /* The piece will be drawn using its own bitmap as a matte */
8672 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8673 XSetClipMask(xDisplay, anim->pieceGC, mask);
8677 AnimationFrame(anim, frame, piece)
8682 XRectangle updates[4];
8687 /* Save what we are about to draw into the new buffer */
8688 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8689 frame->x, frame->y, squareSize, squareSize,
8692 /* Erase bits of the previous frame */
8693 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8694 /* Where the new frame overlapped the previous,
8695 the contents in newBuf are wrong. */
8696 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8697 overlap.x, overlap.y,
8698 overlap.width, overlap.height,
8700 /* Repaint the areas in the old that don't overlap new */
8701 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8702 for (i = 0; i < count; i++)
8703 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8704 updates[i].x - anim->prevFrame.x,
8705 updates[i].y - anim->prevFrame.y,
8706 updates[i].width, updates[i].height,
8707 updates[i].x, updates[i].y);
8709 /* Easy when no overlap */
8710 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8711 0, 0, squareSize, squareSize,
8712 anim->prevFrame.x, anim->prevFrame.y);
8715 /* Save this frame for next time round */
8716 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8717 0, 0, squareSize, squareSize,
8719 anim->prevFrame = *frame;
8721 /* Draw piece over original screen contents, not current,
8722 and copy entire rect. Wipes out overlapping piece images. */
8723 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8724 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8725 0, 0, squareSize, squareSize,
8726 frame->x, frame->y);
8730 EndAnimation (anim, finish)
8734 XRectangle updates[4];
8739 /* The main code will redraw the final square, so we
8740 only need to erase the bits that don't overlap. */
8741 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8742 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8743 for (i = 0; i < count; i++)
8744 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8745 updates[i].x - anim->prevFrame.x,
8746 updates[i].y - anim->prevFrame.y,
8747 updates[i].width, updates[i].height,
8748 updates[i].x, updates[i].y);
8750 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8751 0, 0, squareSize, squareSize,
8752 anim->prevFrame.x, anim->prevFrame.y);
8757 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8759 ChessSquare piece; int startColor;
8760 XPoint * start; XPoint * finish;
8761 XPoint frames[]; int nFrames;
8765 BeginAnimation(anim, piece, startColor, start);
8766 for (n = 0; n < nFrames; n++) {
8767 AnimationFrame(anim, &(frames[n]), piece);
8768 FrameDelay(appData.animSpeed);
8770 EndAnimation(anim, finish);
8774 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
8777 ChessSquare piece = board[fromY][toY];
8778 board[fromY][toY] = EmptySquare;
8779 DrawPosition(FALSE, board);
8781 x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap);
8782 y = lineGap + toY * (squareSize + lineGap);
8784 x = lineGap + toX * (squareSize + lineGap);
8785 y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap);
8787 for(i=1; i<4*kFactor; i++) {
8788 int r = squareSize * 9 * i/(20*kFactor - 5);
8789 XFillArc(xDisplay, xBoardWindow, highlineGC,
8790 x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360);
8791 FrameDelay(appData.animSpeed);
8793 board[fromY][toY] = piece;
8796 /* Main control logic for deciding what to animate and how */
8799 AnimateMove(board, fromX, fromY, toX, toY)
8808 XPoint start, finish, mid;
8809 XPoint frames[kFactor * 2 + 1];
8810 int nFrames, startColor, endColor;
8812 /* Are we animating? */
8813 if (!appData.animate || appData.blindfold)
8816 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8817 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8818 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8820 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8821 piece = board[fromY][fromX];
8822 if (piece >= EmptySquare) return;
8827 hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1;
8830 if (appData.debugMode) {
8831 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8832 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8833 piece, fromX, fromY, toX, toY); }
8835 ScreenSquare(fromX, fromY, &start, &startColor);
8836 ScreenSquare(toX, toY, &finish, &endColor);
8839 /* Knight: make straight movement then diagonal */
8840 if (abs(toY - fromY) < abs(toX - fromX)) {
8841 mid.x = start.x + (finish.x - start.x) / 2;
8845 mid.y = start.y + (finish.y - start.y) / 2;
8848 mid.x = start.x + (finish.x - start.x) / 2;
8849 mid.y = start.y + (finish.y - start.y) / 2;
8852 /* Don't use as many frames for very short moves */
8853 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8854 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8856 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8857 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8858 if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
8860 for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
8861 if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
8864 /* Be sure end square is redrawn */
8865 damage[0][toY][toX] = True;
8869 DragPieceBegin(x, y)
8872 int boardX, boardY, color;
8875 /* Are we animating? */
8876 if (!appData.animateDragging || appData.blindfold)
8879 /* Figure out which square we start in and the
8880 mouse position relative to top left corner. */
8881 BoardSquare(x, y, &boardX, &boardY);
8882 player.startBoardX = boardX;
8883 player.startBoardY = boardY;
8884 ScreenSquare(boardX, boardY, &corner, &color);
8885 player.startSquare = corner;
8886 player.startColor = color;
8887 /* As soon as we start dragging, the piece will jump slightly to
8888 be centered over the mouse pointer. */
8889 player.mouseDelta.x = squareSize/2;
8890 player.mouseDelta.y = squareSize/2;
8891 /* Initialise animation */
8892 player.dragPiece = PieceForSquare(boardX, boardY);
8894 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8895 player.dragActive = True;
8896 BeginAnimation(&player, player.dragPiece, color, &corner);
8897 /* Mark this square as needing to be redrawn. Note that
8898 we don't remove the piece though, since logically (ie
8899 as seen by opponent) the move hasn't been made yet. */
8900 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8901 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8902 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8903 corner.x, corner.y, squareSize, squareSize,
8904 0, 0); // [HGM] zh: unstack in stead of grab
8905 if(gatingPiece != EmptySquare) {
8906 /* Kludge alert: When gating we want the introduced
8907 piece to appear on the from square. To generate an
8908 image of it, we draw it on the board, copy the image,
8909 and draw the original piece again. */
8910 ChessSquare piece = boards[currentMove][boardY][boardX];
8911 DrawSquare(boardY, boardX, gatingPiece, 0);
8912 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8913 corner.x, corner.y, squareSize, squareSize, 0, 0);
8914 DrawSquare(boardY, boardX, piece, 0);
8916 damage[0][boardY][boardX] = True;
8918 player.dragActive = False;
8928 /* Are we animating? */
8929 if (!appData.animateDragging || appData.blindfold)
8933 if (! player.dragActive)
8935 /* Move piece, maintaining same relative position
8936 of mouse within square */
8937 corner.x = x - player.mouseDelta.x;
8938 corner.y = y - player.mouseDelta.y;
8939 AnimationFrame(&player, &corner, player.dragPiece);
8941 if (appData.highlightDragging) {
8943 BoardSquare(x, y, &boardX, &boardY);
8944 SetHighlights(fromX, fromY, boardX, boardY);
8953 int boardX, boardY, color;
8956 /* Are we animating? */
8957 if (!appData.animateDragging || appData.blindfold)
8961 if (! player.dragActive)
8963 /* Last frame in sequence is square piece is
8964 placed on, which may not match mouse exactly. */
8965 BoardSquare(x, y, &boardX, &boardY);
8966 ScreenSquare(boardX, boardY, &corner, &color);
8967 EndAnimation(&player, &corner);
8969 /* Be sure end square is redrawn */
8970 damage[0][boardY][boardX] = True;
8972 /* This prevents weird things happening with fast successive
8973 clicks which on my Sun at least can cause motion events
8974 without corresponding press/release. */
8975 player.dragActive = False;
8978 /* Handle expose event while piece being dragged */
8983 if (!player.dragActive || appData.blindfold)
8986 /* What we're doing: logically, the move hasn't been made yet,
8987 so the piece is still in it's original square. But visually
8988 it's being dragged around the board. So we erase the square
8989 that the piece is on and draw it at the last known drag point. */
8990 BlankSquare(player.startSquare.x, player.startSquare.y,
8991 player.startColor, EmptySquare, xBoardWindow, 1);
8992 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8993 damage[0][player.startBoardY][player.startBoardX] = TRUE;
8996 #include <sys/ioctl.h>
8997 int get_term_width()
8999 int fd, default_width;
9002 default_width = 79; // this is FICS default anyway...
9004 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
9006 if (!ioctl(fd, TIOCGSIZE, &win))
9007 default_width = win.ts_cols;
9008 #elif defined(TIOCGWINSZ)
9010 if (!ioctl(fd, TIOCGWINSZ, &win))
9011 default_width = win.ws_col;
9013 return default_width;
9019 static int old_width = 0;
9020 int new_width = get_term_width();
9022 if (old_width != new_width)
9023 ics_printf("set width %d\n", new_width);
9024 old_width = new_width;
9027 void NotifyFrontendLogin()
9032 /* [AS] Arrow highlighting support */
9034 static double A_WIDTH = 5; /* Width of arrow body */
9036 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
9037 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
9039 static double Sqr( double x )
9044 static int Round( double x )
9046 return (int) (x + 0.5);
9049 void SquareToPos(int rank, int file, int *x, int *y)
9052 *x = lineGap + ((BOARD_WIDTH-1)-file) * (squareSize + lineGap);
9053 *y = lineGap + rank * (squareSize + lineGap);
9055 *x = lineGap + file * (squareSize + lineGap);
9056 *y = lineGap + ((BOARD_HEIGHT-1)-rank) * (squareSize + lineGap);
9060 /* Draw an arrow between two points using current settings */
9061 void DrawArrowBetweenPoints( int s_x, int s_y, int d_x, int d_y )
9064 double dx, dy, j, k, x, y;
9067 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
9069 arrow[0].x = s_x + A_WIDTH + 0.5;
9072 arrow[1].x = s_x + A_WIDTH + 0.5;
9073 arrow[1].y = d_y - h;
9075 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9076 arrow[2].y = d_y - h;
9081 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
9082 arrow[5].y = d_y - h;
9084 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9085 arrow[4].y = d_y - h;
9087 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
9090 else if( d_y == s_y ) {
9091 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
9094 arrow[0].y = s_y + A_WIDTH + 0.5;
9096 arrow[1].x = d_x - w;
9097 arrow[1].y = s_y + A_WIDTH + 0.5;
9099 arrow[2].x = d_x - w;
9100 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9105 arrow[5].x = d_x - w;
9106 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
9108 arrow[4].x = d_x - w;
9109 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9112 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
9115 /* [AS] Needed a lot of paper for this! :-) */
9116 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
9117 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
9119 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
9121 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
9126 arrow[0].x = Round(x - j);
9127 arrow[0].y = Round(y + j*dx);
9129 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
9130 arrow[1].y = Round(arrow[0].y - 2*j*dx);
9133 x = (double) d_x - k;
9134 y = (double) d_y - k*dy;
9137 x = (double) d_x + k;
9138 y = (double) d_y + k*dy;
9141 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
9143 arrow[6].x = Round(x - j);
9144 arrow[6].y = Round(y + j*dx);
9146 arrow[2].x = Round(arrow[6].x + 2*j);
9147 arrow[2].y = Round(arrow[6].y - 2*j*dx);
9149 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
9150 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
9155 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
9156 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
9159 XFillPolygon(xDisplay, xBoardWindow, highlineGC, arrow, 7, Nonconvex, CoordModeOrigin);
9160 // Polygon( hdc, arrow, 7 );
9163 /* [AS] Draw an arrow between two squares */
9164 void DrawArrowBetweenSquares( int s_col, int s_row, int d_col, int d_row )
9166 int s_x, s_y, d_x, d_y, hor, vert, i;
9168 if( s_col == d_col && s_row == d_row ) {
9172 /* Get source and destination points */
9173 SquareToPos( s_row, s_col, &s_x, &s_y);
9174 SquareToPos( d_row, d_col, &d_x, &d_y);
9177 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
9179 else if( d_y < s_y ) {
9180 d_y += squareSize / 2 + squareSize / 4;
9183 d_y += squareSize / 2;
9187 d_x += squareSize / 2 - squareSize / 4;
9189 else if( d_x < s_x ) {
9190 d_x += squareSize / 2 + squareSize / 4;
9193 d_x += squareSize / 2;
9196 s_x += squareSize / 2;
9197 s_y += squareSize / 2;
9200 A_WIDTH = squareSize / 14.; //[HGM] make float
9202 DrawArrowBetweenPoints( s_x, s_y, d_x, d_y );
9204 hor = 64*s_col + 32; vert = 64*s_row + 32;
9205 for(i=0; i<= 64; i++) {
9206 damage[0][vert+6>>6][hor+6>>6] = True;
9207 damage[0][vert-6>>6][hor+6>>6] = True;
9208 damage[0][vert+6>>6][hor-6>>6] = True;
9209 damage[0][vert-6>>6][hor-6>>6] = True;
9210 hor += d_col - s_col; vert += d_row - s_row;
9214 Boolean IsDrawArrowEnabled()
9216 return appData.highlightMoveWithArrow && squareSize >= 32;
9219 void DrawArrowHighlight(int fromX, int fromY, int toX,int toY)
9221 if( IsDrawArrowEnabled() && fromX >= 0 && fromY >= 0 && toX >= 0 && toY >= 0)
9222 DrawArrowBetweenSquares(fromX, fromY, toX, toY);