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 OptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
454 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
455 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
456 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
457 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
458 void IcsOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
459 void SoundOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
460 void BoardOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
461 void LoadOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
462 void SaveOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
463 void GameListOptionsPopDown P(());
464 void ShufflePopDown P(());
465 void TimeControlPopDown 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 #define OPTIONSDIALOG
708 {N_("General ..."), "General", OptionsProc},
710 {N_("Time Control ... Alt+Shift+T"), "Time Control", TimeControlProc},
711 {N_("Common Engine ... Alt+Shift+U"), "Common Engine", UciMenuProc},
712 {N_("Adjudications ... Alt+Shift+J"), "Adjudications", EngineMenuProc},
713 {N_("ICS ..."), "ICS", IcsOptionsProc},
714 {N_("Load Game ..."), "Load Game", LoadOptionsProc},
715 {N_("Save Game ..."), "Save Game", SaveOptionsProc},
716 // {N_(" ..."), "", OptionsProc},
717 {N_("Game List ..."), "Game List", GameListOptionsPopUp},
718 {N_("Sounds ..."), "Sounds", SoundOptionsProc},
719 {"----", NULL, NothingProc},
720 #ifndef OPTIONSDIALOG
721 {N_("Always Queen Ctrl+Shift+Q"), "Always Queen", AlwaysQueenProc},
722 {N_("Animate Dragging"), "Animate Dragging", AnimateDraggingProc},
723 {N_("Animate Moving Ctrl+Shift+A"), "Animate Moving", AnimateMovingProc},
724 {N_("Auto Flag Ctrl+Shift+F"), "Auto Flag", AutoflagProc},
725 {N_("Auto Flip View"), "Auto Flip View", AutoflipProc},
726 {N_("Blindfold"), "Blindfold", BlindfoldProc},
727 {N_("Flash Moves"), "Flash Moves", FlashMovesProc},
729 {N_("Highlight Dragging"), "Highlight Dragging", HighlightDraggingProc},
731 {N_("Highlight Last Move"), "Highlight Last Move", HighlightLastMoveProc},
732 {N_("Highlight With Arrow"), "Arrow", HighlightArrowProc},
733 {N_("Move Sound"), "Move Sound", MoveSoundProc},
734 // {N_("ICS Alarm"), "ICS Alarm", IcsAlarmProc},
735 {N_("One-Click Moving"), "OneClick", OneClickProc},
736 {N_("Periodic Updates"), "Periodic Updates", PeriodicUpdatesProc},
737 {N_("Ponder Next Move Ctrl+Shift+P"), "Ponder Next Move", PonderNextMoveProc},
738 {N_("Popup Exit Message"), "Popup Exit Message", PopupExitMessageProc},
739 {N_("Popup Move Errors"), "Popup Move Errors", PopupMoveErrorsProc},
740 // {N_("Premove"), "Premove", PremoveProc},
741 {N_("Show Coords"), "Show Coords", ShowCoordsProc},
742 {N_("Hide Thinking Ctrl+Shift+H"), "Hide Thinking", HideThinkingProc},
743 {N_("Test Legality Ctrl+Shift+L"), "Test Legality", TestLegalityProc},
744 {"----", NULL, NothingProc},
746 {N_("Save Settings Now"), "Save Settings Now", SaveSettingsProc},
747 {N_("Save Settings on Exit"), "Save Settings on Exit", SaveOnExitProc},
751 MenuItem helpMenu[] = {
752 {N_("Info XBoard"), "Info XBoard", InfoProc},
753 {N_("Man XBoard F1"), "Man XBoard", ManProc},
754 {"----", NULL, NothingProc},
755 {N_("About XBoard"), "About XBoard", AboutProc},
760 {N_("File"), "File", fileMenu},
761 {N_("Edit"), "Edit", editMenu},
762 {N_("View"), "View", viewMenu},
763 {N_("Mode"), "Mode", modeMenu},
764 {N_("Action"), "Action", actionMenu},
765 {N_("Engine"), "Engine", engineMenu},
766 {N_("Options"), "Options", optionsMenu},
767 {N_("Help"), "Help", helpMenu},
771 #define PAUSE_BUTTON "P"
772 MenuItem buttonBar[] = {
773 {"<<", "<<", ToStartProc},
774 {"<", "<", BackwardProc},
775 {PAUSE_BUTTON, PAUSE_BUTTON, PauseProc},
776 {">", ">", ForwardProc},
777 {">>", ">>", ToEndProc},
781 #define PIECE_MENU_SIZE 18
782 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
783 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
784 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
785 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
786 N_("Empty square"), N_("Clear board") },
787 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
788 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
789 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
790 N_("Empty square"), N_("Clear board") }
792 /* must be in same order as PieceMenuStrings! */
793 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
794 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
795 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
796 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
797 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
798 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
799 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
800 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
801 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
804 #define DROP_MENU_SIZE 6
805 String dropMenuStrings[DROP_MENU_SIZE] = {
806 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
808 /* must be in same order as PieceMenuStrings! */
809 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
810 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
811 WhiteRook, WhiteQueen
819 DropMenuEnables dmEnables[] = {
837 { XtNborderWidth, 0 },
838 { XtNdefaultDistance, 0 },
842 { XtNborderWidth, 0 },
843 { XtNresizable, (XtArgVal) True },
847 { XtNborderWidth, 0 },
853 { XtNjustify, (XtArgVal) XtJustifyRight },
854 { XtNlabel, (XtArgVal) "..." },
855 { XtNresizable, (XtArgVal) True },
856 { XtNresize, (XtArgVal) False }
859 Arg messageArgs[] = {
860 { XtNjustify, (XtArgVal) XtJustifyLeft },
861 { XtNlabel, (XtArgVal) "..." },
862 { XtNresizable, (XtArgVal) True },
863 { XtNresize, (XtArgVal) False }
867 { XtNborderWidth, 0 },
868 { XtNjustify, (XtArgVal) XtJustifyLeft }
871 XtResource clientResources[] = {
872 { "flashCount", "flashCount", XtRInt, sizeof(int),
873 XtOffset(AppDataPtr, flashCount), XtRImmediate,
874 (XtPointer) FLASH_COUNT },
877 XrmOptionDescRec shellOptions[] = {
878 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
879 { "-flash", "flashCount", XrmoptionNoArg, "3" },
880 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
883 XtActionsRec boardActions[] = {
884 { "DrawPosition", DrawPositionProc },
885 { "HandleUserMove", HandleUserMove },
886 { "AnimateUserMove", AnimateUserMove },
887 { "HandlePV", HandlePV },
888 { "SelectPV", SelectPV },
889 { "StopPV", StopPV },
890 { "FileNameAction", FileNameAction },
891 { "AskQuestionProc", AskQuestionProc },
892 { "AskQuestionReplyAction", AskQuestionReplyAction },
893 { "PieceMenuPopup", PieceMenuPopup },
894 { "WhiteClock", WhiteClock },
895 { "BlackClock", BlackClock },
896 { "Iconify", Iconify },
897 { "ResetProc", ResetProc },
898 { "NewVariantProc", NewVariantProc },
899 { "LoadGameProc", LoadGameProc },
900 { "LoadNextGameProc", LoadNextGameProc },
901 { "LoadPrevGameProc", LoadPrevGameProc },
902 { "LoadSelectedProc", LoadSelectedProc },
903 { "SetFilterProc", SetFilterProc },
904 { "ReloadGameProc", ReloadGameProc },
905 { "LoadPositionProc", LoadPositionProc },
906 { "LoadNextPositionProc", LoadNextPositionProc },
907 { "LoadPrevPositionProc", LoadPrevPositionProc },
908 { "ReloadPositionProc", ReloadPositionProc },
909 { "CopyPositionProc", CopyPositionProc },
910 { "PastePositionProc", PastePositionProc },
911 { "CopyGameProc", CopyGameProc },
912 { "PasteGameProc", PasteGameProc },
913 { "SaveGameProc", SaveGameProc },
914 { "SavePositionProc", SavePositionProc },
915 { "MailMoveProc", MailMoveProc },
916 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
917 { "QuitProc", QuitProc },
918 { "MachineWhiteProc", MachineWhiteProc },
919 { "MachineBlackProc", MachineBlackProc },
920 { "AnalysisModeProc", AnalyzeModeProc },
921 { "AnalyzeFileProc", AnalyzeFileProc },
922 { "TwoMachinesProc", TwoMachinesProc },
923 { "IcsClientProc", IcsClientProc },
924 { "EditGameProc", EditGameProc },
925 { "EditPositionProc", EditPositionProc },
926 { "TrainingProc", EditPositionProc },
927 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
928 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
929 { "ShowGameListProc", ShowGameListProc },
930 { "ShowMoveListProc", HistoryShowProc},
931 { "EditTagsProc", EditCommentProc },
932 { "EditCommentProc", EditCommentProc },
933 { "IcsInputBoxProc", IcsInputBoxProc },
934 { "PauseProc", PauseProc },
935 { "AcceptProc", AcceptProc },
936 { "DeclineProc", DeclineProc },
937 { "RematchProc", RematchProc },
938 { "CallFlagProc", CallFlagProc },
939 { "DrawProc", DrawProc },
940 { "AdjournProc", AdjournProc },
941 { "AbortProc", AbortProc },
942 { "ResignProc", ResignProc },
943 { "AdjuWhiteProc", AdjuWhiteProc },
944 { "AdjuBlackProc", AdjuBlackProc },
945 { "AdjuDrawProc", AdjuDrawProc },
946 { "EnterKeyProc", EnterKeyProc },
947 { "UpKeyProc", UpKeyProc },
948 { "DownKeyProc", DownKeyProc },
949 { "StopObservingProc", StopObservingProc },
950 { "StopExaminingProc", StopExaminingProc },
951 { "UploadProc", UploadProc },
952 { "BackwardProc", BackwardProc },
953 { "ForwardProc", ForwardProc },
954 { "ToStartProc", ToStartProc },
955 { "ToEndProc", ToEndProc },
956 { "RevertProc", RevertProc },
957 { "AnnotateProc", AnnotateProc },
958 { "TruncateGameProc", TruncateGameProc },
959 { "MoveNowProc", MoveNowProc },
960 { "RetractMoveProc", RetractMoveProc },
961 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
962 { "UciMenuProc", (XtActionProc) UciMenuProc },
963 { "TimeControlProc", (XtActionProc) TimeControlProc },
964 { "FlipViewProc", FlipViewProc },
965 { "PonderNextMoveProc", PonderNextMoveProc },
966 #ifndef OPTIONSDIALOG
967 { "AlwaysQueenProc", AlwaysQueenProc },
968 { "AnimateDraggingProc", AnimateDraggingProc },
969 { "AnimateMovingProc", AnimateMovingProc },
970 { "AutoflagProc", AutoflagProc },
971 { "AutoflipProc", AutoflipProc },
972 { "BlindfoldProc", BlindfoldProc },
973 { "FlashMovesProc", FlashMovesProc },
975 { "HighlightDraggingProc", HighlightDraggingProc },
977 { "HighlightLastMoveProc", HighlightLastMoveProc },
978 // { "IcsAlarmProc", IcsAlarmProc },
979 { "MoveSoundProc", MoveSoundProc },
980 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
981 { "PopupExitMessageProc", PopupExitMessageProc },
982 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
983 // { "PremoveProc", PremoveProc },
984 { "ShowCoordsProc", ShowCoordsProc },
985 { "ShowThinkingProc", ShowThinkingProc },
986 { "HideThinkingProc", HideThinkingProc },
987 { "TestLegalityProc", TestLegalityProc },
989 { "SaveSettingsProc", SaveSettingsProc },
990 { "SaveOnExitProc", SaveOnExitProc },
991 { "InfoProc", InfoProc },
992 { "ManProc", ManProc },
993 { "HintProc", HintProc },
994 { "BookProc", BookProc },
995 { "AboutGameProc", AboutGameProc },
996 { "AboutProc", AboutProc },
997 { "DebugProc", DebugProc },
998 { "NothingProc", NothingProc },
999 { "CommentClick", (XtActionProc) CommentClick },
1000 { "CommentPopDown", (XtActionProc) CommentPopDown },
1001 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
1002 { "TagsPopDown", (XtActionProc) TagsPopDown },
1003 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
1004 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
1005 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
1006 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
1007 { "GameListPopDown", (XtActionProc) GameListPopDown },
1008 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
1009 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1010 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
1011 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1012 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1013 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
1014 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
1015 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
1016 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1019 char globalTranslations[] =
1020 ":<Key>F9: ResignProc() \n \
1021 :Ctrl<Key>n: ResetProc() \n \
1022 :Meta<Key>V: NewVariantProc() \n \
1023 :Ctrl<Key>o: LoadGameProc() \n \
1024 :Meta<Key>Next: LoadNextGameProc() \n \
1025 :Meta<Key>Prior: LoadPrevGameProc() \n \
1026 :Ctrl<Key>s: SaveGameProc() \n \
1027 :Ctrl<Key>c: CopyGameProc() \n \
1028 :Ctrl<Key>v: PasteGameProc() \n \
1029 :Ctrl<Key>O: LoadPositionProc() \n \
1030 :Shift<Key>Next: LoadNextPositionProc() \n \
1031 :Shift<Key>Prior: LoadPrevPositionProc() \n \
1032 :Ctrl<Key>S: SavePositionProc() \n \
1033 :Ctrl<Key>C: CopyPositionProc() \n \
1034 :Ctrl<Key>V: PastePositionProc() \n \
1035 :Ctrl<Key>q: QuitProc() \n \
1036 :Ctrl<Key>w: MachineWhiteProc() \n \
1037 :Ctrl<Key>b: MachineBlackProc() \n \
1038 :Ctrl<Key>t: TwoMachinesProc() \n \
1039 :Ctrl<Key>a: AnalysisModeProc() \n \
1040 :Ctrl<Key>f: AnalyzeFileProc() \n \
1041 :Ctrl<Key>e: EditGameProc() \n \
1042 :Ctrl<Key>E: EditPositionProc() \n \
1043 :Meta<Key>O: EngineOutputProc() \n \
1044 :Meta<Key>E: EvalGraphProc() \n \
1045 :Meta<Key>G: ShowGameListProc() \n \
1046 :Meta<Key>H: ShowMoveListProc() \n \
1047 :<Key>Pause: PauseProc() \n \
1048 :<Key>F3: AcceptProc() \n \
1049 :<Key>F4: DeclineProc() \n \
1050 :<Key>F12: RematchProc() \n \
1051 :<Key>F5: CallFlagProc() \n \
1052 :<Key>F6: DrawProc() \n \
1053 :<Key>F7: AdjournProc() \n \
1054 :<Key>F8: AbortProc() \n \
1055 :<Key>F10: StopObservingProc() \n \
1056 :<Key>F11: StopExaminingProc() \n \
1057 :Meta Ctrl<Key>F12: DebugProc() \n \
1058 :Meta<Key>End: ToEndProc() \n \
1059 :Meta<Key>Right: ForwardProc() \n \
1060 :Meta<Key>Home: ToStartProc() \n \
1061 :Meta<Key>Left: BackwardProc() \n \
1062 :<Key>Home: RevertProc() \n \
1063 :<Key>End: TruncateGameProc() \n \
1064 :Ctrl<Key>m: MoveNowProc() \n \
1065 :Ctrl<Key>x: RetractMoveProc() \n \
1066 :Meta<Key>J: EngineMenuProc() \n \
1067 :Meta<Key>U: UciMenuProc() \n \
1068 :Meta<Key>T: TimeControlProc() \n \
1069 :Ctrl<Key>P: PonderNextMoveProc() \n "
1070 #ifndef OPTIONSDIALOG
1072 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1073 :Ctrl<Key>F: AutoflagProc() \n \
1074 :Ctrl<Key>A: AnimateMovingProc() \n \
1075 :Ctrl<Key>L: TestLegalityProc() \n \
1076 :Ctrl<Key>H: HideThinkingProc() \n "
1079 :<Key>-: Iconify() \n \
1080 :<Key>F1: ManProc() \n \
1081 :<Key>F2: FlipViewProc() \n \
1082 <KeyDown>.: BackwardProc() \n \
1083 <KeyUp>.: ForwardProc() \n \
1084 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1085 \"Send to chess program:\",,1) \n \
1086 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1087 \"Send to second chess program:\",,2) \n";
1089 char boardTranslations[] =
1090 "<Btn1Down>: HandleUserMove(0) \n \
1091 Shift<Btn1Up>: HandleUserMove(1) \n \
1092 <Btn1Up>: HandleUserMove(0) \n \
1093 <Btn1Motion>: AnimateUserMove() \n \
1094 <Btn3Motion>: HandlePV() \n \
1095 <Btn3Up>: PieceMenuPopup(menuB) \n \
1096 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1097 PieceMenuPopup(menuB) \n \
1098 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1099 PieceMenuPopup(menuW) \n \
1100 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1101 PieceMenuPopup(menuW) \n \
1102 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1103 PieceMenuPopup(menuB) \n";
1105 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1106 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1108 char ICSInputTranslations[] =
1109 "<Key>Up: UpKeyProc() \n "
1110 "<Key>Down: DownKeyProc() \n "
1111 "<Key>Return: EnterKeyProc() \n";
1113 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1114 // as the widget is destroyed before the up-click can call extend-end
1115 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1117 String xboardResources[] = {
1118 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1119 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1120 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1125 /* Max possible square size */
1126 #define MAXSQSIZE 256
1128 static int xpm_avail[MAXSQSIZE];
1130 #ifdef HAVE_DIR_STRUCT
1132 /* Extract piece size from filename */
1134 xpm_getsize(name, len, ext)
1145 if ((p=strchr(name, '.')) == NULL ||
1146 StrCaseCmp(p+1, ext) != 0)
1152 while (*p && isdigit(*p))
1159 /* Setup xpm_avail */
1161 xpm_getavail(dirname, ext)
1169 for (i=0; i<MAXSQSIZE; ++i)
1172 if (appData.debugMode)
1173 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1175 dir = opendir(dirname);
1178 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1179 programName, dirname);
1183 while ((ent=readdir(dir)) != NULL) {
1184 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1185 if (i > 0 && i < MAXSQSIZE)
1195 xpm_print_avail(fp, ext)
1201 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1202 for (i=1; i<MAXSQSIZE; ++i) {
1208 /* Return XPM piecesize closest to size */
1210 xpm_closest_to(dirname, size, ext)
1216 int sm_diff = MAXSQSIZE;
1220 xpm_getavail(dirname, ext);
1222 if (appData.debugMode)
1223 xpm_print_avail(stderr, ext);
1225 for (i=1; i<MAXSQSIZE; ++i) {
1228 diff = (diff<0) ? -diff : diff;
1229 if (diff < sm_diff) {
1237 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1243 #else /* !HAVE_DIR_STRUCT */
1244 /* If we are on a system without a DIR struct, we can't
1245 read the directory, so we can't collect a list of
1246 filenames, etc., so we can't do any size-fitting. */
1248 xpm_closest_to(dirname, size, ext)
1253 fprintf(stderr, _("\
1254 Warning: No DIR structure found on this system --\n\
1255 Unable to autosize for XPM/XIM pieces.\n\
1256 Please report this error to frankm@hiwaay.net.\n\
1257 Include system type & operating system in message.\n"));
1260 #endif /* HAVE_DIR_STRUCT */
1262 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1263 "magenta", "cyan", "white" };
1267 TextColors textColors[(int)NColorClasses];
1269 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1271 parse_color(str, which)
1275 char *p, buf[100], *d;
1278 if (strlen(str) > 99) /* watch bounds on buf */
1283 for (i=0; i<which; ++i) {
1290 /* Could be looking at something like:
1292 .. in which case we want to stop on a comma also */
1293 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1297 return -1; /* Use default for empty field */
1300 if (which == 2 || isdigit(*p))
1303 while (*p && isalpha(*p))
1308 for (i=0; i<8; ++i) {
1309 if (!StrCaseCmp(buf, cnames[i]))
1310 return which? (i+40) : (i+30);
1312 if (!StrCaseCmp(buf, "default")) return -1;
1314 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1319 parse_cpair(cc, str)
1323 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1324 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1329 /* bg and attr are optional */
1330 textColors[(int)cc].bg = parse_color(str, 1);
1331 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1332 textColors[(int)cc].attr = 0;
1338 /* Arrange to catch delete-window events */
1339 Atom wm_delete_window;
1341 CatchDeleteWindow(Widget w, String procname)
1344 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1345 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1346 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1353 XtSetArg(args[0], XtNiconic, False);
1354 XtSetValues(shellWidget, args, 1);
1356 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1359 //---------------------------------------------------------------------------------------------------------
1360 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1363 #define CW_USEDEFAULT (1<<31)
1364 #define ICS_TEXT_MENU_SIZE 90
1365 #define DEBUG_FILE "xboard.debug"
1366 #define SetCurrentDirectory chdir
1367 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1371 // these two must some day move to frontend.h, when they are implemented
1372 Boolean GameListIsUp();
1374 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1377 // front-end part of option handling
1379 // [HGM] This platform-dependent table provides the location for storing the color info
1380 extern char *crWhite, * crBlack;
1384 &appData.whitePieceColor,
1385 &appData.blackPieceColor,
1386 &appData.lightSquareColor,
1387 &appData.darkSquareColor,
1388 &appData.highlightSquareColor,
1389 &appData.premoveHighlightColor,
1390 &appData.lowTimeWarningColor,
1401 // [HGM] font: keep a font for each square size, even non-stndard ones
1402 #define NUM_SIZES 18
1403 #define MAX_SIZE 130
1404 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1405 char *fontTable[NUM_FONTS][MAX_SIZE];
1408 ParseFont(char *name, int number)
1409 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1411 if(sscanf(name, "size%d:", &size)) {
1412 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1413 // defer processing it until we know if it matches our board size
1414 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1415 fontTable[number][size] = strdup(strchr(name, ':')+1);
1416 fontValid[number][size] = True;
1421 case 0: // CLOCK_FONT
1422 appData.clockFont = strdup(name);
1424 case 1: // MESSAGE_FONT
1425 appData.font = strdup(name);
1427 case 2: // COORD_FONT
1428 appData.coordFont = strdup(name);
1433 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1438 { // only 2 fonts currently
1439 appData.clockFont = CLOCK_FONT_NAME;
1440 appData.coordFont = COORD_FONT_NAME;
1441 appData.font = DEFAULT_FONT_NAME;
1446 { // no-op, until we identify the code for this already in XBoard and move it here
1450 ParseColor(int n, char *name)
1451 { // in XBoard, just copy the color-name string
1452 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1456 ParseTextAttribs(ColorClass cc, char *s)
1458 (&appData.colorShout)[cc] = strdup(s);
1462 ParseBoardSize(void *addr, char *name)
1464 appData.boardSize = strdup(name);
1469 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1473 SetCommPortDefaults()
1474 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1477 // [HGM] args: these three cases taken out to stay in front-end
1479 SaveFontArg(FILE *f, ArgDescriptor *ad)
1482 int i, n = (int)(intptr_t)ad->argLoc;
1484 case 0: // CLOCK_FONT
1485 name = appData.clockFont;
1487 case 1: // MESSAGE_FONT
1488 name = appData.font;
1490 case 2: // COORD_FONT
1491 name = appData.coordFont;
1496 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1497 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1498 fontTable[n][squareSize] = strdup(name);
1499 fontValid[n][squareSize] = True;
1502 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1503 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1508 { // nothing to do, as the sounds are at all times represented by their text-string names already
1512 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1513 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1514 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
1518 SaveColor(FILE *f, ArgDescriptor *ad)
1519 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1520 if(colorVariable[(int)(intptr_t)ad->argLoc])
1521 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
1525 SaveBoardSize(FILE *f, char *name, void *addr)
1526 { // wrapper to shield back-end from BoardSize & sizeInfo
1527 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1531 ParseCommPortSettings(char *s)
1532 { // no such option in XBoard (yet)
1535 extern Widget engineOutputShell;
1536 extern Widget tagsShell, editTagsShell;
1538 GetActualPlacement(Widget wg, WindowPlacement *wp)
1548 XtSetArg(args[i], XtNx, &x); i++;
1549 XtSetArg(args[i], XtNy, &y); i++;
1550 XtSetArg(args[i], XtNwidth, &w); i++;
1551 XtSetArg(args[i], XtNheight, &h); i++;
1552 XtGetValues(wg, args, i);
1561 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1562 // In XBoard this will have to wait until awareness of window parameters is implemented
1563 GetActualPlacement(shellWidget, &wpMain);
1564 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1565 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1566 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1567 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1568 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1569 else GetActualPlacement(editShell, &wpComment);
1570 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1571 else GetActualPlacement(editTagsShell, &wpTags);
1575 PrintCommPortSettings(FILE *f, char *name)
1576 { // This option does not exist in XBoard
1580 MySearchPath(char *installDir, char *name, char *fullname)
1581 { // just append installDir and name. Perhaps ExpandPath should be used here?
1582 name = ExpandPathName(name);
1583 if(name && name[0] == '/')
1584 safeStrCpy(fullname, name, MSG_SIZ );
1586 sprintf(fullname, "%s%c%s", installDir, '/', name);
1592 MyGetFullPathName(char *name, char *fullname)
1593 { // should use ExpandPath?
1594 name = ExpandPathName(name);
1595 safeStrCpy(fullname, name, MSG_SIZ );
1600 EnsureOnScreen(int *x, int *y, int minX, int minY)
1607 { // [HGM] args: allows testing if main window is realized from back-end
1608 return xBoardWindow != 0;
1612 PopUpStartupDialog()
1613 { // start menu not implemented in XBoard
1617 ConvertToLine(int argc, char **argv)
1619 static char line[128*1024], buf[1024];
1623 for(i=1; i<argc; i++)
1625 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1626 && argv[i][0] != '{' )
1627 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1629 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1630 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1633 line[strlen(line)-1] = NULLCHAR;
1637 //--------------------------------------------------------------------------------------------
1639 extern Boolean twoBoards, partnerUp;
1642 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1644 #define BoardSize int
1645 void InitDrawingSizes(BoardSize boardSize, int flags)
1646 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1647 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1649 XtGeometryResult gres;
1652 if(!formWidget) return;
1655 * Enable shell resizing.
1657 shellArgs[0].value = (XtArgVal) &w;
1658 shellArgs[1].value = (XtArgVal) &h;
1659 XtGetValues(shellWidget, shellArgs, 2);
1661 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1662 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1663 XtSetValues(shellWidget, &shellArgs[2], 4);
1665 XtSetArg(args[0], XtNdefaultDistance, &sep);
1666 XtGetValues(formWidget, args, 1);
1668 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1669 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1670 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1672 hOffset = boardWidth + 10;
1673 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1674 secondSegments[i] = gridSegments[i];
1675 secondSegments[i].x1 += hOffset;
1676 secondSegments[i].x2 += hOffset;
1679 XtSetArg(args[0], XtNwidth, boardWidth);
1680 XtSetArg(args[1], XtNheight, boardHeight);
1681 XtSetValues(boardWidget, args, 2);
1683 timerWidth = (boardWidth - sep) / 2;
1684 XtSetArg(args[0], XtNwidth, timerWidth);
1685 XtSetValues(whiteTimerWidget, args, 1);
1686 XtSetValues(blackTimerWidget, args, 1);
1688 XawFormDoLayout(formWidget, False);
1690 if (appData.titleInWindow) {
1692 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1693 XtSetArg(args[i], XtNheight, &h); i++;
1694 XtGetValues(titleWidget, args, i);
1696 w = boardWidth - 2*bor;
1698 XtSetArg(args[0], XtNwidth, &w);
1699 XtGetValues(menuBarWidget, args, 1);
1700 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1703 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1704 if (gres != XtGeometryYes && appData.debugMode) {
1706 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1707 programName, gres, w, h, wr, hr);
1711 XawFormDoLayout(formWidget, True);
1714 * Inhibit shell resizing.
1716 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1717 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1718 shellArgs[4].value = shellArgs[2].value = w;
1719 shellArgs[5].value = shellArgs[3].value = h;
1720 XtSetValues(shellWidget, &shellArgs[0], 6);
1722 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1725 for(i=0; i<4; i++) {
1727 for(p=0; p<=(int)WhiteKing; p++)
1728 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1729 if(gameInfo.variant == VariantShogi) {
1730 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1731 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1732 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1733 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1734 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1737 if(gameInfo.variant == VariantGothic) {
1738 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1741 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1742 xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
1743 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1746 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1747 for(p=0; p<=(int)WhiteKing; p++)
1748 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1749 if(gameInfo.variant == VariantShogi) {
1750 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1751 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1752 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1753 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1754 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1757 if(gameInfo.variant == VariantGothic) {
1758 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1761 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1762 ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
1763 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1768 for(i=0; i<2; i++) {
1770 for(p=0; p<=(int)WhiteKing; p++)
1771 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1772 if(gameInfo.variant == VariantShogi) {
1773 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1774 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1775 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1776 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1777 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1780 if(gameInfo.variant == VariantGothic) {
1781 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1784 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1785 pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
1786 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1796 void ParseIcsTextColors()
1797 { // [HGM] tken out of main(), so it can be called from ICS-Options dialog
1798 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1799 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1800 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1801 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1802 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1803 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1804 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1805 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1806 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1807 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1809 if (appData.colorize) {
1811 _("%s: can't parse color names; disabling colorization\n"),
1814 appData.colorize = FALSE;
1819 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
1820 XrmValue vFrom, vTo;
1821 int forceMono = False;
1823 if (!appData.monoMode) {
1824 vFrom.addr = (caddr_t) appData.lightSquareColor;
1825 vFrom.size = strlen(appData.lightSquareColor);
1826 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1827 if (vTo.addr == NULL) {
1828 appData.monoMode = True;
1831 lightSquareColor = *(Pixel *) vTo.addr;
1834 if (!appData.monoMode) {
1835 vFrom.addr = (caddr_t) appData.darkSquareColor;
1836 vFrom.size = strlen(appData.darkSquareColor);
1837 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1838 if (vTo.addr == NULL) {
1839 appData.monoMode = True;
1842 darkSquareColor = *(Pixel *) vTo.addr;
1845 if (!appData.monoMode) {
1846 vFrom.addr = (caddr_t) appData.whitePieceColor;
1847 vFrom.size = strlen(appData.whitePieceColor);
1848 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1849 if (vTo.addr == NULL) {
1850 appData.monoMode = True;
1853 whitePieceColor = *(Pixel *) vTo.addr;
1856 if (!appData.monoMode) {
1857 vFrom.addr = (caddr_t) appData.blackPieceColor;
1858 vFrom.size = strlen(appData.blackPieceColor);
1859 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1860 if (vTo.addr == NULL) {
1861 appData.monoMode = True;
1864 blackPieceColor = *(Pixel *) vTo.addr;
1868 if (!appData.monoMode) {
1869 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1870 vFrom.size = strlen(appData.highlightSquareColor);
1871 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1872 if (vTo.addr == NULL) {
1873 appData.monoMode = True;
1876 highlightSquareColor = *(Pixel *) vTo.addr;
1880 if (!appData.monoMode) {
1881 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1882 vFrom.size = strlen(appData.premoveHighlightColor);
1883 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1884 if (vTo.addr == NULL) {
1885 appData.monoMode = True;
1888 premoveHighlightColor = *(Pixel *) vTo.addr;
1899 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1900 XSetWindowAttributes window_attributes;
1902 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1903 XrmValue vFrom, vTo;
1904 XtGeometryResult gres;
1907 int forceMono = False;
1909 srandom(time(0)); // [HGM] book: make random truly random
1911 setbuf(stdout, NULL);
1912 setbuf(stderr, NULL);
1915 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1916 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1920 programName = strrchr(argv[0], '/');
1921 if (programName == NULL)
1922 programName = argv[0];
1927 XtSetLanguageProc(NULL, NULL, NULL);
1928 bindtextdomain(PACKAGE, LOCALEDIR);
1929 textdomain(PACKAGE);
1933 XtAppInitialize(&appContext, "XBoard", shellOptions,
1934 XtNumber(shellOptions),
1935 &argc, argv, xboardResources, NULL, 0);
1936 appData.boardSize = "";
1937 InitAppData(ConvertToLine(argc, argv));
1939 if (p == NULL) p = "/tmp";
1940 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1941 gameCopyFilename = (char*) malloc(i);
1942 gamePasteFilename = (char*) malloc(i);
1943 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1944 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1946 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1947 clientResources, XtNumber(clientResources),
1950 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1951 static char buf[MSG_SIZ];
1952 EscapeExpand(buf, appData.initString);
1953 appData.initString = strdup(buf);
1954 EscapeExpand(buf, appData.secondInitString);
1955 appData.secondInitString = strdup(buf);
1956 EscapeExpand(buf, appData.firstComputerString);
1957 appData.firstComputerString = strdup(buf);
1958 EscapeExpand(buf, appData.secondComputerString);
1959 appData.secondComputerString = strdup(buf);
1962 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1965 if (chdir(chessDir) != 0) {
1966 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1972 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1973 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1974 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1975 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1978 setbuf(debugFP, NULL);
1981 /* [HGM,HR] make sure board size is acceptable */
1982 if(appData.NrFiles > BOARD_FILES ||
1983 appData.NrRanks > BOARD_RANKS )
1984 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1987 /* This feature does not work; animation needs a rewrite */
1988 appData.highlightDragging = FALSE;
1992 xDisplay = XtDisplay(shellWidget);
1993 xScreen = DefaultScreen(xDisplay);
1994 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1996 gameInfo.variant = StringToVariant(appData.variant);
1997 InitPosition(FALSE);
2000 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
2002 if (isdigit(appData.boardSize[0])) {
2003 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
2004 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
2005 &fontPxlSize, &smallLayout, &tinyLayout);
2007 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
2008 programName, appData.boardSize);
2012 /* Find some defaults; use the nearest known size */
2013 SizeDefaults *szd, *nearest;
2014 int distance = 99999;
2015 nearest = szd = sizeDefaults;
2016 while (szd->name != NULL) {
2017 if (abs(szd->squareSize - squareSize) < distance) {
2019 distance = abs(szd->squareSize - squareSize);
2020 if (distance == 0) break;
2024 if (i < 2) lineGap = nearest->lineGap;
2025 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
2026 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
2027 if (i < 5) fontPxlSize = nearest->fontPxlSize;
2028 if (i < 6) smallLayout = nearest->smallLayout;
2029 if (i < 7) tinyLayout = nearest->tinyLayout;
2032 SizeDefaults *szd = sizeDefaults;
2033 if (*appData.boardSize == NULLCHAR) {
2034 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
2035 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
2038 if (szd->name == NULL) szd--;
2039 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
2041 while (szd->name != NULL &&
2042 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
2043 if (szd->name == NULL) {
2044 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
2045 programName, appData.boardSize);
2049 squareSize = szd->squareSize;
2050 lineGap = szd->lineGap;
2051 clockFontPxlSize = szd->clockFontPxlSize;
2052 coordFontPxlSize = szd->coordFontPxlSize;
2053 fontPxlSize = szd->fontPxlSize;
2054 smallLayout = szd->smallLayout;
2055 tinyLayout = szd->tinyLayout;
2056 // [HGM] font: use defaults from settings file if available and not overruled
2058 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
2059 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
2060 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
2061 appData.font = fontTable[MESSAGE_FONT][squareSize];
2062 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
2063 appData.coordFont = fontTable[COORD_FONT][squareSize];
2065 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
2066 if (strlen(appData.pixmapDirectory) > 0) {
2067 p = ExpandPathName(appData.pixmapDirectory);
2069 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
2070 appData.pixmapDirectory);
2073 if (appData.debugMode) {
2074 fprintf(stderr, _("\
2075 XBoard square size (hint): %d\n\
2076 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
2078 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
2079 if (appData.debugMode) {
2080 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
2083 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
2085 /* [HR] height treated separately (hacked) */
2086 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
2087 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
2088 if (appData.showJail == 1) {
2089 /* Jail on top and bottom */
2090 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2091 XtSetArg(boardArgs[2], XtNheight,
2092 boardHeight + 2*(lineGap + squareSize));
2093 } else if (appData.showJail == 2) {
2095 XtSetArg(boardArgs[1], XtNwidth,
2096 boardWidth + 2*(lineGap + squareSize));
2097 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2100 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2101 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2105 * Determine what fonts to use.
2107 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2108 clockFontID = XLoadFont(xDisplay, appData.clockFont);
2109 clockFontStruct = XQueryFont(xDisplay, clockFontID);
2110 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2111 coordFontID = XLoadFont(xDisplay, appData.coordFont);
2112 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2113 appData.font = FindFont(appData.font, fontPxlSize);
2114 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
2115 countFontStruct = XQueryFont(xDisplay, countFontID);
2116 // appData.font = FindFont(appData.font, fontPxlSize);
2118 xdb = XtDatabase(xDisplay);
2119 XrmPutStringResource(&xdb, "*font", appData.font);
2122 * Detect if there are not enough colors available and adapt.
2124 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2125 appData.monoMode = True;
2128 forceMono = MakeColors();
2131 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2134 if (appData.bitmapDirectory == NULL ||
2135 appData.bitmapDirectory[0] == NULLCHAR)
2136 appData.bitmapDirectory = DEF_BITMAP_DIR;
2139 if (appData.lowTimeWarning && !appData.monoMode) {
2140 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2141 vFrom.size = strlen(appData.lowTimeWarningColor);
2142 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2143 if (vTo.addr == NULL)
2144 appData.monoMode = True;
2146 lowTimeWarningColor = *(Pixel *) vTo.addr;
2149 if (appData.monoMode && appData.debugMode) {
2150 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2151 (unsigned long) XWhitePixel(xDisplay, xScreen),
2152 (unsigned long) XBlackPixel(xDisplay, xScreen));
2155 ParseIcsTextColors();
2156 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2157 textColors[ColorNone].attr = 0;
2159 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2165 layoutName = "tinyLayout";
2166 } else if (smallLayout) {
2167 layoutName = "smallLayout";
2169 layoutName = "normalLayout";
2171 /* Outer layoutWidget is there only to provide a name for use in
2172 resources that depend on the layout style */
2174 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2175 layoutArgs, XtNumber(layoutArgs));
2177 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2178 formArgs, XtNumber(formArgs));
2179 XtSetArg(args[0], XtNdefaultDistance, &sep);
2180 XtGetValues(formWidget, args, 1);
2183 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2184 XtSetArg(args[0], XtNtop, XtChainTop);
2185 XtSetArg(args[1], XtNbottom, XtChainTop);
2186 XtSetArg(args[2], XtNright, XtChainLeft);
2187 XtSetValues(menuBarWidget, args, 3);
2189 widgetList[j++] = whiteTimerWidget =
2190 XtCreateWidget("whiteTime", labelWidgetClass,
2191 formWidget, timerArgs, XtNumber(timerArgs));
2192 XtSetArg(args[0], XtNfont, clockFontStruct);
2193 XtSetArg(args[1], XtNtop, XtChainTop);
2194 XtSetArg(args[2], XtNbottom, XtChainTop);
2195 XtSetValues(whiteTimerWidget, args, 3);
2197 widgetList[j++] = blackTimerWidget =
2198 XtCreateWidget("blackTime", labelWidgetClass,
2199 formWidget, timerArgs, XtNumber(timerArgs));
2200 XtSetArg(args[0], XtNfont, clockFontStruct);
2201 XtSetArg(args[1], XtNtop, XtChainTop);
2202 XtSetArg(args[2], XtNbottom, XtChainTop);
2203 XtSetValues(blackTimerWidget, args, 3);
2205 if (appData.titleInWindow) {
2206 widgetList[j++] = titleWidget =
2207 XtCreateWidget("title", labelWidgetClass, formWidget,
2208 titleArgs, XtNumber(titleArgs));
2209 XtSetArg(args[0], XtNtop, XtChainTop);
2210 XtSetArg(args[1], XtNbottom, XtChainTop);
2211 XtSetValues(titleWidget, args, 2);
2214 if (appData.showButtonBar) {
2215 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2216 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2217 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2218 XtSetArg(args[2], XtNtop, XtChainTop);
2219 XtSetArg(args[3], XtNbottom, XtChainTop);
2220 XtSetValues(buttonBarWidget, args, 4);
2223 widgetList[j++] = messageWidget =
2224 XtCreateWidget("message", labelWidgetClass, formWidget,
2225 messageArgs, XtNumber(messageArgs));
2226 XtSetArg(args[0], XtNtop, XtChainTop);
2227 XtSetArg(args[1], XtNbottom, XtChainTop);
2228 XtSetValues(messageWidget, args, 2);
2230 widgetList[j++] = boardWidget =
2231 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2232 XtNumber(boardArgs));
2234 XtManageChildren(widgetList, j);
2236 timerWidth = (boardWidth - sep) / 2;
2237 XtSetArg(args[0], XtNwidth, timerWidth);
2238 XtSetValues(whiteTimerWidget, args, 1);
2239 XtSetValues(blackTimerWidget, args, 1);
2241 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2242 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2243 XtGetValues(whiteTimerWidget, args, 2);
2245 if (appData.showButtonBar) {
2246 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2247 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2248 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2252 * formWidget uses these constraints but they are stored
2256 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2257 XtSetValues(menuBarWidget, args, i);
2258 if (appData.titleInWindow) {
2261 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2262 XtSetValues(whiteTimerWidget, args, i);
2264 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2265 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2266 XtSetValues(blackTimerWidget, args, i);
2268 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2269 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2270 XtSetValues(titleWidget, args, i);
2272 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2273 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2274 XtSetValues(messageWidget, args, i);
2275 if (appData.showButtonBar) {
2277 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2278 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2279 XtSetValues(buttonBarWidget, args, i);
2283 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2284 XtSetValues(whiteTimerWidget, args, i);
2286 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2287 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2288 XtSetValues(blackTimerWidget, args, i);
2290 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2291 XtSetValues(titleWidget, args, i);
2293 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2294 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2295 XtSetValues(messageWidget, args, i);
2296 if (appData.showButtonBar) {
2298 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2299 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2300 XtSetValues(buttonBarWidget, args, i);
2305 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2306 XtSetValues(whiteTimerWidget, args, i);
2308 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2309 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2310 XtSetValues(blackTimerWidget, args, i);
2312 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2313 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2314 XtSetValues(messageWidget, args, i);
2315 if (appData.showButtonBar) {
2317 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2318 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2319 XtSetValues(buttonBarWidget, args, i);
2323 XtSetArg(args[0], XtNfromVert, messageWidget);
2324 XtSetArg(args[1], XtNtop, XtChainTop);
2325 XtSetArg(args[2], XtNbottom, XtChainBottom);
2326 XtSetArg(args[3], XtNleft, XtChainLeft);
2327 XtSetArg(args[4], XtNright, XtChainRight);
2328 XtSetValues(boardWidget, args, 5);
2330 XtRealizeWidget(shellWidget);
2333 XtSetArg(args[0], XtNx, wpMain.x);
2334 XtSetArg(args[1], XtNy, wpMain.y);
2335 XtSetValues(shellWidget, args, 2);
2339 * Correct the width of the message and title widgets.
2340 * It is not known why some systems need the extra fudge term.
2341 * The value "2" is probably larger than needed.
2343 XawFormDoLayout(formWidget, False);
2345 #define WIDTH_FUDGE 2
2347 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2348 XtSetArg(args[i], XtNheight, &h); i++;
2349 XtGetValues(messageWidget, args, i);
2350 if (appData.showButtonBar) {
2352 XtSetArg(args[i], XtNwidth, &w); i++;
2353 XtGetValues(buttonBarWidget, args, i);
2354 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2356 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2359 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2360 if (gres != XtGeometryYes && appData.debugMode) {
2361 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2362 programName, gres, w, h, wr, hr);
2365 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2366 /* The size used for the child widget in layout lags one resize behind
2367 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2369 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2370 if (gres != XtGeometryYes && appData.debugMode) {
2371 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2372 programName, gres, w, h, wr, hr);
2375 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2376 XtSetArg(args[1], XtNright, XtChainRight);
2377 XtSetValues(messageWidget, args, 2);
2379 if (appData.titleInWindow) {
2381 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2382 XtSetArg(args[i], XtNheight, &h); i++;
2383 XtGetValues(titleWidget, args, i);
2385 w = boardWidth - 2*bor;
2387 XtSetArg(args[0], XtNwidth, &w);
2388 XtGetValues(menuBarWidget, args, 1);
2389 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2392 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2393 if (gres != XtGeometryYes && appData.debugMode) {
2395 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2396 programName, gres, w, h, wr, hr);
2399 XawFormDoLayout(formWidget, True);
2401 xBoardWindow = XtWindow(boardWidget);
2403 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2404 // not need to go into InitDrawingSizes().
2408 * Create X checkmark bitmap and initialize option menu checks.
2410 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2411 checkmark_bits, checkmark_width, checkmark_height);
2412 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2413 #ifndef OPTIONSDIALOG
2414 if (appData.alwaysPromoteToQueen) {
2415 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2418 if (appData.animateDragging) {
2419 XtSetValues(XtNameToWidget(menuBarWidget,
2420 "menuOptions.Animate Dragging"),
2423 if (appData.animate) {
2424 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2427 if (appData.autoCallFlag) {
2428 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2431 if (appData.autoFlipView) {
2432 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2435 if (appData.blindfold) {
2436 XtSetValues(XtNameToWidget(menuBarWidget,
2437 "menuOptions.Blindfold"), args, 1);
2439 if (appData.flashCount > 0) {
2440 XtSetValues(XtNameToWidget(menuBarWidget,
2441 "menuOptions.Flash Moves"),
2445 if (appData.highlightDragging) {
2446 XtSetValues(XtNameToWidget(menuBarWidget,
2447 "menuOptions.Highlight Dragging"),
2451 if (appData.highlightLastMove) {
2452 XtSetValues(XtNameToWidget(menuBarWidget,
2453 "menuOptions.Highlight Last Move"),
2456 if (appData.highlightMoveWithArrow) {
2457 XtSetValues(XtNameToWidget(menuBarWidget,
2458 "menuOptions.Arrow"),
2461 // if (appData.icsAlarm) {
2462 // XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2465 if (appData.ringBellAfterMoves) {
2466 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2469 if (appData.oneClick) {
2470 XtSetValues(XtNameToWidget(menuBarWidget,
2471 "menuOptions.OneClick"), args, 1);
2473 if (appData.periodicUpdates) {
2474 XtSetValues(XtNameToWidget(menuBarWidget,
2475 "menuOptions.Periodic Updates"), args, 1);
2477 if (appData.ponderNextMove) {
2478 XtSetValues(XtNameToWidget(menuBarWidget,
2479 "menuOptions.Ponder Next Move"), args, 1);
2481 if (appData.popupExitMessage) {
2482 XtSetValues(XtNameToWidget(menuBarWidget,
2483 "menuOptions.Popup Exit Message"), args, 1);
2485 if (appData.popupMoveErrors) {
2486 XtSetValues(XtNameToWidget(menuBarWidget,
2487 "menuOptions.Popup Move Errors"), args, 1);
2489 // if (appData.premove) {
2490 // XtSetValues(XtNameToWidget(menuBarWidget,
2491 // "menuOptions.Premove"), args, 1);
2493 if (appData.showCoords) {
2494 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2497 if (appData.hideThinkingFromHuman) {
2498 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2501 if (appData.testLegality) {
2502 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2506 if (saveSettingsOnExit) {
2507 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2514 ReadBitmap(&wIconPixmap, "icon_white.bm",
2515 icon_white_bits, icon_white_width, icon_white_height);
2516 ReadBitmap(&bIconPixmap, "icon_black.bm",
2517 icon_black_bits, icon_black_width, icon_black_height);
2518 iconPixmap = wIconPixmap;
2520 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2521 XtSetValues(shellWidget, args, i);
2524 * Create a cursor for the board widget.
2526 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2527 XChangeWindowAttributes(xDisplay, xBoardWindow,
2528 CWCursor, &window_attributes);
2531 * Inhibit shell resizing.
2533 shellArgs[0].value = (XtArgVal) &w;
2534 shellArgs[1].value = (XtArgVal) &h;
2535 XtGetValues(shellWidget, shellArgs, 2);
2536 shellArgs[4].value = shellArgs[2].value = w;
2537 shellArgs[5].value = shellArgs[3].value = h;
2538 XtSetValues(shellWidget, &shellArgs[2], 4);
2539 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2540 marginH = h - boardHeight;
2542 CatchDeleteWindow(shellWidget, "QuitProc");
2547 if (appData.bitmapDirectory[0] != NULLCHAR) {
2551 CreateXPMBoard(appData.liteBackTextureFile, 1);
2552 CreateXPMBoard(appData.darkBackTextureFile, 0);
2556 /* Create regular pieces */
2557 if (!useImages) CreatePieces();
2562 if (appData.animate || appData.animateDragging)
2565 XtAugmentTranslations(formWidget,
2566 XtParseTranslationTable(globalTranslations));
2567 XtAugmentTranslations(boardWidget,
2568 XtParseTranslationTable(boardTranslations));
2569 XtAugmentTranslations(whiteTimerWidget,
2570 XtParseTranslationTable(whiteTranslations));
2571 XtAugmentTranslations(blackTimerWidget,
2572 XtParseTranslationTable(blackTranslations));
2574 /* Why is the following needed on some versions of X instead
2575 * of a translation? */
2576 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2577 (XtEventHandler) EventProc, NULL);
2580 /* [AS] Restore layout */
2581 if( wpMoveHistory.visible ) {
2585 if( wpEvalGraph.visible )
2590 if( wpEngineOutput.visible ) {
2591 EngineOutputPopUp();
2596 if (errorExitStatus == -1) {
2597 if (appData.icsActive) {
2598 /* We now wait until we see "login:" from the ICS before
2599 sending the logon script (problems with timestamp otherwise) */
2600 /*ICSInitScript();*/
2601 if (appData.icsInputBox) ICSInputBoxPopUp();
2605 signal(SIGWINCH, TermSizeSigHandler);
2607 signal(SIGINT, IntSigHandler);
2608 signal(SIGTERM, IntSigHandler);
2609 if (*appData.cmailGameName != NULLCHAR) {
2610 signal(SIGUSR1, CmailSigHandler);
2613 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2615 XtSetKeyboardFocus(shellWidget, formWidget);
2617 XtAppMainLoop(appContext);
2618 if (appData.debugMode) fclose(debugFP); // [DM] debug
2625 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2626 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2628 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2629 unlink(gameCopyFilename);
2630 unlink(gamePasteFilename);
2633 RETSIGTYPE TermSizeSigHandler(int sig)
2646 CmailSigHandler(sig)
2652 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2654 /* Activate call-back function CmailSigHandlerCallBack() */
2655 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2657 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2661 CmailSigHandlerCallBack(isr, closure, message, count, error)
2669 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2671 /**** end signal code ****/
2677 /* try to open the icsLogon script, either in the location given
2678 * or in the users HOME directory
2685 f = fopen(appData.icsLogon, "r");
2688 homedir = getenv("HOME");
2689 if (homedir != NULL)
2691 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2692 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2693 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2694 f = fopen(buf, "r");
2699 ProcessICSInitScript(f);
2701 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2710 EditCommentPopDown();
2725 if (!menuBarWidget) return;
2726 w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2728 DisplayError("menuEdit.Revert", 0);
2730 XtSetSensitive(w, !grey);
2732 w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2734 DisplayError("menuEdit.Annotate", 0);
2736 XtSetSensitive(w, !grey);
2741 SetMenuEnables(enab)
2745 if (!menuBarWidget) return;
2746 while (enab->name != NULL) {
2747 w = XtNameToWidget(menuBarWidget, enab->name);
2749 DisplayError(enab->name, 0);
2751 XtSetSensitive(w, enab->value);
2757 Enables icsEnables[] = {
2758 { "menuFile.Mail Move", False },
2759 { "menuFile.Reload CMail Message", False },
2760 { "menuMode.Machine Black", False },
2761 { "menuMode.Machine White", False },
2762 { "menuMode.Analysis Mode", False },
2763 { "menuMode.Analyze File", False },
2764 { "menuMode.Two Machines", False },
2766 { "menuEngine.Hint", False },
2767 { "menuEngine.Book", False },
2768 { "menuEngine.Move Now", False },
2769 #ifndef OPTIONSDIALOG
2770 { "menuOptions.Periodic Updates", False },
2771 { "menuOptions.Hide Thinking", False },
2772 { "menuOptions.Ponder Next Move", False },
2774 { "menuEngine.Engine #1 Settings", False },
2776 { "menuEngine.Engine #2 Settings", False },
2777 { "menuEdit.Annotate", False },
2781 Enables ncpEnables[] = {
2782 { "menuFile.Mail Move", False },
2783 { "menuFile.Reload CMail Message", False },
2784 { "menuMode.Machine White", False },
2785 { "menuMode.Machine Black", False },
2786 { "menuMode.Analysis Mode", False },
2787 { "menuMode.Analyze File", False },
2788 { "menuMode.Two Machines", False },
2789 { "menuMode.ICS Client", False },
2790 { "menuView.ICS Input Box", False },
2791 { "Action", False },
2792 { "menuEdit.Revert", False },
2793 { "menuEdit.Annotate", False },
2794 { "menuEngine.Engine #1 Settings", False },
2795 { "menuEngine.Engine #2 Settings", False },
2796 { "menuEngine.Move Now", False },
2797 { "menuEngine.Retract Move", False },
2798 #ifndef OPTIONSDIALOG
2799 { "menuOptions.Auto Flag", False },
2800 { "menuOptions.Auto Flip View", False },
2801 { "menuOptions.ICS", False },
2802 // { "menuOptions.ICS Alarm", False },
2803 { "menuOptions.Move Sound", False },
2804 { "menuOptions.Hide Thinking", False },
2805 { "menuOptions.Periodic Updates", False },
2806 { "menuOptions.Ponder Next Move", False },
2808 { "menuEngine.Hint", False },
2809 { "menuEngine.Book", False },
2813 Enables gnuEnables[] = {
2814 { "menuMode.ICS Client", False },
2815 { "menuView.ICS Input Box", False },
2816 { "menuAction.Accept", False },
2817 { "menuAction.Decline", False },
2818 { "menuAction.Rematch", False },
2819 { "menuAction.Adjourn", False },
2820 { "menuAction.Stop Examining", False },
2821 { "menuAction.Stop Observing", False },
2822 { "menuAction.Upload to Examine", False },
2823 { "menuEdit.Revert", False },
2824 { "menuEdit.Annotate", False },
2825 { "menuOptions.ICS", False },
2827 /* The next two options rely on SetCmailMode being called *after* */
2828 /* SetGNUMode so that when GNU is being used to give hints these */
2829 /* menu options are still available */
2831 { "menuFile.Mail Move", False },
2832 { "menuFile.Reload CMail Message", False },
2836 Enables cmailEnables[] = {
2838 { "menuAction.Call Flag", False },
2839 { "menuAction.Draw", True },
2840 { "menuAction.Adjourn", False },
2841 { "menuAction.Abort", False },
2842 { "menuAction.Stop Observing", False },
2843 { "menuAction.Stop Examining", False },
2844 { "menuFile.Mail Move", True },
2845 { "menuFile.Reload CMail Message", True },
2849 Enables trainingOnEnables[] = {
2850 { "menuMode.Edit Comment", False },
2851 { "menuMode.Pause", False },
2852 { "menuEdit.Forward", False },
2853 { "menuEdit.Backward", False },
2854 { "menuEdit.Forward to End", False },
2855 { "menuEdit.Back to Start", False },
2856 { "menuEngine.Move Now", False },
2857 { "menuEdit.Truncate Game", False },
2861 Enables trainingOffEnables[] = {
2862 { "menuMode.Edit Comment", True },
2863 { "menuMode.Pause", True },
2864 { "menuEdit.Forward", True },
2865 { "menuEdit.Backward", True },
2866 { "menuEdit.Forward to End", True },
2867 { "menuEdit.Back to Start", True },
2868 { "menuEngine.Move Now", True },
2869 { "menuEdit.Truncate Game", True },
2873 Enables machineThinkingEnables[] = {
2874 { "menuFile.Load Game", False },
2875 // { "menuFile.Load Next Game", False },
2876 // { "menuFile.Load Previous Game", False },
2877 // { "menuFile.Reload Same Game", False },
2878 { "menuEdit.Paste Game", False },
2879 { "menuFile.Load Position", False },
2880 // { "menuFile.Load Next Position", False },
2881 // { "menuFile.Load Previous Position", False },
2882 // { "menuFile.Reload Same Position", False },
2883 { "menuEdit.Paste Position", False },
2884 { "menuMode.Machine White", False },
2885 { "menuMode.Machine Black", False },
2886 { "menuMode.Two Machines", False },
2887 { "menuEngine.Retract Move", False },
2891 Enables userThinkingEnables[] = {
2892 { "menuFile.Load Game", True },
2893 // { "menuFile.Load Next Game", True },
2894 // { "menuFile.Load Previous Game", True },
2895 // { "menuFile.Reload Same Game", True },
2896 { "menuEdit.Paste Game", True },
2897 { "menuFile.Load Position", True },
2898 // { "menuFile.Load Next Position", True },
2899 // { "menuFile.Load Previous Position", True },
2900 // { "menuFile.Reload Same Position", True },
2901 { "menuEdit.Paste Position", True },
2902 { "menuMode.Machine White", True },
2903 { "menuMode.Machine Black", True },
2904 { "menuMode.Two Machines", True },
2905 { "menuEngine.Retract Move", True },
2911 SetMenuEnables(icsEnables);
2914 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2915 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2922 SetMenuEnables(ncpEnables);
2928 SetMenuEnables(gnuEnables);
2934 SetMenuEnables(cmailEnables);
2940 SetMenuEnables(trainingOnEnables);
2941 if (appData.showButtonBar) {
2942 XtSetSensitive(buttonBarWidget, False);
2948 SetTrainingModeOff()
2950 SetMenuEnables(trainingOffEnables);
2951 if (appData.showButtonBar) {
2952 XtSetSensitive(buttonBarWidget, True);
2957 SetUserThinkingEnables()
2959 if (appData.noChessProgram) return;
2960 SetMenuEnables(userThinkingEnables);
2964 SetMachineThinkingEnables()
2966 if (appData.noChessProgram) return;
2967 SetMenuEnables(machineThinkingEnables);
2969 case MachinePlaysBlack:
2970 case MachinePlaysWhite:
2971 case TwoMachinesPlay:
2972 XtSetSensitive(XtNameToWidget(menuBarWidget,
2973 ModeToWidgetName(gameMode)), True);
2980 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2981 #define HISTORY_SIZE 64
2982 static char *history[HISTORY_SIZE];
2983 int histIn = 0, histP = 0;
2986 SaveInHistory(char *cmd)
2988 if (history[histIn] != NULL) {
2989 free(history[histIn]);
2990 history[histIn] = NULL;
2992 if (*cmd == NULLCHAR) return;
2993 history[histIn] = StrSave(cmd);
2994 histIn = (histIn + 1) % HISTORY_SIZE;
2995 if (history[histIn] != NULL) {
2996 free(history[histIn]);
2997 history[histIn] = NULL;
3003 PrevInHistory(char *cmd)
3006 if (histP == histIn) {
3007 if (history[histIn] != NULL) free(history[histIn]);
3008 history[histIn] = StrSave(cmd);
3010 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
3011 if (newhp == histIn || history[newhp] == NULL) return NULL;
3013 return history[histP];
3019 if (histP == histIn) return NULL;
3020 histP = (histP + 1) % HISTORY_SIZE;
3021 return history[histP];
3023 // end of borrowed code
3025 #define Abs(n) ((n)<0 ? -(n) : (n))
3028 * Find a font that matches "pattern" that is as close as
3029 * possible to the targetPxlSize. Prefer fonts that are k
3030 * pixels smaller to fonts that are k pixels larger. The
3031 * pattern must be in the X Consortium standard format,
3032 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3033 * The return value should be freed with XtFree when no
3037 FindFont(pattern, targetPxlSize)
3041 char **fonts, *p, *best, *scalable, *scalableTail;
3042 int i, j, nfonts, minerr, err, pxlSize;
3045 char **missing_list;
3047 char *def_string, *base_fnt_lst, strInt[3];
3049 XFontStruct **fnt_list;
3051 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3052 snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
3053 p = strstr(pattern, "--");
3054 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3055 strcat(base_fnt_lst, strInt);
3056 strcat(base_fnt_lst, strchr(p + 2, '-'));
3058 if ((fntSet = XCreateFontSet(xDisplay,
3062 &def_string)) == NULL) {
3064 fprintf(stderr, _("Unable to create font set.\n"));
3068 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3070 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3072 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3073 programName, pattern);
3081 for (i=0; i<nfonts; i++) {
3084 if (*p != '-') continue;
3086 if (*p == NULLCHAR) break;
3087 if (*p++ == '-') j++;
3089 if (j < 7) continue;
3092 scalable = fonts[i];
3095 err = pxlSize - targetPxlSize;
3096 if (Abs(err) < Abs(minerr) ||
3097 (minerr > 0 && err < 0 && -err == minerr)) {
3103 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3104 /* If the error is too big and there is a scalable font,
3105 use the scalable font. */
3106 int headlen = scalableTail - scalable;
3107 p = (char *) XtMalloc(strlen(scalable) + 10);
3108 while (isdigit(*scalableTail)) scalableTail++;
3109 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3111 p = (char *) XtMalloc(strlen(best) + 2);
3112 safeStrCpy(p, best, strlen(best)+1 );
3114 if (appData.debugMode) {
3115 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3116 pattern, targetPxlSize, p);
3119 if (missing_count > 0)
3120 XFreeStringList(missing_list);
3121 XFreeFontSet(xDisplay, fntSet);
3123 XFreeFontNames(fonts);
3129 { // [HGM] deletes GCs that are to be remade, to prevent resource leak;
3130 // must be called before all non-first callse to CreateGCs()
3131 XtReleaseGC(shellWidget, highlineGC);
3132 XtReleaseGC(shellWidget, lightSquareGC);
3133 XtReleaseGC(shellWidget, darkSquareGC);
3134 if (appData.monoMode) {
3135 if (DefaultDepth(xDisplay, xScreen) == 1) {
3136 XtReleaseGC(shellWidget, wbPieceGC);
3138 XtReleaseGC(shellWidget, bwPieceGC);
3141 XtReleaseGC(shellWidget, prelineGC);
3142 XtReleaseGC(shellWidget, jailSquareGC);
3143 XtReleaseGC(shellWidget, wdPieceGC);
3144 XtReleaseGC(shellWidget, wlPieceGC);
3145 XtReleaseGC(shellWidget, wjPieceGC);
3146 XtReleaseGC(shellWidget, bdPieceGC);
3147 XtReleaseGC(shellWidget, blPieceGC);
3148 XtReleaseGC(shellWidget, bjPieceGC);
3152 void CreateGCs(int redo)
3154 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3155 | GCBackground | GCFunction | GCPlaneMask;
3156 XGCValues gc_values;
3159 gc_values.plane_mask = AllPlanes;
3160 gc_values.line_width = lineGap;
3161 gc_values.line_style = LineSolid;
3162 gc_values.function = GXcopy;
3165 DeleteGCs(); // called a second time; clean up old GCs first
3166 } else { // [HGM] grid and font GCs created on first call only
3167 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3168 gc_values.background = XBlackPixel(xDisplay, xScreen);
3169 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3171 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3172 gc_values.background = XWhitePixel(xDisplay, xScreen);
3173 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3174 XSetFont(xDisplay, coordGC, coordFontID);
3176 // [HGM] make font for holdings counts (white on black)
3177 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3178 gc_values.background = XBlackPixel(xDisplay, xScreen);
3179 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3180 XSetFont(xDisplay, countGC, countFontID);
3182 if (appData.monoMode) {
3183 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3184 gc_values.background = XWhitePixel(xDisplay, xScreen);
3185 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3187 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3188 gc_values.background = XBlackPixel(xDisplay, xScreen);
3189 lightSquareGC = wbPieceGC
3190 = XtGetGC(shellWidget, value_mask, &gc_values);
3192 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3193 gc_values.background = XWhitePixel(xDisplay, xScreen);
3194 darkSquareGC = bwPieceGC
3195 = XtGetGC(shellWidget, value_mask, &gc_values);
3197 if (DefaultDepth(xDisplay, xScreen) == 1) {
3198 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3199 gc_values.function = GXcopyInverted;
3200 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3201 gc_values.function = GXcopy;
3202 if (XBlackPixel(xDisplay, xScreen) == 1) {
3203 bwPieceGC = darkSquareGC;
3204 wbPieceGC = copyInvertedGC;
3206 bwPieceGC = copyInvertedGC;
3207 wbPieceGC = lightSquareGC;
3211 gc_values.foreground = highlightSquareColor;
3212 gc_values.background = highlightSquareColor;
3213 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3215 gc_values.foreground = premoveHighlightColor;
3216 gc_values.background = premoveHighlightColor;
3217 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3219 gc_values.foreground = lightSquareColor;
3220 gc_values.background = darkSquareColor;
3221 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3223 gc_values.foreground = darkSquareColor;
3224 gc_values.background = lightSquareColor;
3225 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3227 gc_values.foreground = jailSquareColor;
3228 gc_values.background = jailSquareColor;
3229 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3231 gc_values.foreground = whitePieceColor;
3232 gc_values.background = darkSquareColor;
3233 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3235 gc_values.foreground = whitePieceColor;
3236 gc_values.background = lightSquareColor;
3237 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3239 gc_values.foreground = whitePieceColor;
3240 gc_values.background = jailSquareColor;
3241 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3243 gc_values.foreground = blackPieceColor;
3244 gc_values.background = darkSquareColor;
3245 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3247 gc_values.foreground = blackPieceColor;
3248 gc_values.background = lightSquareColor;
3249 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3251 gc_values.foreground = blackPieceColor;
3252 gc_values.background = jailSquareColor;
3253 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3257 void loadXIM(xim, xmask, filename, dest, mask)
3270 fp = fopen(filename, "rb");
3272 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3279 for (y=0; y<h; ++y) {
3280 for (x=0; x<h; ++x) {
3285 XPutPixel(xim, x, y, blackPieceColor);
3287 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3290 XPutPixel(xim, x, y, darkSquareColor);
3292 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3295 XPutPixel(xim, x, y, whitePieceColor);
3297 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3300 XPutPixel(xim, x, y, lightSquareColor);
3302 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3310 /* create Pixmap of piece */
3311 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3313 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3316 /* create Pixmap of clipmask
3317 Note: We assume the white/black pieces have the same
3318 outline, so we make only 6 masks. This is okay
3319 since the XPM clipmask routines do the same. */
3321 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3323 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3326 /* now create the 1-bit version */
3327 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3330 values.foreground = 1;
3331 values.background = 0;
3333 /* Don't use XtGetGC, not read only */
3334 maskGC = XCreateGC(xDisplay, *mask,
3335 GCForeground | GCBackground, &values);
3336 XCopyPlane(xDisplay, temp, *mask, maskGC,
3337 0, 0, squareSize, squareSize, 0, 0, 1);
3338 XFreePixmap(xDisplay, temp);
3343 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3345 void CreateXIMPieces()
3350 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3355 /* The XSynchronize calls were copied from CreatePieces.
3356 Not sure if needed, but can't hurt */
3357 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3360 /* temp needed by loadXIM() */
3361 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3362 0, 0, ss, ss, AllPlanes, XYPixmap);
3364 if (strlen(appData.pixmapDirectory) == 0) {
3368 if (appData.monoMode) {
3369 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3373 fprintf(stderr, _("\nLoading XIMs...\n"));
3375 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3376 fprintf(stderr, "%d", piece+1);
3377 for (kind=0; kind<4; kind++) {
3378 fprintf(stderr, ".");
3379 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3380 ExpandPathName(appData.pixmapDirectory),
3381 piece <= (int) WhiteKing ? "" : "w",
3382 pieceBitmapNames[piece],
3384 ximPieceBitmap[kind][piece] =
3385 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3386 0, 0, ss, ss, AllPlanes, XYPixmap);
3387 if (appData.debugMode)
3388 fprintf(stderr, _("(File:%s:) "), buf);
3389 loadXIM(ximPieceBitmap[kind][piece],
3391 &(xpmPieceBitmap2[kind][piece]),
3392 &(ximMaskPm2[piece]));
3393 if(piece <= (int)WhiteKing)
3394 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3396 fprintf(stderr," ");
3398 /* Load light and dark squares */
3399 /* If the LSQ and DSQ pieces don't exist, we will
3400 draw them with solid squares. */
3401 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3402 if (access(buf, 0) != 0) {
3406 fprintf(stderr, _("light square "));
3408 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3409 0, 0, ss, ss, AllPlanes, XYPixmap);
3410 if (appData.debugMode)
3411 fprintf(stderr, _("(File:%s:) "), buf);
3413 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3414 fprintf(stderr, _("dark square "));
3415 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3416 ExpandPathName(appData.pixmapDirectory), ss);
3417 if (appData.debugMode)
3418 fprintf(stderr, _("(File:%s:) "), buf);
3420 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3421 0, 0, ss, ss, AllPlanes, XYPixmap);
3422 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3423 xpmJailSquare = xpmLightSquare;
3425 fprintf(stderr, _("Done.\n"));
3427 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3431 void CreateXPMBoard(char *s, int kind)
3435 if(s == NULL || *s == 0 || *s == '*') { useTexture &= ~(kind+1); return; }
3436 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3437 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3441 void FreeXPMPieces()
3442 { // [HGM] to prevent resoucre leak on calling CreaeXPMPieces() a second time,
3443 // thisroutine has to be called t free the old piece pixmaps
3445 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++)
3446 for (kind=0; kind<4; kind++) XFreePixmap(xDisplay, xpmPieceBitmap2[kind][piece]);
3448 XFreePixmap(xDisplay, xpmLightSquare);
3449 XFreePixmap(xDisplay, xpmDarkSquare);
3453 void CreateXPMPieces()
3457 u_int ss = squareSize;
3459 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3460 XpmColorSymbol symbols[4];
3461 static int redo = False;
3463 if(redo) FreeXPMPieces(); else redo = 1;
3465 /* The XSynchronize calls were copied from CreatePieces.
3466 Not sure if needed, but can't hurt */
3467 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3469 /* Setup translations so piece colors match square colors */
3470 symbols[0].name = "light_piece";
3471 symbols[0].value = appData.whitePieceColor;
3472 symbols[1].name = "dark_piece";
3473 symbols[1].value = appData.blackPieceColor;
3474 symbols[2].name = "light_square";
3475 symbols[2].value = appData.lightSquareColor;
3476 symbols[3].name = "dark_square";
3477 symbols[3].value = appData.darkSquareColor;
3479 attr.valuemask = XpmColorSymbols;
3480 attr.colorsymbols = symbols;
3481 attr.numsymbols = 4;
3483 if (appData.monoMode) {
3484 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3488 if (strlen(appData.pixmapDirectory) == 0) {
3489 XpmPieces* pieces = builtInXpms;
3492 while (pieces->size != squareSize && pieces->size) pieces++;
3493 if (!pieces->size) {
3494 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3497 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3498 for (kind=0; kind<4; kind++) {
3500 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3501 pieces->xpm[piece][kind],
3502 &(xpmPieceBitmap2[kind][piece]),
3503 NULL, &attr)) != 0) {
3504 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3508 if(piece <= (int) WhiteKing)
3509 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3513 xpmJailSquare = xpmLightSquare;
3517 fprintf(stderr, _("\nLoading XPMs...\n"));
3520 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3521 fprintf(stderr, "%d ", piece+1);
3522 for (kind=0; kind<4; kind++) {
3523 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3524 ExpandPathName(appData.pixmapDirectory),
3525 piece > (int) WhiteKing ? "w" : "",
3526 pieceBitmapNames[piece],
3528 if (appData.debugMode) {
3529 fprintf(stderr, _("(File:%s:) "), buf);
3531 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3532 &(xpmPieceBitmap2[kind][piece]),
3533 NULL, &attr)) != 0) {
3534 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3535 // [HGM] missing: read of unorthodox piece failed; substitute King.
3536 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3537 ExpandPathName(appData.pixmapDirectory),
3539 if (appData.debugMode) {
3540 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3542 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3543 &(xpmPieceBitmap2[kind][piece]),
3547 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3552 if(piece <= (int) WhiteKing)
3553 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3556 /* Load light and dark squares */
3557 /* If the LSQ and DSQ pieces don't exist, we will
3558 draw them with solid squares. */
3559 fprintf(stderr, _("light square "));
3560 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3561 if (access(buf, 0) != 0) {
3565 if (appData.debugMode)
3566 fprintf(stderr, _("(File:%s:) "), buf);
3568 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3569 &xpmLightSquare, NULL, &attr)) != 0) {
3570 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3573 fprintf(stderr, _("dark square "));
3574 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3575 ExpandPathName(appData.pixmapDirectory), ss);
3576 if (appData.debugMode) {
3577 fprintf(stderr, _("(File:%s:) "), buf);
3579 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3580 &xpmDarkSquare, NULL, &attr)) != 0) {
3581 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3585 xpmJailSquare = xpmLightSquare;
3586 fprintf(stderr, _("Done.\n"));
3588 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3591 #endif /* HAVE_LIBXPM */
3594 /* No built-in bitmaps */
3599 u_int ss = squareSize;
3601 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3604 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3605 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3606 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3607 pieceBitmapNames[piece],
3608 ss, kind == SOLID ? 's' : 'o');
3609 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3610 if(piece <= (int)WhiteKing)
3611 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3615 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3619 /* With built-in bitmaps */
3622 BuiltInBits* bib = builtInBits;
3625 u_int ss = squareSize;
3627 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3630 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3632 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3633 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3634 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3635 pieceBitmapNames[piece],
3636 ss, kind == SOLID ? 's' : 'o');
3637 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3638 bib->bits[kind][piece], ss, ss);
3639 if(piece <= (int)WhiteKing)
3640 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3644 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3649 void ReadBitmap(pm, name, bits, wreq, hreq)
3652 unsigned char bits[];
3658 char msg[MSG_SIZ], fullname[MSG_SIZ];
3660 if (*appData.bitmapDirectory != NULLCHAR) {
3661 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3662 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3663 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3664 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3665 &w, &h, pm, &x_hot, &y_hot);
3666 fprintf(stderr, "load %s\n", name);
3667 if (errcode != BitmapSuccess) {
3669 case BitmapOpenFailed:
3670 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3672 case BitmapFileInvalid:
3673 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3675 case BitmapNoMemory:
3676 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3680 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3684 fprintf(stderr, _("%s: %s...using built-in\n"),
3686 } else if (w != wreq || h != hreq) {
3688 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3689 programName, fullname, w, h, wreq, hreq);
3695 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3704 if (lineGap == 0) return;
3706 /* [HR] Split this into 2 loops for non-square boards. */
3708 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3709 gridSegments[i].x1 = 0;
3710 gridSegments[i].x2 =
3711 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3712 gridSegments[i].y1 = gridSegments[i].y2
3713 = lineGap / 2 + (i * (squareSize + lineGap));
3716 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3717 gridSegments[j + i].y1 = 0;
3718 gridSegments[j + i].y2 =
3719 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3720 gridSegments[j + i].x1 = gridSegments[j + i].x2
3721 = lineGap / 2 + (j * (squareSize + lineGap));
3725 static void MenuBarSelect(w, addr, index)
3730 XtActionProc proc = (XtActionProc) addr;
3732 (proc)(NULL, NULL, NULL, NULL);
3735 void CreateMenuBarPopup(parent, name, mb)
3745 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3748 XtSetArg(args[j], XtNleftMargin, 20); j++;
3749 XtSetArg(args[j], XtNrightMargin, 20); j++;
3751 while (mi->string != NULL) {
3752 if (strcmp(mi->string, "----") == 0) {
3753 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3756 XtSetArg(args[j], XtNlabel, XtNewString(mi->string));
3757 entry = XtCreateManagedWidget(mi->ref, smeBSBObjectClass,
3759 XtAddCallback(entry, XtNcallback,
3760 (XtCallbackProc) MenuBarSelect,
3761 (caddr_t) mi->proc);
3767 Widget CreateMenuBar(mb)
3771 Widget anchor, menuBar;
3773 char menuName[MSG_SIZ];
3776 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3777 XtSetArg(args[j], XtNvSpace, 0); j++;
3778 XtSetArg(args[j], XtNborderWidth, 0); j++;
3779 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3780 formWidget, args, j);
3782 while (mb->name != NULL) {
3783 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3784 strncat(menuName, mb->ref, MSG_SIZ - strlen(menuName) - 1);
3786 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3789 shortName[0] = mb->name[0];
3790 shortName[1] = NULLCHAR;
3791 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3794 XtSetArg(args[j], XtNlabel, XtNewString(mb->name)); j++;
3797 XtSetArg(args[j], XtNborderWidth, 0); j++;
3798 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3800 CreateMenuBarPopup(menuBar, menuName, mb);
3806 Widget CreateButtonBar(mi)
3810 Widget button, buttonBar;
3814 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3816 XtSetArg(args[j], XtNhSpace, 0); j++;
3818 XtSetArg(args[j], XtNborderWidth, 0); j++;
3819 XtSetArg(args[j], XtNvSpace, 0); j++;
3820 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3821 formWidget, args, j);
3823 while (mi->string != NULL) {
3826 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3827 XtSetArg(args[j], XtNborderWidth, 0); j++;
3829 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3830 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3831 buttonBar, args, j);
3832 XtAddCallback(button, XtNcallback,
3833 (XtCallbackProc) MenuBarSelect,
3834 (caddr_t) mi->proc);
3841 CreatePieceMenu(name, color)
3848 ChessSquare selection;
3850 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3851 boardWidget, args, 0);
3853 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3854 String item = pieceMenuStrings[color][i];
3856 if (strcmp(item, "----") == 0) {
3857 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3860 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3861 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3863 selection = pieceMenuTranslation[color][i];
3864 XtAddCallback(entry, XtNcallback,
3865 (XtCallbackProc) PieceMenuSelect,
3866 (caddr_t) selection);
3867 if (selection == WhitePawn || selection == BlackPawn) {
3868 XtSetArg(args[0], XtNpopupOnEntry, entry);
3869 XtSetValues(menu, args, 1);
3882 ChessSquare selection;
3884 whitePieceMenu = CreatePieceMenu("menuW", 0);
3885 blackPieceMenu = CreatePieceMenu("menuB", 1);
3887 XtRegisterGrabAction(PieceMenuPopup, True,
3888 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3889 GrabModeAsync, GrabModeAsync);
3891 XtSetArg(args[0], XtNlabel, _("Drop"));
3892 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3893 boardWidget, args, 1);
3894 for (i = 0; i < DROP_MENU_SIZE; i++) {
3895 String item = dropMenuStrings[i];
3897 if (strcmp(item, "----") == 0) {
3898 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3901 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3902 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3904 selection = dropMenuTranslation[i];
3905 XtAddCallback(entry, XtNcallback,
3906 (XtCallbackProc) DropMenuSelect,
3907 (caddr_t) selection);
3912 void SetupDropMenu()
3920 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3921 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3922 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3923 dmEnables[i].piece);
3924 XtSetSensitive(entry, p != NULL || !appData.testLegality
3925 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3926 && !appData.icsActive));
3928 while (p && *p++ == dmEnables[i].piece) count++;
3929 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3931 XtSetArg(args[j], XtNlabel, label); j++;
3932 XtSetValues(entry, args, j);
3936 void PieceMenuPopup(w, event, params, num_params)
3940 Cardinal *num_params;
3942 String whichMenu; int menuNr;
3943 if (event->type == ButtonRelease)
3944 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3945 else if (event->type == ButtonPress)
3946 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3948 case 0: whichMenu = params[0]; break;
3949 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3951 case -1: if (errorUp) ErrorPopDown();
3954 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3957 static void PieceMenuSelect(w, piece, junk)
3962 if (pmFromX < 0 || pmFromY < 0) return;
3963 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3966 static void DropMenuSelect(w, piece, junk)
3971 if (pmFromX < 0 || pmFromY < 0) return;
3972 DropMenuEvent(piece, pmFromX, pmFromY);
3975 void WhiteClock(w, event, prms, nprms)
3984 void BlackClock(w, event, prms, nprms)
3995 * If the user selects on a border boundary, return -1; if off the board,
3996 * return -2. Otherwise map the event coordinate to the square.
3998 int EventToSquare(x, limit)
4006 if ((x % (squareSize + lineGap)) >= squareSize)
4008 x /= (squareSize + lineGap);
4014 static void do_flash_delay(msec)
4020 static void drawHighlight(file, rank, gc)
4026 if (lineGap == 0) return;
4029 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
4030 (squareSize + lineGap);
4031 y = lineGap/2 + rank * (squareSize + lineGap);
4033 x = lineGap/2 + file * (squareSize + lineGap);
4034 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
4035 (squareSize + lineGap);
4038 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
4039 squareSize+lineGap, squareSize+lineGap);
4042 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
4043 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4046 SetHighlights(fromX, fromY, toX, toY)
4047 int fromX, fromY, toX, toY;
4049 if (hi1X != fromX || hi1Y != fromY) {
4050 if (hi1X >= 0 && hi1Y >= 0) {
4051 drawHighlight(hi1X, hi1Y, lineGC);
4053 } // [HGM] first erase both, then draw new!
4054 if (hi2X != toX || hi2Y != toY) {
4055 if (hi2X >= 0 && hi2Y >= 0) {
4056 drawHighlight(hi2X, hi2Y, lineGC);
4059 if (hi1X != fromX || hi1Y != fromY) {
4060 if (fromX >= 0 && fromY >= 0) {
4061 drawHighlight(fromX, fromY, highlineGC);
4064 if (hi2X != toX || hi2Y != toY) {
4065 if (toX >= 0 && toY >= 0) {
4066 drawHighlight(toX, toY, highlineGC);
4078 SetHighlights(-1, -1, -1, -1);
4083 SetPremoveHighlights(fromX, fromY, toX, toY)
4084 int fromX, fromY, toX, toY;
4086 if (pm1X != fromX || pm1Y != fromY) {
4087 if (pm1X >= 0 && pm1Y >= 0) {
4088 drawHighlight(pm1X, pm1Y, lineGC);
4090 if (fromX >= 0 && fromY >= 0) {
4091 drawHighlight(fromX, fromY, prelineGC);
4094 if (pm2X != toX || pm2Y != toY) {
4095 if (pm2X >= 0 && pm2Y >= 0) {
4096 drawHighlight(pm2X, pm2Y, lineGC);
4098 if (toX >= 0 && toY >= 0) {
4099 drawHighlight(toX, toY, prelineGC);
4109 ClearPremoveHighlights()
4111 SetPremoveHighlights(-1, -1, -1, -1);
4114 static int CutOutSquare(x, y, x0, y0, kind)
4115 int x, y, *x0, *y0, kind;
4117 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
4118 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
4120 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
4121 if(textureW[kind] < W*squareSize)
4122 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
4124 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
4125 if(textureH[kind] < H*squareSize)
4126 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
4128 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
4132 static void BlankSquare(x, y, color, piece, dest, fac)
4133 int x, y, color, fac;
4136 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
4138 if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
4139 XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
4140 squareSize, squareSize, x*fac, y*fac);
4142 if (useImages && useImageSqs) {
4146 pm = xpmLightSquare;
4151 case 2: /* neutral */
4156 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4157 squareSize, squareSize, x*fac, y*fac);
4167 case 2: /* neutral */
4172 XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
4177 I split out the routines to draw a piece so that I could
4178 make a generic flash routine.
4180 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4182 int square_color, x, y;
4185 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4186 switch (square_color) {
4188 case 2: /* neutral */
4190 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4191 ? *pieceToOutline(piece)
4192 : *pieceToSolid(piece),
4193 dest, bwPieceGC, 0, 0,
4194 squareSize, squareSize, x, y);
4197 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4198 ? *pieceToSolid(piece)
4199 : *pieceToOutline(piece),
4200 dest, wbPieceGC, 0, 0,
4201 squareSize, squareSize, x, y);
4206 static void monoDrawPiece(piece, square_color, x, y, dest)
4208 int square_color, x, y;
4211 switch (square_color) {
4213 case 2: /* neutral */
4215 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4216 ? *pieceToOutline(piece)
4217 : *pieceToSolid(piece),
4218 dest, bwPieceGC, 0, 0,
4219 squareSize, squareSize, x, y, 1);
4222 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4223 ? *pieceToSolid(piece)
4224 : *pieceToOutline(piece),
4225 dest, wbPieceGC, 0, 0,
4226 squareSize, squareSize, x, y, 1);
4231 static void colorDrawPiece(piece, square_color, x, y, dest)
4233 int square_color, x, y;
4236 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4237 switch (square_color) {
4239 XCopyPlane(xDisplay, *pieceToSolid(piece),
4240 dest, (int) piece < (int) BlackPawn
4241 ? wlPieceGC : blPieceGC, 0, 0,
4242 squareSize, squareSize, x, y, 1);
4245 XCopyPlane(xDisplay, *pieceToSolid(piece),
4246 dest, (int) piece < (int) BlackPawn
4247 ? wdPieceGC : bdPieceGC, 0, 0,
4248 squareSize, squareSize, x, y, 1);
4250 case 2: /* neutral */
4252 XCopyPlane(xDisplay, *pieceToSolid(piece),
4253 dest, (int) piece < (int) BlackPawn
4254 ? wjPieceGC : bjPieceGC, 0, 0,
4255 squareSize, squareSize, x, y, 1);
4260 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4262 int square_color, x, y;
4265 int kind, p = piece;
4267 switch (square_color) {
4269 case 2: /* neutral */
4271 if ((int)piece < (int) BlackPawn) {
4279 if ((int)piece < (int) BlackPawn) {
4287 if(appData.upsideDown && flipView) { kind ^= 2; p += p < BlackPawn ? BlackPawn : -BlackPawn; }// swap white and black pieces
4288 if(useTexture & square_color+1) {
4289 BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
4290 XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
4291 XSetClipOrigin(xDisplay, wlPieceGC, x, y);
4292 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);
4293 XSetClipMask(xDisplay, wlPieceGC, None);
4294 XSetClipOrigin(xDisplay, wlPieceGC, 0, 0);
4296 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4297 dest, wlPieceGC, 0, 0,
4298 squareSize, squareSize, x, y);
4301 typedef void (*DrawFunc)();
4303 DrawFunc ChooseDrawFunc()
4305 if (appData.monoMode) {
4306 if (DefaultDepth(xDisplay, xScreen) == 1) {
4307 return monoDrawPiece_1bit;
4309 return monoDrawPiece;
4313 return colorDrawPieceImage;
4315 return colorDrawPiece;
4319 /* [HR] determine square color depending on chess variant. */
4320 static int SquareColor(row, column)
4325 if (gameInfo.variant == VariantXiangqi) {
4326 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4328 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4330 } else if (row <= 4) {
4336 square_color = ((column + row) % 2) == 1;
4339 /* [hgm] holdings: next line makes all holdings squares light */
4340 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4342 return square_color;
4345 void DrawSquare(row, column, piece, do_flash)
4346 int row, column, do_flash;
4349 int square_color, x, y, direction, font_ascent, font_descent;
4352 XCharStruct overall;
4356 /* Calculate delay in milliseconds (2-delays per complete flash) */
4357 flash_delay = 500 / appData.flashRate;
4360 x = lineGap + ((BOARD_WIDTH-1)-column) *
4361 (squareSize + lineGap);
4362 y = lineGap + row * (squareSize + lineGap);
4364 x = lineGap + column * (squareSize + lineGap);
4365 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4366 (squareSize + lineGap);
4369 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4371 square_color = SquareColor(row, column);
4373 if ( // [HGM] holdings: blank out area between board and holdings
4374 column == BOARD_LEFT-1 || column == BOARD_RGHT
4375 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4376 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4377 BlankSquare(x, y, 2, EmptySquare, xBoardWindow, 1);
4379 // [HGM] print piece counts next to holdings
4380 string[1] = NULLCHAR;
4381 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4382 string[0] = '0' + piece;
4383 XTextExtents(countFontStruct, string, 1, &direction,
4384 &font_ascent, &font_descent, &overall);
4385 if (appData.monoMode) {
4386 XDrawImageString(xDisplay, xBoardWindow, countGC,
4387 x + squareSize - overall.width - 2,
4388 y + font_ascent + 1, string, 1);
4390 XDrawString(xDisplay, xBoardWindow, countGC,
4391 x + squareSize - overall.width - 2,
4392 y + font_ascent + 1, string, 1);
4395 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4396 string[0] = '0' + piece;
4397 XTextExtents(countFontStruct, string, 1, &direction,
4398 &font_ascent, &font_descent, &overall);
4399 if (appData.monoMode) {
4400 XDrawImageString(xDisplay, xBoardWindow, countGC,
4401 x + 2, y + font_ascent + 1, string, 1);
4403 XDrawString(xDisplay, xBoardWindow, countGC,
4404 x + 2, y + font_ascent + 1, string, 1);
4408 if (piece == EmptySquare || appData.blindfold) {
4409 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4411 drawfunc = ChooseDrawFunc();
4413 if (do_flash && appData.flashCount > 0) {
4414 for (i=0; i<appData.flashCount; ++i) {
4415 drawfunc(piece, square_color, x, y, xBoardWindow);
4416 XSync(xDisplay, False);
4417 do_flash_delay(flash_delay);
4419 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4420 XSync(xDisplay, False);
4421 do_flash_delay(flash_delay);
4424 drawfunc(piece, square_color, x, y, xBoardWindow);
4428 string[1] = NULLCHAR;
4429 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4430 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4431 string[0] = 'a' + column - BOARD_LEFT;
4432 XTextExtents(coordFontStruct, string, 1, &direction,
4433 &font_ascent, &font_descent, &overall);
4434 if (appData.monoMode) {
4435 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4436 x + squareSize - overall.width - 2,
4437 y + squareSize - font_descent - 1, string, 1);
4439 XDrawString(xDisplay, xBoardWindow, coordGC,
4440 x + squareSize - overall.width - 2,
4441 y + squareSize - font_descent - 1, string, 1);
4444 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4445 string[0] = ONE + row;
4446 XTextExtents(coordFontStruct, string, 1, &direction,
4447 &font_ascent, &font_descent, &overall);
4448 if (appData.monoMode) {
4449 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4450 x + 2, y + font_ascent + 1, string, 1);
4452 XDrawString(xDisplay, xBoardWindow, coordGC,
4453 x + 2, y + font_ascent + 1, string, 1);
4456 if(!partnerUp && marker[row][column]) {
4457 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4458 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4463 /* Why is this needed on some versions of X? */
4464 void EventProc(widget, unused, event)
4469 if (!XtIsRealized(widget))
4472 switch (event->type) {
4474 if (event->xexpose.count > 0) return; /* no clipping is done */
4475 XDrawPosition(widget, True, NULL);
4476 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4477 flipView = !flipView; partnerUp = !partnerUp;
4478 XDrawPosition(widget, True, NULL);
4479 flipView = !flipView; partnerUp = !partnerUp;
4483 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
4490 void DrawPosition(fullRedraw, board)
4491 /*Boolean*/int fullRedraw;
4494 XDrawPosition(boardWidget, fullRedraw, board);
4497 /* Returns 1 if there are "too many" differences between b1 and b2
4498 (i.e. more than 1 move was made) */
4499 static int too_many_diffs(b1, b2)
4505 for (i=0; i<BOARD_HEIGHT; ++i) {
4506 for (j=0; j<BOARD_WIDTH; ++j) {
4507 if (b1[i][j] != b2[i][j]) {
4508 if (++c > 4) /* Castling causes 4 diffs */
4516 /* Matrix describing castling maneuvers */
4517 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4518 static int castling_matrix[4][5] = {
4519 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4520 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4521 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4522 { 7, 7, 4, 5, 6 } /* 0-0, black */
4525 /* Checks whether castling occurred. If it did, *rrow and *rcol
4526 are set to the destination (row,col) of the rook that moved.
4528 Returns 1 if castling occurred, 0 if not.
4530 Note: Only handles a max of 1 castling move, so be sure
4531 to call too_many_diffs() first.
4533 static int check_castle_draw(newb, oldb, rrow, rcol)
4540 /* For each type of castling... */
4541 for (i=0; i<4; ++i) {
4542 r = castling_matrix[i];
4544 /* Check the 4 squares involved in the castling move */
4546 for (j=1; j<=4; ++j) {
4547 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4554 /* All 4 changed, so it must be a castling move */
4563 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4564 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4566 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4569 void DrawSeekBackground( int left, int top, int right, int bottom )
4571 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4574 void DrawSeekText(char *buf, int x, int y)
4576 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4579 void DrawSeekDot(int x, int y, int colorNr)
4581 int square = colorNr & 0x80;
4584 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4586 XFillRectangle(xDisplay, xBoardWindow, color,
4587 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4589 XFillArc(xDisplay, xBoardWindow, color,
4590 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4593 static int damage[2][BOARD_RANKS][BOARD_FILES];
4596 * event handler for redrawing the board
4598 void XDrawPosition(w, repaint, board)
4600 /*Boolean*/int repaint;
4604 static int lastFlipView = 0;
4605 static int lastBoardValid[2] = {0, 0};
4606 static Board lastBoard[2];
4609 int nr = twoBoards*partnerUp;
4611 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4613 if (board == NULL) {
4614 if (!lastBoardValid[nr]) return;
4615 board = lastBoard[nr];
4617 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4618 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4619 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Flip View"),
4624 * It would be simpler to clear the window with XClearWindow()
4625 * but this causes a very distracting flicker.
4628 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4630 if ( lineGap && IsDrawArrowEnabled())
4631 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4632 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4634 /* If too much changes (begin observing new game, etc.), don't
4636 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4638 /* Special check for castling so we don't flash both the king
4639 and the rook (just flash the king). */
4641 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4642 /* Draw rook with NO flashing. King will be drawn flashing later */
4643 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4644 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4648 /* First pass -- Draw (newly) empty squares and repair damage.
4649 This prevents you from having a piece show up twice while it
4650 is flashing on its new square */
4651 for (i = 0; i < BOARD_HEIGHT; i++)
4652 for (j = 0; j < BOARD_WIDTH; j++)
4653 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4654 || damage[nr][i][j]) {
4655 DrawSquare(i, j, board[i][j], 0);
4656 damage[nr][i][j] = False;
4659 /* Second pass -- Draw piece(s) in new position and flash them */
4660 for (i = 0; i < BOARD_HEIGHT; i++)
4661 for (j = 0; j < BOARD_WIDTH; j++)
4662 if (board[i][j] != lastBoard[nr][i][j]) {
4663 DrawSquare(i, j, board[i][j], do_flash);
4667 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4668 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4669 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4671 for (i = 0; i < BOARD_HEIGHT; i++)
4672 for (j = 0; j < BOARD_WIDTH; j++) {
4673 DrawSquare(i, j, board[i][j], 0);
4674 damage[nr][i][j] = False;
4678 CopyBoard(lastBoard[nr], board);
4679 lastBoardValid[nr] = 1;
4680 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4681 lastFlipView = flipView;
4683 /* Draw highlights */
4684 if (pm1X >= 0 && pm1Y >= 0) {
4685 drawHighlight(pm1X, pm1Y, prelineGC);
4687 if (pm2X >= 0 && pm2Y >= 0) {
4688 drawHighlight(pm2X, pm2Y, prelineGC);
4690 if (hi1X >= 0 && hi1Y >= 0) {
4691 drawHighlight(hi1X, hi1Y, highlineGC);
4693 if (hi2X >= 0 && hi2Y >= 0) {
4694 drawHighlight(hi2X, hi2Y, highlineGC);
4696 DrawArrowHighlight(hi1X, hi1Y, hi2X, hi2Y);
4698 /* If piece being dragged around board, must redraw that too */
4701 XSync(xDisplay, False);
4706 * event handler for redrawing the board
4708 void DrawPositionProc(w, event, prms, nprms)
4714 XDrawPosition(w, True, NULL);
4719 * event handler for parsing user moves
4721 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4722 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4723 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4724 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4725 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4726 // and at the end FinishMove() to perform the move after optional promotion popups.
4727 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4728 void HandleUserMove(w, event, prms, nprms)
4734 if (w != boardWidget || errorExitStatus != -1) return;
4735 if(nprms) shiftKey = !strcmp(prms[0], "1");
4738 if (event->type == ButtonPress) {
4739 XtPopdown(promotionShell);
4740 XtDestroyWidget(promotionShell);
4741 promotionUp = False;
4749 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4750 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4751 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4754 void AnimateUserMove (Widget w, XEvent * event,
4755 String * params, Cardinal * nParams)
4757 DragPieceMove(event->xmotion.x, event->xmotion.y);
4760 void HandlePV (Widget w, XEvent * event,
4761 String * params, Cardinal * nParams)
4762 { // [HGM] pv: walk PV
4763 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4766 Widget CommentCreate(name, text, mutable, callback, lines)
4768 int /*Boolean*/ mutable;
4769 XtCallbackProc callback;
4773 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4778 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4779 XtGetValues(boardWidget, args, j);
4782 XtSetArg(args[j], XtNresizable, True); j++;
4785 XtCreatePopupShell(name, topLevelShellWidgetClass,
4786 shellWidget, args, j);
4789 XtCreatePopupShell(name, transientShellWidgetClass,
4790 shellWidget, args, j);
4793 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4794 layoutArgs, XtNumber(layoutArgs));
4796 XtCreateManagedWidget("form", formWidgetClass, layout,
4797 formArgs, XtNumber(formArgs));
4801 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4802 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4804 XtSetArg(args[j], XtNstring, text); j++;
4805 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4806 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4807 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4808 XtSetArg(args[j], XtNright, XtChainRight); j++;
4809 XtSetArg(args[j], XtNresizable, True); j++;
4810 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4811 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4812 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4813 XtSetArg(args[j], XtNautoFill, True); j++;
4814 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4816 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4817 XtOverrideTranslations(edit, XtParseTranslationTable(commentTranslations));
4821 XtSetArg(args[j], XtNfromVert, edit); j++;
4822 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4823 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4824 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4825 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4827 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4828 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4831 XtSetArg(args[j], XtNfromVert, edit); j++;
4832 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4833 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4834 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4835 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4836 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4838 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4839 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4842 XtSetArg(args[j], XtNfromVert, edit); j++;
4843 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4844 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4845 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4846 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4847 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4849 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4850 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4853 XtSetArg(args[j], XtNfromVert, edit); j++;
4854 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4855 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4856 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4857 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4859 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4860 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4863 XtSetArg(args[j], XtNfromVert, edit); j++;
4864 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4865 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4866 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4867 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4868 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4870 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4871 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4874 XtRealizeWidget(shell);
4876 if (commentX == -1) {
4879 Dimension pw_height;
4880 Dimension ew_height;
4883 XtSetArg(args[j], XtNheight, &ew_height); j++;
4884 XtGetValues(edit, args, j);
4887 XtSetArg(args[j], XtNheight, &pw_height); j++;
4888 XtGetValues(shell, args, j);
4889 commentH = pw_height + (lines - 1) * ew_height;
4890 commentW = bw_width - 16;
4892 XSync(xDisplay, False);
4894 /* This code seems to tickle an X bug if it is executed too soon
4895 after xboard starts up. The coordinates get transformed as if
4896 the main window was positioned at (0, 0).
4898 XtTranslateCoords(shellWidget,
4899 (bw_width - commentW) / 2, 0 - commentH / 2,
4900 &commentX, &commentY);
4902 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4903 RootWindowOfScreen(XtScreen(shellWidget)),
4904 (bw_width - commentW) / 2, 0 - commentH / 2,
4909 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4912 if(wpComment.width > 0) {
4913 commentX = wpComment.x;
4914 commentY = wpComment.y;
4915 commentW = wpComment.width;
4916 commentH = wpComment.height;
4920 XtSetArg(args[j], XtNheight, commentH); j++;
4921 XtSetArg(args[j], XtNwidth, commentW); j++;
4922 XtSetArg(args[j], XtNx, commentX); j++;
4923 XtSetArg(args[j], XtNy, commentY); j++;
4924 XtSetValues(shell, args, j);
4925 XtSetKeyboardFocus(shell, edit);
4930 /* Used for analysis window and ICS input window */
4931 Widget MiscCreate(name, text, mutable, callback, lines)
4933 int /*Boolean*/ mutable;
4934 XtCallbackProc callback;
4938 Widget shell, layout, form, edit;
4940 Dimension bw_width, pw_height, ew_height, w, h;
4946 XtSetArg(args[j], XtNresizable, True); j++;
4949 XtCreatePopupShell(name, topLevelShellWidgetClass,
4950 shellWidget, args, j);
4953 XtCreatePopupShell(name, transientShellWidgetClass,
4954 shellWidget, args, j);
4957 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4958 layoutArgs, XtNumber(layoutArgs));
4960 XtCreateManagedWidget("form", formWidgetClass, layout,
4961 formArgs, XtNumber(formArgs));
4965 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4966 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4968 XtSetArg(args[j], XtNstring, text); j++;
4969 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4970 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4971 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4972 XtSetArg(args[j], XtNright, XtChainRight); j++;
4973 XtSetArg(args[j], XtNresizable, True); j++;
4974 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4975 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4976 XtSetArg(args[j], XtNautoFill, True); j++;
4977 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4979 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4981 XtRealizeWidget(shell);
4984 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4985 XtGetValues(boardWidget, args, j);
4988 XtSetArg(args[j], XtNheight, &ew_height); j++;
4989 XtGetValues(edit, args, j);
4992 XtSetArg(args[j], XtNheight, &pw_height); j++;
4993 XtGetValues(shell, args, j);
4994 h = pw_height + (lines - 1) * ew_height;
4997 XSync(xDisplay, False);
4999 /* This code seems to tickle an X bug if it is executed too soon
5000 after xboard starts up. The coordinates get transformed as if
5001 the main window was positioned at (0, 0).
5003 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
5005 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
5006 RootWindowOfScreen(XtScreen(shellWidget)),
5007 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
5011 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5014 XtSetArg(args[j], XtNheight, h); j++;
5015 XtSetArg(args[j], XtNwidth, w); j++;
5016 XtSetArg(args[j], XtNx, x); j++;
5017 XtSetArg(args[j], XtNy, y); j++;
5018 XtSetValues(shell, args, j);
5024 static int savedIndex; /* gross that this is global */
5026 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
5029 XawTextPosition index, dummy;
5032 XawTextGetSelectionPos(w, &index, &dummy);
5033 XtSetArg(arg, XtNstring, &val);
5034 XtGetValues(w, &arg, 1);
5035 ReplaceComment(savedIndex, val);
5036 if(savedIndex != currentMove) ToNrEvent(savedIndex);
5037 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
5040 void EditCommentPopUp(index, title, text)
5049 if (text == NULL) text = "";
5051 if (editShell == NULL) {
5053 CommentCreate(title, text, True, EditCommentCallback, 4);
5054 XtRealizeWidget(editShell);
5055 CatchDeleteWindow(editShell, "EditCommentPopDown");
5057 edit = XtNameToWidget(editShell, "*form.text");
5059 XtSetArg(args[j], XtNstring, text); j++;
5060 XtSetValues(edit, args, j);
5062 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5063 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5064 XtSetValues(editShell, args, j);
5067 XtPopup(editShell, XtGrabNone);
5071 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5072 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"),
5074 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"),
5078 void EditCommentCallback(w, client_data, call_data)
5080 XtPointer client_data, call_data;
5088 XtSetArg(args[j], XtNlabel, &name); j++;
5089 XtGetValues(w, args, j);
5091 if (strcmp(name, _("ok")) == 0) {
5092 edit = XtNameToWidget(editShell, "*form.text");
5094 XtSetArg(args[j], XtNstring, &val); j++;
5095 XtGetValues(edit, args, j);
5096 ReplaceComment(savedIndex, val);
5097 EditCommentPopDown();
5098 } else if (strcmp(name, _("cancel")) == 0) {
5099 EditCommentPopDown();
5100 } else if (strcmp(name, _("clear")) == 0) {
5101 edit = XtNameToWidget(editShell, "*form.text");
5102 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5103 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5107 void EditCommentPopDown()
5112 if (!editUp) return;
5114 XtSetArg(args[j], XtNx, &commentX); j++;
5115 XtSetArg(args[j], XtNy, &commentY); j++;
5116 XtSetArg(args[j], XtNheight, &commentH); j++;
5117 XtSetArg(args[j], XtNwidth, &commentW); j++;
5118 XtGetValues(editShell, args, j);
5119 XtPopdown(editShell);
5122 XtSetArg(args[j], XtNleftBitmap, None); j++;
5123 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"),
5125 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"),
5129 void ICSInputBoxPopUp()
5134 char *title = _("ICS Input");
5137 if (ICSInputShell == NULL) {
5138 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
5139 tr = XtParseTranslationTable(ICSInputTranslations);
5140 edit = XtNameToWidget(ICSInputShell, "*form.text");
5141 XtOverrideTranslations(edit, tr);
5142 XtRealizeWidget(ICSInputShell);
5143 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
5146 edit = XtNameToWidget(ICSInputShell, "*form.text");
5148 XtSetArg(args[j], XtNstring, ""); j++;
5149 XtSetValues(edit, args, j);
5151 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5152 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5153 XtSetValues(ICSInputShell, args, j);
5156 XtPopup(ICSInputShell, XtGrabNone);
5157 XtSetKeyboardFocus(ICSInputShell, edit);
5159 ICSInputBoxUp = True;
5161 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5162 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.ICS Input Box"),
5166 void ICSInputSendText()
5173 edit = XtNameToWidget(ICSInputShell, "*form.text");
5175 XtSetArg(args[j], XtNstring, &val); j++;
5176 XtGetValues(edit, args, j);
5178 SendMultiLineToICS(val);
5179 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5180 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5183 void ICSInputBoxPopDown()
5188 if (!ICSInputBoxUp) return;
5190 XtPopdown(ICSInputShell);
5191 ICSInputBoxUp = False;
5193 XtSetArg(args[j], XtNleftBitmap, None); j++;
5194 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.ICS Input Box"),
5198 void CommentPopUp(title, text)
5205 savedIndex = currentMove; // [HGM] vari
5206 if (commentShell == NULL) {
5208 CommentCreate(title, text, False, CommentCallback, 4);
5209 XtRealizeWidget(commentShell);
5210 CatchDeleteWindow(commentShell, "CommentPopDown");
5212 edit = XtNameToWidget(commentShell, "*form.text");
5214 XtSetArg(args[j], XtNstring, text); j++;
5215 XtSetValues(edit, args, j);
5217 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5218 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5219 XtSetValues(commentShell, args, j);
5222 XtPopup(commentShell, XtGrabNone);
5223 XSync(xDisplay, False);
5228 void CommentCallback(w, client_data, call_data)
5230 XtPointer client_data, call_data;
5237 XtSetArg(args[j], XtNlabel, &name); j++;
5238 XtGetValues(w, args, j);
5240 if (strcmp(name, _("close")) == 0) {
5242 } else if (strcmp(name, _("edit")) == 0) {
5249 void CommentPopDown()
5254 if (!commentUp) return;
5256 XtSetArg(args[j], XtNx, &commentX); j++;
5257 XtSetArg(args[j], XtNy, &commentY); j++;
5258 XtSetArg(args[j], XtNwidth, &commentW); j++;
5259 XtSetArg(args[j], XtNheight, &commentH); j++;
5260 XtGetValues(commentShell, args, j);
5261 XtPopdown(commentShell);
5262 XSync(xDisplay, False);
5266 void FileNamePopUp(label, def, proc, openMode)
5272 fileProc = proc; /* I can't see a way not */
5273 fileOpenMode = openMode; /* to use globals here */
5274 { // [HGM] use file-selector dialog stolen from Ghostview
5276 int index; // this is not supported yet
5278 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5279 def, openMode, NULL, &name))
5280 (void) (*fileProc)(f, index=0, name);
5284 void FileNamePopDown()
5286 if (!filenameUp) return;
5287 XtPopdown(fileNameShell);
5288 XtDestroyWidget(fileNameShell);
5293 void FileNameCallback(w, client_data, call_data)
5295 XtPointer client_data, call_data;
5300 XtSetArg(args[0], XtNlabel, &name);
5301 XtGetValues(w, args, 1);
5303 if (strcmp(name, _("cancel")) == 0) {
5308 FileNameAction(w, NULL, NULL, NULL);
5311 void FileNameAction(w, event, prms, nprms)
5323 name = XawDialogGetValueString(w = XtParent(w));
5325 if ((name != NULL) && (*name != NULLCHAR)) {
5326 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
5327 XtPopdown(w = XtParent(XtParent(w)));
5331 p = strrchr(buf, ' ');
5338 fullname = ExpandPathName(buf);
5340 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5343 f = fopen(fullname, fileOpenMode);
5345 DisplayError(_("Failed to open file"), errno);
5347 (void) (*fileProc)(f, index, buf);
5354 XtPopdown(w = XtParent(XtParent(w)));
5360 void PromotionPopUp()
5363 Widget dialog, layout;
5365 Dimension bw_width, pw_width;
5369 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5370 XtGetValues(boardWidget, args, j);
5373 XtSetArg(args[j], XtNresizable, True); j++;
5374 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5376 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5377 shellWidget, args, j);
5379 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5380 layoutArgs, XtNumber(layoutArgs));
5383 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5384 XtSetArg(args[j], XtNborderWidth, 0); j++;
5385 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5388 if(gameInfo.variant != VariantShogi) {
5389 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) {
5390 XawDialogAddButton(dialog, _("Warlord"), PromotionCallback,
5391 (XtPointer) dialog);
5392 XawDialogAddButton(dialog, _("General"), PromotionCallback,
5393 (XtPointer) dialog);
5394 XawDialogAddButton(dialog, _("Lieutenant"), PromotionCallback,
5395 (XtPointer) dialog);
5396 XawDialogAddButton(dialog, _("Captain"), PromotionCallback,
5397 (XtPointer) dialog);
5399 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5400 (XtPointer) dialog);
5401 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5402 (XtPointer) dialog);
5403 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5404 (XtPointer) dialog);
5405 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5406 (XtPointer) dialog);
5408 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5409 gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
\r
5410 gameInfo.variant == VariantGiveaway) {
5411 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5412 (XtPointer) dialog);
5414 if(gameInfo.variant == VariantCapablanca ||
5415 gameInfo.variant == VariantGothic ||
5416 gameInfo.variant == VariantCapaRandom) {
5417 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5418 (XtPointer) dialog);
5419 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5420 (XtPointer) dialog);
5422 } else // [HGM] shogi
5424 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5425 (XtPointer) dialog);
5426 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5427 (XtPointer) dialog);
5429 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5430 (XtPointer) dialog);
5432 XtRealizeWidget(promotionShell);
5433 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5436 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5437 XtGetValues(promotionShell, args, j);
5439 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5440 lineGap + squareSize/3 +
5441 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5442 0 : 6*(squareSize + lineGap)), &x, &y);
5445 XtSetArg(args[j], XtNx, x); j++;
5446 XtSetArg(args[j], XtNy, y); j++;
5447 XtSetValues(promotionShell, args, j);
5449 XtPopup(promotionShell, XtGrabNone);
5454 void PromotionPopDown()
5456 if (!promotionUp) return;
5457 XtPopdown(promotionShell);
5458 XtDestroyWidget(promotionShell);
5459 promotionUp = False;
5462 void PromotionCallback(w, client_data, call_data)
5464 XtPointer client_data, call_data;
5470 XtSetArg(args[0], XtNlabel, &name);
5471 XtGetValues(w, args, 1);
5475 if (fromX == -1) return;
5477 if (strcmp(name, _("cancel")) == 0) {
5481 } else if (strcmp(name, _("Knight")) == 0) {
5483 } else if (strcmp(name, _("Promote")) == 0) {
5485 } else if (strcmp(name, _("Defer")) == 0) {
5488 promoChar = ToLower(name[0]);
5491 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5493 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5494 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5499 void ErrorCallback(w, client_data, call_data)
5501 XtPointer client_data, call_data;
5504 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5506 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5512 if (!errorUp) return;
5514 XtPopdown(errorShell);
5515 XtDestroyWidget(errorShell);
5516 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5519 void ErrorPopUp(title, label, modal)
5520 char *title, *label;
5524 Widget dialog, layout;
5528 Dimension bw_width, pw_width;
5529 Dimension pw_height;
5533 XtSetArg(args[i], XtNresizable, True); i++;
5534 XtSetArg(args[i], XtNtitle, title); i++;
5536 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5537 shellWidget, args, i);
5539 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5540 layoutArgs, XtNumber(layoutArgs));
5543 XtSetArg(args[i], XtNlabel, label); i++;
5544 XtSetArg(args[i], XtNborderWidth, 0); i++;
5545 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5548 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5550 XtRealizeWidget(errorShell);
5551 CatchDeleteWindow(errorShell, "ErrorPopDown");
5554 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5555 XtGetValues(boardWidget, args, i);
5557 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5558 XtSetArg(args[i], XtNheight, &pw_height); i++;
5559 XtGetValues(errorShell, args, i);
5562 /* This code seems to tickle an X bug if it is executed too soon
5563 after xboard starts up. The coordinates get transformed as if
5564 the main window was positioned at (0, 0).
5566 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5567 0 - pw_height + squareSize / 3, &x, &y);
5569 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5570 RootWindowOfScreen(XtScreen(boardWidget)),
5571 (bw_width - pw_width) / 2,
5572 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5576 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5579 XtSetArg(args[i], XtNx, x); i++;
5580 XtSetArg(args[i], XtNy, y); i++;
5581 XtSetValues(errorShell, args, i);
5584 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5587 /* Disable all user input other than deleting the window */
5588 static int frozen = 0;
5592 /* Grab by a widget that doesn't accept input */
5593 XtAddGrab(messageWidget, TRUE, FALSE);
5597 /* Undo a FreezeUI */
5600 if (!frozen) return;
5601 XtRemoveGrab(messageWidget);
5605 char *ModeToWidgetName(mode)
5609 case BeginningOfGame:
5610 if (appData.icsActive)
5611 return "menuMode.ICS Client";
5612 else if (appData.noChessProgram ||
5613 *appData.cmailGameName != NULLCHAR)
5614 return "menuMode.Edit Game";
5616 return "menuMode.Machine Black";
5617 case MachinePlaysBlack:
5618 return "menuMode.Machine Black";
5619 case MachinePlaysWhite:
5620 return "menuMode.Machine White";
5622 return "menuMode.Analysis Mode";
5624 return "menuMode.Analyze File";
5625 case TwoMachinesPlay:
5626 return "menuMode.Two Machines";
5628 return "menuMode.Edit Game";
5629 case PlayFromGameFile:
5630 return "menuFile.Load Game";
5632 return "menuMode.Edit Position";
5634 return "menuMode.Training";
5635 case IcsPlayingWhite:
5636 case IcsPlayingBlack:
5640 return "menuMode.ICS Client";
5647 void ModeHighlight()
5650 static int oldPausing = FALSE;
5651 static GameMode oldmode = (GameMode) -1;
5654 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5656 if (pausing != oldPausing) {
5657 oldPausing = pausing;
5659 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5661 XtSetArg(args[0], XtNleftBitmap, None);
5663 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5666 if (appData.showButtonBar) {
5667 /* Always toggle, don't set. Previous code messes up when
5668 invoked while the button is pressed, as releasing it
5669 toggles the state again. */
5672 XtSetArg(args[0], XtNbackground, &oldbg);
5673 XtSetArg(args[1], XtNforeground, &oldfg);
5674 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5676 XtSetArg(args[0], XtNbackground, oldfg);
5677 XtSetArg(args[1], XtNforeground, oldbg);
5679 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5683 wname = ModeToWidgetName(oldmode);
5684 if (wname != NULL) {
5685 XtSetArg(args[0], XtNleftBitmap, None);
5686 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5688 wname = ModeToWidgetName(gameMode);
5689 if (wname != NULL) {
5690 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5691 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5695 /* Maybe all the enables should be handled here, not just this one */
5696 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5697 gameMode == Training || gameMode == PlayFromGameFile);
5702 * Button/menu procedures
5704 void ResetProc(w, event, prms, nprms)
5713 int LoadGamePopUp(f, gameNumber, title)
5718 cmailMsgLoaded = FALSE;
5719 if (gameNumber == 0) {
5720 int error = GameListBuild(f);
5722 DisplayError(_("Cannot build game list"), error);
5723 } else if (!ListEmpty(&gameList) &&
5724 ((ListGame *) gameList.tailPred)->number > 1) {
5725 GameListPopUp(f, title);
5731 return LoadGame(f, gameNumber, title, FALSE);
5734 void LoadGameProc(w, event, prms, nprms)
5740 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5743 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5746 void LoadNextGameProc(w, event, prms, nprms)
5755 void LoadPrevGameProc(w, event, prms, nprms)
5764 void ReloadGameProc(w, event, prms, nprms)
5773 void LoadNextPositionProc(w, event, prms, nprms)
5782 void LoadPrevPositionProc(w, event, prms, nprms)
5791 void ReloadPositionProc(w, event, prms, nprms)
5800 void LoadPositionProc(w, event, prms, nprms)
5806 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5809 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5812 void SaveGameProc(w, event, prms, nprms)
5818 FileNamePopUp(_("Save game file name?"),
5819 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5823 void SavePositionProc(w, event, prms, nprms)
5829 FileNamePopUp(_("Save position file name?"),
5830 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5834 void ReloadCmailMsgProc(w, event, prms, nprms)
5840 ReloadCmailMsgEvent(FALSE);
5843 void MailMoveProc(w, event, prms, nprms)
5852 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5853 char *selected_fen_position=NULL;
5856 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5857 Atom *type_return, XtPointer *value_return,
5858 unsigned long *length_return, int *format_return)
5860 char *selection_tmp;
5862 if (!selected_fen_position) return False; /* should never happen */
5863 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5864 /* note: since no XtSelectionDoneProc was registered, Xt will
5865 * automatically call XtFree on the value returned. So have to
5866 * make a copy of it allocated with XtMalloc */
5867 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5868 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
5870 *value_return=selection_tmp;
5871 *length_return=strlen(selection_tmp);
5872 *type_return=*target;
5873 *format_return = 8; /* bits per byte */
5875 } else if (*target == XA_TARGETS(xDisplay)) {
5876 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5877 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5878 targets_tmp[1] = XA_STRING;
5879 *value_return = targets_tmp;
5880 *type_return = XA_ATOM;
5882 *format_return = 8 * sizeof(Atom);
5883 if (*format_return > 32) {
5884 *length_return *= *format_return / 32;
5885 *format_return = 32;
5893 /* note: when called from menu all parameters are NULL, so no clue what the
5894 * Widget which was clicked on was, or what the click event was
5896 void CopyPositionProc(w, event, prms, nprms)
5903 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5904 * have a notion of a position that is selected but not copied.
5905 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5907 if(gameMode == EditPosition) EditPositionDone(TRUE);
5908 if (selected_fen_position) free(selected_fen_position);
5909 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5910 if (!selected_fen_position) return;
5911 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5913 SendPositionSelection,
5914 NULL/* lose_ownership_proc */ ,
5915 NULL/* transfer_done_proc */);
5916 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5918 SendPositionSelection,
5919 NULL/* lose_ownership_proc */ ,
5920 NULL/* transfer_done_proc */);
5923 /* function called when the data to Paste is ready */
5925 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5926 Atom *type, XtPointer value, unsigned long *len, int *format)
5929 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5930 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5931 EditPositionPasteFEN(fenstr);
5935 /* called when Paste Position button is pressed,
5936 * all parameters will be NULL */
5937 void PastePositionProc(w, event, prms, nprms)
5943 XtGetSelectionValue(menuBarWidget,
5944 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5945 /* (XtSelectionCallbackProc) */ PastePositionCB,
5946 NULL, /* client_data passed to PastePositionCB */
5948 /* better to use the time field from the event that triggered the
5949 * call to this function, but that isn't trivial to get
5957 SendGameSelection(Widget w, Atom *selection, Atom *target,
5958 Atom *type_return, XtPointer *value_return,
5959 unsigned long *length_return, int *format_return)
5961 char *selection_tmp;
5963 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5964 FILE* f = fopen(gameCopyFilename, "r");
5967 if (f == NULL) return False;
5971 selection_tmp = XtMalloc(len + 1);
5972 count = fread(selection_tmp, 1, len, f);
5975 XtFree(selection_tmp);
5978 selection_tmp[len] = NULLCHAR;
5979 *value_return = selection_tmp;
5980 *length_return = len;
5981 *type_return = *target;
5982 *format_return = 8; /* bits per byte */
5984 } else if (*target == XA_TARGETS(xDisplay)) {
5985 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5986 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5987 targets_tmp[1] = XA_STRING;
5988 *value_return = targets_tmp;
5989 *type_return = XA_ATOM;
5991 *format_return = 8 * sizeof(Atom);
5992 if (*format_return > 32) {
5993 *length_return *= *format_return / 32;
5994 *format_return = 32;
6002 /* note: when called from menu all parameters are NULL, so no clue what the
6003 * Widget which was clicked on was, or what the click event was
6005 void CopyGameProc(w, event, prms, nprms)
6013 ret = SaveGameToFile(gameCopyFilename, FALSE);
6017 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
6018 * have a notion of a game that is selected but not copied.
6019 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
6021 XtOwnSelection(menuBarWidget, XA_PRIMARY,
6024 NULL/* lose_ownership_proc */ ,
6025 NULL/* transfer_done_proc */);
6026 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
6029 NULL/* lose_ownership_proc */ ,
6030 NULL/* transfer_done_proc */);
6033 /* function called when the data to Paste is ready */
6035 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
6036 Atom *type, XtPointer value, unsigned long *len, int *format)
6039 if (value == NULL || *len == 0) {
6040 return; /* nothing had been selected to copy */
6042 f = fopen(gamePasteFilename, "w");
6044 DisplayError(_("Can't open temp file"), errno);
6047 fwrite(value, 1, *len, f);
6050 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
6053 /* called when Paste Game button is pressed,
6054 * all parameters will be NULL */
6055 void PasteGameProc(w, event, prms, nprms)
6061 XtGetSelectionValue(menuBarWidget,
6062 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
6063 /* (XtSelectionCallbackProc) */ PasteGameCB,
6064 NULL, /* client_data passed to PasteGameCB */
6066 /* better to use the time field from the event that triggered the
6067 * call to this function, but that isn't trivial to get
6077 SaveGameProc(NULL, NULL, NULL, NULL);
6081 void QuitProc(w, event, prms, nprms)
6090 void PauseProc(w, event, prms, nprms)
6100 void MachineBlackProc(w, event, prms, nprms)
6106 MachineBlackEvent();
6109 void MachineWhiteProc(w, event, prms, nprms)
6115 MachineWhiteEvent();
6118 void AnalyzeModeProc(w, event, prms, nprms)
6126 if (!first.analysisSupport) {
6127 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6128 DisplayError(buf, 0);
6131 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
6132 if (appData.icsActive) {
6133 if (gameMode != IcsObserving) {
6134 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
6135 DisplayError(buf, 0);
6137 if (appData.icsEngineAnalyze) {
6138 if (appData.debugMode)
6139 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
6145 /* if enable, use want disable icsEngineAnalyze */
6146 if (appData.icsEngineAnalyze) {
6151 appData.icsEngineAnalyze = TRUE;
6152 if (appData.debugMode)
6153 fprintf(debugFP, _("ICS engine analyze starting... \n"));
6155 #ifndef OPTIONSDIALOG
6156 if (!appData.showThinking)
6157 ShowThinkingProc(w,event,prms,nprms);
6163 void AnalyzeFileProc(w, event, prms, nprms)
6169 if (!first.analysisSupport) {
6171 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6172 DisplayError(buf, 0);
6176 #ifndef OPTIONSDIALOG
6177 if (!appData.showThinking)
6178 ShowThinkingProc(w,event,prms,nprms);
6181 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
6182 AnalysisPeriodicEvent(1);
6185 void TwoMachinesProc(w, event, prms, nprms)
6194 void IcsClientProc(w, event, prms, nprms)
6203 void EditGameProc(w, event, prms, nprms)
6212 void EditPositionProc(w, event, prms, nprms)
6218 EditPositionEvent();
6221 void TrainingProc(w, event, prms, nprms)
6230 void EditCommentProc(w, event, prms, nprms)
6237 EditCommentPopDown();
6243 void IcsInputBoxProc(w, event, prms, nprms)
6249 if (ICSInputBoxUp) {
6250 ICSInputBoxPopDown();
6256 void AcceptProc(w, event, prms, nprms)
6265 void DeclineProc(w, event, prms, nprms)
6274 void RematchProc(w, event, prms, nprms)
6283 void CallFlagProc(w, event, prms, nprms)
6292 void DrawProc(w, event, prms, nprms)
6301 void AbortProc(w, event, prms, nprms)
6310 void AdjournProc(w, event, prms, nprms)
6319 void ResignProc(w, event, prms, nprms)
6328 void AdjuWhiteProc(w, event, prms, nprms)
6334 UserAdjudicationEvent(+1);
6337 void AdjuBlackProc(w, event, prms, nprms)
6343 UserAdjudicationEvent(-1);
6346 void AdjuDrawProc(w, event, prms, nprms)
6352 UserAdjudicationEvent(0);
6355 void EnterKeyProc(w, event, prms, nprms)
6361 if (ICSInputBoxUp == True)
6365 void UpKeyProc(w, event, prms, nprms)
6370 { // [HGM] input: let up-arrow recall previous line from history
6377 if (!ICSInputBoxUp) return;
6378 edit = XtNameToWidget(ICSInputShell, "*form.text");
6380 XtSetArg(args[j], XtNstring, &val); j++;
6381 XtGetValues(edit, args, j);
6382 val = PrevInHistory(val);
6383 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6384 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6386 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6387 XawTextReplace(edit, 0, 0, &t);
6388 XawTextSetInsertionPoint(edit, 9999);
6392 void DownKeyProc(w, event, prms, nprms)
6397 { // [HGM] input: let down-arrow recall next line from history
6402 if (!ICSInputBoxUp) return;
6403 edit = XtNameToWidget(ICSInputShell, "*form.text");
6404 val = NextInHistory();
6405 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6406 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6408 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6409 XawTextReplace(edit, 0, 0, &t);
6410 XawTextSetInsertionPoint(edit, 9999);
6414 void StopObservingProc(w, event, prms, nprms)
6420 StopObservingEvent();
6423 void StopExaminingProc(w, event, prms, nprms)
6429 StopExaminingEvent();
6432 void UploadProc(w, event, prms, nprms)
6442 void ForwardProc(w, event, prms, nprms)
6452 void BackwardProc(w, event, prms, nprms)
6461 void ToStartProc(w, event, prms, nprms)
6470 void ToEndProc(w, event, prms, nprms)
6479 void RevertProc(w, event, prms, nprms)
6488 void AnnotateProc(w, event, prms, nprms)
6497 void TruncateGameProc(w, event, prms, nprms)
6503 TruncateGameEvent();
6505 void RetractMoveProc(w, event, prms, nprms)
6514 void MoveNowProc(w, event, prms, nprms)
6523 void FlipViewProc(w, event, prms, nprms)
6529 flipView = !flipView;
6530 DrawPosition(True, NULL);
6533 void PonderNextMoveProc(w, event, prms, nprms)
6541 PonderNextMoveEvent(!appData.ponderNextMove);
6542 #ifndef OPTIONSDIALOG
6543 if (appData.ponderNextMove) {
6544 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6546 XtSetArg(args[0], XtNleftBitmap, None);
6548 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6553 #ifndef OPTIONSDIALOG
6554 void AlwaysQueenProc(w, event, prms, nprms)
6562 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6564 if (appData.alwaysPromoteToQueen) {
6565 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6567 XtSetArg(args[0], XtNleftBitmap, None);
6569 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6573 void AnimateDraggingProc(w, event, prms, nprms)
6581 appData.animateDragging = !appData.animateDragging;
6583 if (appData.animateDragging) {
6584 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6587 XtSetArg(args[0], XtNleftBitmap, None);
6589 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6593 void AnimateMovingProc(w, event, prms, nprms)
6601 appData.animate = !appData.animate;
6603 if (appData.animate) {
6604 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6607 XtSetArg(args[0], XtNleftBitmap, None);
6609 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6613 void AutoflagProc(w, event, prms, nprms)
6621 appData.autoCallFlag = !appData.autoCallFlag;
6623 if (appData.autoCallFlag) {
6624 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6626 XtSetArg(args[0], XtNleftBitmap, None);
6628 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6632 void AutoflipProc(w, event, prms, nprms)
6640 appData.autoFlipView = !appData.autoFlipView;
6642 if (appData.autoFlipView) {
6643 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6645 XtSetArg(args[0], XtNleftBitmap, None);
6647 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6651 void BlindfoldProc(w, event, prms, nprms)
6659 appData.blindfold = !appData.blindfold;
6661 if (appData.blindfold) {
6662 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6664 XtSetArg(args[0], XtNleftBitmap, None);
6666 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6669 DrawPosition(True, NULL);
6672 void TestLegalityProc(w, event, prms, nprms)
6680 appData.testLegality = !appData.testLegality;
6682 if (appData.testLegality) {
6683 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6685 XtSetArg(args[0], XtNleftBitmap, None);
6687 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6692 void FlashMovesProc(w, event, prms, nprms)
6700 if (appData.flashCount == 0) {
6701 appData.flashCount = 3;
6703 appData.flashCount = -appData.flashCount;
6706 if (appData.flashCount > 0) {
6707 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6709 XtSetArg(args[0], XtNleftBitmap, None);
6711 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6716 void HighlightDraggingProc(w, event, prms, nprms)
6724 appData.highlightDragging = !appData.highlightDragging;
6726 if (appData.highlightDragging) {
6727 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6729 XtSetArg(args[0], XtNleftBitmap, None);
6731 XtSetValues(XtNameToWidget(menuBarWidget,
6732 "menuOptions.Highlight Dragging"), args, 1);
6736 void HighlightLastMoveProc(w, event, prms, nprms)
6744 appData.highlightLastMove = !appData.highlightLastMove;
6746 if (appData.highlightLastMove) {
6747 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6749 XtSetArg(args[0], XtNleftBitmap, None);
6751 XtSetValues(XtNameToWidget(menuBarWidget,
6752 "menuOptions.Highlight Last Move"), args, 1);
6755 void HighlightArrowProc(w, event, prms, nprms)
6763 appData.highlightMoveWithArrow = !appData.highlightMoveWithArrow;
6765 if (appData.highlightMoveWithArrow) {
6766 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6768 XtSetArg(args[0], XtNleftBitmap, None);
6770 XtSetValues(XtNameToWidget(menuBarWidget,
6771 "menuOptions.Arrow"), args, 1);
6775 void IcsAlarmProc(w, event, prms, nprms)
6783 appData.icsAlarm = !appData.icsAlarm;
6785 if (appData.icsAlarm) {
6786 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6788 XtSetArg(args[0], XtNleftBitmap, None);
6790 XtSetValues(XtNameToWidget(menuBarWidget,
6791 "menuOptions.ICS Alarm"), args, 1);
6795 void MoveSoundProc(w, event, prms, nprms)
6803 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6805 if (appData.ringBellAfterMoves) {
6806 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6808 XtSetArg(args[0], XtNleftBitmap, None);
6810 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6814 void OneClickProc(w, event, prms, nprms)
6822 appData.oneClick = !appData.oneClick;
6824 if (appData.oneClick) {
6825 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6827 XtSetArg(args[0], XtNleftBitmap, None);
6829 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.OneClick"),
6833 void PeriodicUpdatesProc(w, event, prms, nprms)
6841 PeriodicUpdatesEvent(!appData.periodicUpdates);
6843 if (appData.periodicUpdates) {
6844 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6846 XtSetArg(args[0], XtNleftBitmap, None);
6848 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6852 void PopupExitMessageProc(w, event, prms, nprms)
6860 appData.popupExitMessage = !appData.popupExitMessage;
6862 if (appData.popupExitMessage) {
6863 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6865 XtSetArg(args[0], XtNleftBitmap, None);
6867 XtSetValues(XtNameToWidget(menuBarWidget,
6868 "menuOptions.Popup Exit Message"), args, 1);
6871 void PopupMoveErrorsProc(w, event, prms, nprms)
6879 appData.popupMoveErrors = !appData.popupMoveErrors;
6881 if (appData.popupMoveErrors) {
6882 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6884 XtSetArg(args[0], XtNleftBitmap, None);
6886 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6891 void PremoveProc(w, event, prms, nprms)
6899 appData.premove = !appData.premove;
6901 if (appData.premove) {
6902 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6904 XtSetArg(args[0], XtNleftBitmap, None);
6906 XtSetValues(XtNameToWidget(menuBarWidget,
6907 "menuOptions.Premove"), args, 1);
6911 void ShowCoordsProc(w, event, prms, nprms)
6919 appData.showCoords = !appData.showCoords;
6921 if (appData.showCoords) {
6922 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6924 XtSetArg(args[0], XtNleftBitmap, None);
6926 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6929 DrawPosition(True, NULL);
6932 void ShowThinkingProc(w, event, prms, nprms)
6938 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6939 ShowThinkingEvent();
6942 void HideThinkingProc(w, event, prms, nprms)
6950 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6951 ShowThinkingEvent();
6953 if (appData.hideThinkingFromHuman) {
6954 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6956 XtSetArg(args[0], XtNleftBitmap, None);
6958 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6963 void SaveOnExitProc(w, event, prms, nprms)
6971 saveSettingsOnExit = !saveSettingsOnExit;
6973 if (saveSettingsOnExit) {
6974 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6976 XtSetArg(args[0], XtNleftBitmap, None);
6978 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6982 void SaveSettingsProc(w, event, prms, nprms)
6988 SaveSettings(settingsFileName);
6991 void InfoProc(w, event, prms, nprms)
6998 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
7003 void ManProc(w, event, prms, nprms)
7011 if (nprms && *nprms > 0)
7015 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
7019 void HintProc(w, event, prms, nprms)
7028 void BookProc(w, event, prms, nprms)
7037 void AboutProc(w, event, prms, nprms)
7045 char *zippy = " (with Zippy code)";
7049 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
7050 programVersion, zippy,
7051 "Copyright 1991 Digital Equipment Corporation",
7052 "Enhancements Copyright 1992-2009 Free Software Foundation",
7053 "Enhancements Copyright 2005 Alessandro Scotti",
7054 PACKAGE, " is free software and carries NO WARRANTY;",
7055 "see the file COPYING for more information.");
7056 ErrorPopUp(_("About XBoard"), buf, FALSE);
7059 void DebugProc(w, event, prms, nprms)
7065 appData.debugMode = !appData.debugMode;
7068 void AboutGameProc(w, event, prms, nprms)
7077 void NothingProc(w, event, prms, nprms)
7086 void Iconify(w, event, prms, nprms)
7095 XtSetArg(args[0], XtNiconic, True);
7096 XtSetValues(shellWidget, args, 1);
7099 void DisplayMessage(message, extMessage)
7100 char *message, *extMessage;
7102 /* display a message in the message widget */
7111 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
7116 message = extMessage;
7120 /* need to test if messageWidget already exists, since this function
7121 can also be called during the startup, if for example a Xresource
7122 is not set up correctly */
7125 XtSetArg(arg, XtNlabel, message);
7126 XtSetValues(messageWidget, &arg, 1);
7132 void DisplayTitle(text)
7137 char title[MSG_SIZ];
7140 if (text == NULL) text = "";
7142 if (appData.titleInWindow) {
7144 XtSetArg(args[i], XtNlabel, text); i++;
7145 XtSetValues(titleWidget, args, i);
7148 if (*text != NULLCHAR) {
7149 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
7150 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
7151 } else if (appData.icsActive) {
7152 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7153 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7154 } else if (appData.cmailGameName[0] != NULLCHAR) {
7155 snprintf(icon, sizeof(icon), "%s", "CMail");
7156 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7158 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7159 } else if (gameInfo.variant == VariantGothic) {
7160 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7161 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
7164 } else if (gameInfo.variant == VariantFalcon) {
7165 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7166 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
7168 } else if (appData.noChessProgram) {
7169 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7170 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
7172 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
7173 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7176 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7177 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7178 XtSetValues(shellWidget, args, i);
7183 DisplayError(message, error)
7190 if (appData.debugMode || appData.matchMode) {
7191 fprintf(stderr, "%s: %s\n", programName, message);
7194 if (appData.debugMode || appData.matchMode) {
7195 fprintf(stderr, "%s: %s: %s\n",
7196 programName, message, strerror(error));
7198 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7201 ErrorPopUp(_("Error"), message, FALSE);
7205 void DisplayMoveError(message)
7210 DrawPosition(FALSE, NULL);
7211 if (appData.debugMode || appData.matchMode) {
7212 fprintf(stderr, "%s: %s\n", programName, message);
7214 if (appData.popupMoveErrors) {
7215 ErrorPopUp(_("Error"), message, FALSE);
7217 DisplayMessage(message, "");
7222 void DisplayFatalError(message, error, status)
7228 errorExitStatus = status;
7230 fprintf(stderr, "%s: %s\n", programName, message);
7232 fprintf(stderr, "%s: %s: %s\n",
7233 programName, message, strerror(error));
7234 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7237 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7238 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7244 void DisplayInformation(message)
7248 ErrorPopUp(_("Information"), message, TRUE);
7251 void DisplayNote(message)
7255 ErrorPopUp(_("Note"), message, FALSE);
7259 NullXErrorCheck(dpy, error_event)
7261 XErrorEvent *error_event;
7266 void DisplayIcsInteractionTitle(message)
7269 if (oldICSInteractionTitle == NULL) {
7270 /* Magic to find the old window title, adapted from vim */
7271 char *wina = getenv("WINDOWID");
7273 Window win = (Window) atoi(wina);
7274 Window root, parent, *children;
7275 unsigned int nchildren;
7276 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7278 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7279 if (!XQueryTree(xDisplay, win, &root, &parent,
7280 &children, &nchildren)) break;
7281 if (children) XFree((void *)children);
7282 if (parent == root || parent == 0) break;
7285 XSetErrorHandler(oldHandler);
7287 if (oldICSInteractionTitle == NULL) {
7288 oldICSInteractionTitle = "xterm";
7291 printf("\033]0;%s\007", message);
7295 char pendingReplyPrefix[MSG_SIZ];
7296 ProcRef pendingReplyPR;
7298 void AskQuestionProc(w, event, prms, nprms)
7305 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7309 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7312 void AskQuestionPopDown()
7314 if (!askQuestionUp) return;
7315 XtPopdown(askQuestionShell);
7316 XtDestroyWidget(askQuestionShell);
7317 askQuestionUp = False;
7320 void AskQuestionReplyAction(w, event, prms, nprms)
7330 reply = XawDialogGetValueString(w = XtParent(w));
7331 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
7332 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
7333 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
7334 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
7335 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7336 AskQuestionPopDown();
7338 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7341 void AskQuestionCallback(w, client_data, call_data)
7343 XtPointer client_data, call_data;
7348 XtSetArg(args[0], XtNlabel, &name);
7349 XtGetValues(w, args, 1);
7351 if (strcmp(name, _("cancel")) == 0) {
7352 AskQuestionPopDown();
7354 AskQuestionReplyAction(w, NULL, NULL, NULL);
7358 void AskQuestion(title, question, replyPrefix, pr)
7359 char *title, *question, *replyPrefix;
7363 Widget popup, layout, dialog, edit;
7369 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
7370 pendingReplyPR = pr;
7373 XtSetArg(args[i], XtNresizable, True); i++;
7374 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7375 askQuestionShell = popup =
7376 XtCreatePopupShell(title, transientShellWidgetClass,
7377 shellWidget, args, i);
7380 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7381 layoutArgs, XtNumber(layoutArgs));
7384 XtSetArg(args[i], XtNlabel, question); i++;
7385 XtSetArg(args[i], XtNvalue, ""); i++;
7386 XtSetArg(args[i], XtNborderWidth, 0); i++;
7387 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7390 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7391 (XtPointer) dialog);
7392 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7393 (XtPointer) dialog);
7395 XtRealizeWidget(popup);
7396 CatchDeleteWindow(popup, "AskQuestionPopDown");
7398 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7399 &x, &y, &win_x, &win_y, &mask);
7401 XtSetArg(args[0], XtNx, x - 10);
7402 XtSetArg(args[1], XtNy, y - 30);
7403 XtSetValues(popup, args, 2);
7405 XtPopup(popup, XtGrabExclusive);
7406 askQuestionUp = True;
7408 edit = XtNameToWidget(dialog, "*value");
7409 XtSetKeyboardFocus(popup, edit);
7417 if (*name == NULLCHAR) {
7419 } else if (strcmp(name, "$") == 0) {
7420 putc(BELLCHAR, stderr);
7423 char *prefix = "", *sep = "";
7424 if(!strchr(name, '/')) { prefix = appData.soundDirectory; sep = "/"; }
7425 snprintf(buf, sizeof(buf), "%s '%s%s%s' &", appData.soundProgram, prefix, sep, name);
7433 PlaySound(appData.soundMove);
7439 PlaySound(appData.soundIcsWin);
7445 PlaySound(appData.soundIcsLoss);
7451 PlaySound(appData.soundIcsDraw);
7455 PlayIcsUnfinishedSound()
7457 PlaySound(appData.soundIcsUnfinished);
7463 PlaySound(appData.soundIcsAlarm);
7469 system("stty echo");
7475 system("stty -echo");
7479 Colorize(cc, continuation)
7484 int count, outCount, error;
7486 if (textColors[(int)cc].bg > 0) {
7487 if (textColors[(int)cc].fg > 0) {
7488 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7489 textColors[(int)cc].fg, textColors[(int)cc].bg);
7491 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7492 textColors[(int)cc].bg);
7495 if (textColors[(int)cc].fg > 0) {
7496 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7497 textColors[(int)cc].fg);
7499 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7502 count = strlen(buf);
7503 outCount = OutputToProcess(NoProc, buf, count, &error);
7504 if (outCount < count) {
7505 DisplayFatalError(_("Error writing to display"), error, 1);
7508 if (continuation) return;
7511 PlaySound(appData.soundShout);
7514 PlaySound(appData.soundSShout);
7517 PlaySound(appData.soundChannel1);
7520 PlaySound(appData.soundChannel);
7523 PlaySound(appData.soundKibitz);
7526 PlaySound(appData.soundTell);
7528 case ColorChallenge:
7529 PlaySound(appData.soundChallenge);
7532 PlaySound(appData.soundRequest);
7535 PlaySound(appData.soundSeek);
7546 return getpwuid(getuid())->pw_name;
7550 ExpandPathName(path)
7553 static char static_buf[4*MSG_SIZ];
7554 char *d, *s, buf[4*MSG_SIZ];
7560 while (*s && isspace(*s))
7569 if (*(s+1) == '/') {
7570 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7574 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7575 { char *p; if(p = strchr(buf, '/')) *p = 0; }
7576 pwd = getpwnam(buf);
7579 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7583 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7584 strcat(d, strchr(s+1, '/'));
7588 safeStrCpy(d, s, 4*MSG_SIZ );
7595 static char host_name[MSG_SIZ];
7597 #if HAVE_GETHOSTNAME
7598 gethostname(host_name, MSG_SIZ);
7600 #else /* not HAVE_GETHOSTNAME */
7601 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7602 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7604 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7606 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7607 #endif /* not HAVE_GETHOSTNAME */
7610 XtIntervalId delayedEventTimerXID = 0;
7611 DelayedEventCallback delayedEventCallback = 0;
7616 delayedEventTimerXID = 0;
7617 delayedEventCallback();
7621 ScheduleDelayedEvent(cb, millisec)
7622 DelayedEventCallback cb; long millisec;
7624 if(delayedEventTimerXID && delayedEventCallback == cb)
7625 // [HGM] alive: replace, rather than add or flush identical event
7626 XtRemoveTimeOut(delayedEventTimerXID);
7627 delayedEventCallback = cb;
7628 delayedEventTimerXID =
7629 XtAppAddTimeOut(appContext, millisec,
7630 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7633 DelayedEventCallback
7636 if (delayedEventTimerXID) {
7637 return delayedEventCallback;
7644 CancelDelayedEvent()
7646 if (delayedEventTimerXID) {
7647 XtRemoveTimeOut(delayedEventTimerXID);
7648 delayedEventTimerXID = 0;
7652 XtIntervalId loadGameTimerXID = 0;
7654 int LoadGameTimerRunning()
7656 return loadGameTimerXID != 0;
7659 int StopLoadGameTimer()
7661 if (loadGameTimerXID != 0) {
7662 XtRemoveTimeOut(loadGameTimerXID);
7663 loadGameTimerXID = 0;
7671 LoadGameTimerCallback(arg, id)
7675 loadGameTimerXID = 0;
7680 StartLoadGameTimer(millisec)
7684 XtAppAddTimeOut(appContext, millisec,
7685 (XtTimerCallbackProc) LoadGameTimerCallback,
7689 XtIntervalId analysisClockXID = 0;
7692 AnalysisClockCallback(arg, id)
7696 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7697 || appData.icsEngineAnalyze) { // [DM]
7698 AnalysisPeriodicEvent(0);
7699 StartAnalysisClock();
7704 StartAnalysisClock()
7707 XtAppAddTimeOut(appContext, 2000,
7708 (XtTimerCallbackProc) AnalysisClockCallback,
7712 XtIntervalId clockTimerXID = 0;
7714 int ClockTimerRunning()
7716 return clockTimerXID != 0;
7719 int StopClockTimer()
7721 if (clockTimerXID != 0) {
7722 XtRemoveTimeOut(clockTimerXID);
7731 ClockTimerCallback(arg, id)
7740 StartClockTimer(millisec)
7744 XtAppAddTimeOut(appContext, millisec,
7745 (XtTimerCallbackProc) ClockTimerCallback,
7750 DisplayTimerLabel(w, color, timer, highlight)
7759 /* check for low time warning */
7760 Pixel foregroundOrWarningColor = timerForegroundPixel;
7763 appData.lowTimeWarning &&
7764 (timer / 1000) < appData.icsAlarmTime)
7765 foregroundOrWarningColor = lowTimeWarningColor;
7767 if (appData.clockMode) {
7768 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7769 XtSetArg(args[0], XtNlabel, buf);
7771 snprintf(buf, MSG_SIZ, "%s ", color);
7772 XtSetArg(args[0], XtNlabel, buf);
7777 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7778 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7780 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7781 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7784 XtSetValues(w, args, 3);
7788 DisplayWhiteClock(timeRemaining, highlight)
7794 if(appData.noGUI) return;
7795 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7796 if (highlight && iconPixmap == bIconPixmap) {
7797 iconPixmap = wIconPixmap;
7798 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7799 XtSetValues(shellWidget, args, 1);
7804 DisplayBlackClock(timeRemaining, highlight)
7810 if(appData.noGUI) return;
7811 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7812 if (highlight && iconPixmap == wIconPixmap) {
7813 iconPixmap = bIconPixmap;
7814 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7815 XtSetValues(shellWidget, args, 1);
7833 int StartChildProcess(cmdLine, dir, pr)
7840 int to_prog[2], from_prog[2];
7844 if (appData.debugMode) {
7845 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7848 /* We do NOT feed the cmdLine to the shell; we just
7849 parse it into blank-separated arguments in the
7850 most simple-minded way possible.
7853 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7856 while(*p == ' ') p++;
7858 if(*p == '"' || *p == '\'')
7859 p = strchr(++argv[i-1], *p);
7860 else p = strchr(p, ' ');
7861 if (p == NULL) break;
7866 SetUpChildIO(to_prog, from_prog);
7868 if ((pid = fork()) == 0) {
7870 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7871 close(to_prog[1]); // first close the unused pipe ends
7872 close(from_prog[0]);
7873 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7874 dup2(from_prog[1], 1);
7875 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7876 close(from_prog[1]); // and closing again loses one of the pipes!
7877 if(fileno(stderr) >= 2) // better safe than sorry...
7878 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7880 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7885 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7887 execvp(argv[0], argv);
7889 /* If we get here, exec failed */
7894 /* Parent process */
7896 close(from_prog[1]);
7898 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7901 cp->fdFrom = from_prog[0];
7902 cp->fdTo = to_prog[1];
7907 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7908 static RETSIGTYPE AlarmCallBack(int n)
7914 DestroyChildProcess(pr, signalType)
7918 ChildProc *cp = (ChildProc *) pr;
7920 if (cp->kind != CPReal) return;
7922 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7923 signal(SIGALRM, AlarmCallBack);
7925 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7926 kill(cp->pid, SIGKILL); // kill it forcefully
7927 wait((int *) 0); // and wait again
7931 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7933 /* Process is exiting either because of the kill or because of
7934 a quit command sent by the backend; either way, wait for it to die.
7943 InterruptChildProcess(pr)
7946 ChildProc *cp = (ChildProc *) pr;
7948 if (cp->kind != CPReal) return;
7949 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7952 int OpenTelnet(host, port, pr)
7957 char cmdLine[MSG_SIZ];
7959 if (port[0] == NULLCHAR) {
7960 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7962 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7964 return StartChildProcess(cmdLine, "", pr);
7967 int OpenTCP(host, port, pr)
7973 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7974 #else /* !OMIT_SOCKETS */
7976 struct sockaddr_in sa;
7978 unsigned short uport;
7981 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7985 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7986 sa.sin_family = AF_INET;
7987 sa.sin_addr.s_addr = INADDR_ANY;
7988 uport = (unsigned short) 0;
7989 sa.sin_port = htons(uport);
7990 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7994 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7995 if (!(hp = gethostbyname(host))) {
7997 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7998 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7999 hp->h_addrtype = AF_INET;
8001 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
8002 hp->h_addr_list[0] = (char *) malloc(4);
8003 hp->h_addr_list[0][0] = b0;
8004 hp->h_addr_list[0][1] = b1;
8005 hp->h_addr_list[0][2] = b2;
8006 hp->h_addr_list[0][3] = b3;
8011 sa.sin_family = hp->h_addrtype;
8012 uport = (unsigned short) atoi(port);
8013 sa.sin_port = htons(uport);
8014 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
8016 if (connect(s, (struct sockaddr *) &sa,
8017 sizeof(struct sockaddr_in)) < 0) {
8021 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8028 #endif /* !OMIT_SOCKETS */
8033 int OpenCommPort(name, pr)
8040 fd = open(name, 2, 0);
8041 if (fd < 0) return errno;
8043 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8053 int OpenLoopback(pr)
8059 SetUpChildIO(to, from);
8061 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8064 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
8071 int OpenRcmd(host, user, cmd, pr)
8072 char *host, *user, *cmd;
8075 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
8079 #define INPUT_SOURCE_BUF_SIZE 8192
8088 char buf[INPUT_SOURCE_BUF_SIZE];
8093 DoInputCallback(closure, source, xid)
8098 InputSource *is = (InputSource *) closure;
8103 if (is->lineByLine) {
8104 count = read(is->fd, is->unused,
8105 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
8107 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
8110 is->unused += count;
8112 while (p < is->unused) {
8113 q = memchr(p, '\n', is->unused - p);
8114 if (q == NULL) break;
8116 (is->func)(is, is->closure, p, q - p, 0);
8120 while (p < is->unused) {
8125 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8130 (is->func)(is, is->closure, is->buf, count, error);
8134 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8141 ChildProc *cp = (ChildProc *) pr;
8143 is = (InputSource *) calloc(1, sizeof(InputSource));
8144 is->lineByLine = lineByLine;
8148 is->fd = fileno(stdin);
8150 is->kind = cp->kind;
8151 is->fd = cp->fdFrom;
8154 is->unused = is->buf;
8157 is->xid = XtAppAddInput(appContext, is->fd,
8158 (XtPointer) (XtInputReadMask),
8159 (XtInputCallbackProc) DoInputCallback,
8161 is->closure = closure;
8162 return (InputSourceRef) is;
8166 RemoveInputSource(isr)
8169 InputSource *is = (InputSource *) isr;
8171 if (is->xid == 0) return;
8172 XtRemoveInput(is->xid);
8176 int OutputToProcess(pr, message, count, outError)
8182 static int line = 0;
8183 ChildProc *cp = (ChildProc *) pr;
8188 if (appData.noJoin || !appData.useInternalWrap)
8189 outCount = fwrite(message, 1, count, stdout);
8192 int width = get_term_width();
8193 int len = wrap(NULL, message, count, width, &line);
8194 char *msg = malloc(len);
8198 outCount = fwrite(message, 1, count, stdout);
8201 dbgchk = wrap(msg, message, count, width, &line);
8202 if (dbgchk != len && appData.debugMode)
8203 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8204 outCount = fwrite(msg, 1, dbgchk, stdout);
8210 outCount = write(cp->fdTo, message, count);
8220 /* Output message to process, with "ms" milliseconds of delay
8221 between each character. This is needed when sending the logon
8222 script to ICC, which for some reason doesn't like the
8223 instantaneous send. */
8224 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8231 ChildProc *cp = (ChildProc *) pr;
8236 r = write(cp->fdTo, message++, 1);
8249 /**** Animation code by Hugh Fisher, DCS, ANU.
8251 Known problem: if a window overlapping the board is
8252 moved away while a piece is being animated underneath,
8253 the newly exposed area won't be updated properly.
8254 I can live with this.
8256 Known problem: if you look carefully at the animation
8257 of pieces in mono mode, they are being drawn as solid
8258 shapes without interior detail while moving. Fixing
8259 this would be a major complication for minimal return.
8262 /* Masks for XPM pieces. Black and white pieces can have
8263 different shapes, but in the interest of retaining my
8264 sanity pieces must have the same outline on both light
8265 and dark squares, and all pieces must use the same
8266 background square colors/images. */
8268 static int xpmDone = 0;
8271 CreateAnimMasks (pieceDepth)
8278 unsigned long plane;
8281 /* Need a bitmap just to get a GC with right depth */
8282 buf = XCreatePixmap(xDisplay, xBoardWindow,
8284 values.foreground = 1;
8285 values.background = 0;
8286 /* Don't use XtGetGC, not read only */
8287 maskGC = XCreateGC(xDisplay, buf,
8288 GCForeground | GCBackground, &values);
8289 XFreePixmap(xDisplay, buf);
8291 buf = XCreatePixmap(xDisplay, xBoardWindow,
8292 squareSize, squareSize, pieceDepth);
8293 values.foreground = XBlackPixel(xDisplay, xScreen);
8294 values.background = XWhitePixel(xDisplay, xScreen);
8295 bufGC = XCreateGC(xDisplay, buf,
8296 GCForeground | GCBackground, &values);
8298 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8299 /* Begin with empty mask */
8300 if(!xpmDone) // [HGM] pieces: keep using existing
8301 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8302 squareSize, squareSize, 1);
8303 XSetFunction(xDisplay, maskGC, GXclear);
8304 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8305 0, 0, squareSize, squareSize);
8307 /* Take a copy of the piece */
8312 XSetFunction(xDisplay, bufGC, GXcopy);
8313 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8315 0, 0, squareSize, squareSize, 0, 0);
8317 /* XOR the background (light) over the piece */
8318 XSetFunction(xDisplay, bufGC, GXxor);
8320 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8321 0, 0, squareSize, squareSize, 0, 0);
8323 XSetForeground(xDisplay, bufGC, lightSquareColor);
8324 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8327 /* We now have an inverted piece image with the background
8328 erased. Construct mask by just selecting all the non-zero
8329 pixels - no need to reconstruct the original image. */
8330 XSetFunction(xDisplay, maskGC, GXor);
8332 /* Might be quicker to download an XImage and create bitmap
8333 data from it rather than this N copies per piece, but it
8334 only takes a fraction of a second and there is a much
8335 longer delay for loading the pieces. */
8336 for (n = 0; n < pieceDepth; n ++) {
8337 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8338 0, 0, squareSize, squareSize,
8344 XFreePixmap(xDisplay, buf);
8345 XFreeGC(xDisplay, bufGC);
8346 XFreeGC(xDisplay, maskGC);
8350 InitAnimState (anim, info)
8352 XWindowAttributes * info;
8357 /* Each buffer is square size, same depth as window */
8358 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8359 squareSize, squareSize, info->depth);
8360 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8361 squareSize, squareSize, info->depth);
8363 /* Create a plain GC for blitting */
8364 mask = GCForeground | GCBackground | GCFunction |
8365 GCPlaneMask | GCGraphicsExposures;
8366 values.foreground = XBlackPixel(xDisplay, xScreen);
8367 values.background = XWhitePixel(xDisplay, xScreen);
8368 values.function = GXcopy;
8369 values.plane_mask = AllPlanes;
8370 values.graphics_exposures = False;
8371 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8373 /* Piece will be copied from an existing context at
8374 the start of each new animation/drag. */
8375 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8377 /* Outline will be a read-only copy of an existing */
8378 anim->outlineGC = None;
8384 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8385 XWindowAttributes info;
8387 if (xpmDone && gameInfo.variant == old) return;
8388 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8389 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8391 InitAnimState(&game, &info);
8392 InitAnimState(&player, &info);
8394 /* For XPM pieces, we need bitmaps to use as masks. */
8396 CreateAnimMasks(info.depth);
8402 static Boolean frameWaiting;
8404 static RETSIGTYPE FrameAlarm (sig)
8407 frameWaiting = False;
8408 /* In case System-V style signals. Needed?? */
8409 signal(SIGALRM, FrameAlarm);
8416 struct itimerval delay;
8418 XSync(xDisplay, False);
8421 frameWaiting = True;
8422 signal(SIGALRM, FrameAlarm);
8423 delay.it_interval.tv_sec =
8424 delay.it_value.tv_sec = time / 1000;
8425 delay.it_interval.tv_usec =
8426 delay.it_value.tv_usec = (time % 1000) * 1000;
8427 setitimer(ITIMER_REAL, &delay, NULL);
8428 while (frameWaiting) pause();
8429 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8430 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8431 setitimer(ITIMER_REAL, &delay, NULL);
8441 XSync(xDisplay, False);
8443 usleep(time * 1000);
8448 /* Convert board position to corner of screen rect and color */
8451 ScreenSquare(column, row, pt, color)
8452 int column; int row; XPoint * pt; int * color;
8455 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8456 pt->y = lineGap + row * (squareSize + lineGap);
8458 pt->x = lineGap + column * (squareSize + lineGap);
8459 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8461 *color = SquareColor(row, column);
8464 /* Convert window coords to square */
8467 BoardSquare(x, y, column, row)
8468 int x; int y; int * column; int * row;
8470 *column = EventToSquare(x, BOARD_WIDTH);
8471 if (flipView && *column >= 0)
8472 *column = BOARD_WIDTH - 1 - *column;
8473 *row = EventToSquare(y, BOARD_HEIGHT);
8474 if (!flipView && *row >= 0)
8475 *row = BOARD_HEIGHT - 1 - *row;
8480 #undef Max /* just in case */
8482 #define Max(a, b) ((a) > (b) ? (a) : (b))
8483 #define Min(a, b) ((a) < (b) ? (a) : (b))
8486 SetRect(rect, x, y, width, height)
8487 XRectangle * rect; int x; int y; int width; int height;
8491 rect->width = width;
8492 rect->height = height;
8495 /* Test if two frames overlap. If they do, return
8496 intersection rect within old and location of
8497 that rect within new. */
8500 Intersect(old, new, size, area, pt)
8501 XPoint * old; XPoint * new;
8502 int size; XRectangle * area; XPoint * pt;
8504 if (old->x > new->x + size || new->x > old->x + size ||
8505 old->y > new->y + size || new->y > old->y + size) {
8508 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8509 size - abs(old->x - new->x), size - abs(old->y - new->y));
8510 pt->x = Max(old->x - new->x, 0);
8511 pt->y = Max(old->y - new->y, 0);
8516 /* For two overlapping frames, return the rect(s)
8517 in the old that do not intersect with the new. */
8520 CalcUpdateRects(old, new, size, update, nUpdates)
8521 XPoint * old; XPoint * new; int size;
8522 XRectangle update[]; int * nUpdates;
8526 /* If old = new (shouldn't happen) then nothing to draw */
8527 if (old->x == new->x && old->y == new->y) {
8531 /* Work out what bits overlap. Since we know the rects
8532 are the same size we don't need a full intersect calc. */
8534 /* Top or bottom edge? */
8535 if (new->y > old->y) {
8536 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8538 } else if (old->y > new->y) {
8539 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8540 size, old->y - new->y);
8543 /* Left or right edge - don't overlap any update calculated above. */
8544 if (new->x > old->x) {
8545 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8546 new->x - old->x, size - abs(new->y - old->y));
8548 } else if (old->x > new->x) {
8549 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8550 old->x - new->x, size - abs(new->y - old->y));
8557 /* Generate a series of frame coords from start->mid->finish.
8558 The movement rate doubles until the half way point is
8559 reached, then halves back down to the final destination,
8560 which gives a nice slow in/out effect. The algorithmn
8561 may seem to generate too many intermediates for short
8562 moves, but remember that the purpose is to attract the
8563 viewers attention to the piece about to be moved and
8564 then to where it ends up. Too few frames would be less
8568 Tween(start, mid, finish, factor, frames, nFrames)
8569 XPoint * start; XPoint * mid;
8570 XPoint * finish; int factor;
8571 XPoint frames[]; int * nFrames;
8573 int fraction, n, count;
8577 /* Slow in, stepping 1/16th, then 1/8th, ... */
8579 for (n = 0; n < factor; n++)
8581 for (n = 0; n < factor; n++) {
8582 frames[count].x = start->x + (mid->x - start->x) / fraction;
8583 frames[count].y = start->y + (mid->y - start->y) / fraction;
8585 fraction = fraction / 2;
8589 frames[count] = *mid;
8592 /* Slow out, stepping 1/2, then 1/4, ... */
8594 for (n = 0; n < factor; n++) {
8595 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8596 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8598 fraction = fraction * 2;
8603 /* Draw a piece on the screen without disturbing what's there */
8606 SelectGCMask(piece, clip, outline, mask)
8607 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8611 /* Bitmap for piece being moved. */
8612 if (appData.monoMode) {
8613 *mask = *pieceToSolid(piece);
8614 } else if (useImages) {
8616 *mask = xpmMask[piece];
8618 *mask = ximMaskPm[piece];
8621 *mask = *pieceToSolid(piece);
8624 /* GC for piece being moved. Square color doesn't matter, but
8625 since it gets modified we make a copy of the original. */
8627 if (appData.monoMode)
8632 if (appData.monoMode)
8637 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8639 /* Outline only used in mono mode and is not modified */
8641 *outline = bwPieceGC;
8643 *outline = wbPieceGC;
8647 OverlayPiece(piece, clip, outline, dest)
8648 ChessSquare piece; GC clip; GC outline; Drawable dest;
8653 /* Draw solid rectangle which will be clipped to shape of piece */
8654 XFillRectangle(xDisplay, dest, clip,
8655 0, 0, squareSize, squareSize);
8656 if (appData.monoMode)
8657 /* Also draw outline in contrasting color for black
8658 on black / white on white cases */
8659 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8660 0, 0, squareSize, squareSize, 0, 0, 1);
8662 /* Copy the piece */
8667 if(appData.upsideDown && flipView) kind ^= 2;
8668 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8670 0, 0, squareSize, squareSize,
8675 /* Animate the movement of a single piece */
8678 BeginAnimation(anim, piece, startColor, start)
8686 if(appData.upsideDown && flipView) piece += piece < BlackPawn ? BlackPawn : -BlackPawn;
8687 /* The old buffer is initialised with the start square (empty) */
8688 BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0);
8689 anim->prevFrame = *start;
8691 /* The piece will be drawn using its own bitmap as a matte */
8692 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8693 XSetClipMask(xDisplay, anim->pieceGC, mask);
8697 AnimationFrame(anim, frame, piece)
8702 XRectangle updates[4];
8707 /* Save what we are about to draw into the new buffer */
8708 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8709 frame->x, frame->y, squareSize, squareSize,
8712 /* Erase bits of the previous frame */
8713 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8714 /* Where the new frame overlapped the previous,
8715 the contents in newBuf are wrong. */
8716 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8717 overlap.x, overlap.y,
8718 overlap.width, overlap.height,
8720 /* Repaint the areas in the old that don't overlap new */
8721 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8722 for (i = 0; i < count; i++)
8723 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8724 updates[i].x - anim->prevFrame.x,
8725 updates[i].y - anim->prevFrame.y,
8726 updates[i].width, updates[i].height,
8727 updates[i].x, updates[i].y);
8729 /* Easy when no overlap */
8730 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8731 0, 0, squareSize, squareSize,
8732 anim->prevFrame.x, anim->prevFrame.y);
8735 /* Save this frame for next time round */
8736 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8737 0, 0, squareSize, squareSize,
8739 anim->prevFrame = *frame;
8741 /* Draw piece over original screen contents, not current,
8742 and copy entire rect. Wipes out overlapping piece images. */
8743 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8744 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8745 0, 0, squareSize, squareSize,
8746 frame->x, frame->y);
8750 EndAnimation (anim, finish)
8754 XRectangle updates[4];
8759 /* The main code will redraw the final square, so we
8760 only need to erase the bits that don't overlap. */
8761 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8762 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8763 for (i = 0; i < count; i++)
8764 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8765 updates[i].x - anim->prevFrame.x,
8766 updates[i].y - anim->prevFrame.y,
8767 updates[i].width, updates[i].height,
8768 updates[i].x, updates[i].y);
8770 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8771 0, 0, squareSize, squareSize,
8772 anim->prevFrame.x, anim->prevFrame.y);
8777 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8779 ChessSquare piece; int startColor;
8780 XPoint * start; XPoint * finish;
8781 XPoint frames[]; int nFrames;
8785 BeginAnimation(anim, piece, startColor, start);
8786 for (n = 0; n < nFrames; n++) {
8787 AnimationFrame(anim, &(frames[n]), piece);
8788 FrameDelay(appData.animSpeed);
8790 EndAnimation(anim, finish);
8794 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
8797 ChessSquare piece = board[fromY][toY];
8798 board[fromY][toY] = EmptySquare;
8799 DrawPosition(FALSE, board);
8801 x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap);
8802 y = lineGap + toY * (squareSize + lineGap);
8804 x = lineGap + toX * (squareSize + lineGap);
8805 y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap);
8807 for(i=1; i<4*kFactor; i++) {
8808 int r = squareSize * 9 * i/(20*kFactor - 5);
8809 XFillArc(xDisplay, xBoardWindow, highlineGC,
8810 x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360);
8811 FrameDelay(appData.animSpeed);
8813 board[fromY][toY] = piece;
8816 /* Main control logic for deciding what to animate and how */
8819 AnimateMove(board, fromX, fromY, toX, toY)
8828 XPoint start, finish, mid;
8829 XPoint frames[kFactor * 2 + 1];
8830 int nFrames, startColor, endColor;
8832 /* Are we animating? */
8833 if (!appData.animate || appData.blindfold)
8836 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8837 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8838 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8840 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8841 piece = board[fromY][fromX];
8842 if (piece >= EmptySquare) return;
8847 hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1;
8850 if (appData.debugMode) {
8851 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8852 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8853 piece, fromX, fromY, toX, toY); }
8855 ScreenSquare(fromX, fromY, &start, &startColor);
8856 ScreenSquare(toX, toY, &finish, &endColor);
8859 /* Knight: make straight movement then diagonal */
8860 if (abs(toY - fromY) < abs(toX - fromX)) {
8861 mid.x = start.x + (finish.x - start.x) / 2;
8865 mid.y = start.y + (finish.y - start.y) / 2;
8868 mid.x = start.x + (finish.x - start.x) / 2;
8869 mid.y = start.y + (finish.y - start.y) / 2;
8872 /* Don't use as many frames for very short moves */
8873 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8874 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8876 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8877 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8878 if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
8880 for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
8881 if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
8884 /* Be sure end square is redrawn */
8885 damage[0][toY][toX] = True;
8889 DragPieceBegin(x, y)
8892 int boardX, boardY, color;
8895 /* Are we animating? */
8896 if (!appData.animateDragging || appData.blindfold)
8899 /* Figure out which square we start in and the
8900 mouse position relative to top left corner. */
8901 BoardSquare(x, y, &boardX, &boardY);
8902 player.startBoardX = boardX;
8903 player.startBoardY = boardY;
8904 ScreenSquare(boardX, boardY, &corner, &color);
8905 player.startSquare = corner;
8906 player.startColor = color;
8907 /* As soon as we start dragging, the piece will jump slightly to
8908 be centered over the mouse pointer. */
8909 player.mouseDelta.x = squareSize/2;
8910 player.mouseDelta.y = squareSize/2;
8911 /* Initialise animation */
8912 player.dragPiece = PieceForSquare(boardX, boardY);
8914 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8915 player.dragActive = True;
8916 BeginAnimation(&player, player.dragPiece, color, &corner);
8917 /* Mark this square as needing to be redrawn. Note that
8918 we don't remove the piece though, since logically (ie
8919 as seen by opponent) the move hasn't been made yet. */
8920 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8921 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8922 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8923 corner.x, corner.y, squareSize, squareSize,
8924 0, 0); // [HGM] zh: unstack in stead of grab
8925 if(gatingPiece != EmptySquare) {
8926 /* Kludge alert: When gating we want the introduced
8927 piece to appear on the from square. To generate an
8928 image of it, we draw it on the board, copy the image,
8929 and draw the original piece again. */
8930 ChessSquare piece = boards[currentMove][boardY][boardX];
8931 DrawSquare(boardY, boardX, gatingPiece, 0);
8932 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8933 corner.x, corner.y, squareSize, squareSize, 0, 0);
8934 DrawSquare(boardY, boardX, piece, 0);
8936 damage[0][boardY][boardX] = True;
8938 player.dragActive = False;
8948 /* Are we animating? */
8949 if (!appData.animateDragging || appData.blindfold)
8953 if (! player.dragActive)
8955 /* Move piece, maintaining same relative position
8956 of mouse within square */
8957 corner.x = x - player.mouseDelta.x;
8958 corner.y = y - player.mouseDelta.y;
8959 AnimationFrame(&player, &corner, player.dragPiece);
8961 if (appData.highlightDragging) {
8963 BoardSquare(x, y, &boardX, &boardY);
8964 SetHighlights(fromX, fromY, boardX, boardY);
8973 int boardX, boardY, color;
8976 /* Are we animating? */
8977 if (!appData.animateDragging || appData.blindfold)
8981 if (! player.dragActive)
8983 /* Last frame in sequence is square piece is
8984 placed on, which may not match mouse exactly. */
8985 BoardSquare(x, y, &boardX, &boardY);
8986 ScreenSquare(boardX, boardY, &corner, &color);
8987 EndAnimation(&player, &corner);
8989 /* Be sure end square is redrawn */
8990 damage[0][boardY][boardX] = True;
8992 /* This prevents weird things happening with fast successive
8993 clicks which on my Sun at least can cause motion events
8994 without corresponding press/release. */
8995 player.dragActive = False;
8998 /* Handle expose event while piece being dragged */
9003 if (!player.dragActive || appData.blindfold)
9006 /* What we're doing: logically, the move hasn't been made yet,
9007 so the piece is still in it's original square. But visually
9008 it's being dragged around the board. So we erase the square
9009 that the piece is on and draw it at the last known drag point. */
9010 BlankSquare(player.startSquare.x, player.startSquare.y,
9011 player.startColor, EmptySquare, xBoardWindow, 1);
9012 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
9013 damage[0][player.startBoardY][player.startBoardX] = TRUE;
9016 #include <sys/ioctl.h>
9017 int get_term_width()
9019 int fd, default_width;
9022 default_width = 79; // this is FICS default anyway...
9024 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
9026 if (!ioctl(fd, TIOCGSIZE, &win))
9027 default_width = win.ts_cols;
9028 #elif defined(TIOCGWINSZ)
9030 if (!ioctl(fd, TIOCGWINSZ, &win))
9031 default_width = win.ws_col;
9033 return default_width;
9039 static int old_width = 0;
9040 int new_width = get_term_width();
9042 if (old_width != new_width)
9043 ics_printf("set width %d\n", new_width);
9044 old_width = new_width;
9047 void NotifyFrontendLogin()
9052 /* [AS] Arrow highlighting support */
9054 static double A_WIDTH = 5; /* Width of arrow body */
9056 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
9057 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
9059 static double Sqr( double x )
9064 static int Round( double x )
9066 return (int) (x + 0.5);
9069 void SquareToPos(int rank, int file, int *x, int *y)
9072 *x = lineGap + ((BOARD_WIDTH-1)-file) * (squareSize + lineGap);
9073 *y = lineGap + rank * (squareSize + lineGap);
9075 *x = lineGap + file * (squareSize + lineGap);
9076 *y = lineGap + ((BOARD_HEIGHT-1)-rank) * (squareSize + lineGap);
9080 /* Draw an arrow between two points using current settings */
9081 void DrawArrowBetweenPoints( int s_x, int s_y, int d_x, int d_y )
9084 double dx, dy, j, k, x, y;
9087 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
9089 arrow[0].x = s_x + A_WIDTH + 0.5;
9092 arrow[1].x = s_x + A_WIDTH + 0.5;
9093 arrow[1].y = d_y - h;
9095 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9096 arrow[2].y = d_y - h;
9101 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
9102 arrow[5].y = d_y - h;
9104 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9105 arrow[4].y = d_y - h;
9107 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
9110 else if( d_y == s_y ) {
9111 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
9114 arrow[0].y = s_y + A_WIDTH + 0.5;
9116 arrow[1].x = d_x - w;
9117 arrow[1].y = s_y + A_WIDTH + 0.5;
9119 arrow[2].x = d_x - w;
9120 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9125 arrow[5].x = d_x - w;
9126 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
9128 arrow[4].x = d_x - w;
9129 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9132 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
9135 /* [AS] Needed a lot of paper for this! :-) */
9136 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
9137 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
9139 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
9141 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
9146 arrow[0].x = Round(x - j);
9147 arrow[0].y = Round(y + j*dx);
9149 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
9150 arrow[1].y = Round(arrow[0].y - 2*j*dx);
9153 x = (double) d_x - k;
9154 y = (double) d_y - k*dy;
9157 x = (double) d_x + k;
9158 y = (double) d_y + k*dy;
9161 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
9163 arrow[6].x = Round(x - j);
9164 arrow[6].y = Round(y + j*dx);
9166 arrow[2].x = Round(arrow[6].x + 2*j);
9167 arrow[2].y = Round(arrow[6].y - 2*j*dx);
9169 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
9170 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
9175 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
9176 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
9179 XFillPolygon(xDisplay, xBoardWindow, highlineGC, arrow, 7, Nonconvex, CoordModeOrigin);
9180 // Polygon( hdc, arrow, 7 );
9183 /* [AS] Draw an arrow between two squares */
9184 void DrawArrowBetweenSquares( int s_col, int s_row, int d_col, int d_row )
9186 int s_x, s_y, d_x, d_y, hor, vert, i;
9188 if( s_col == d_col && s_row == d_row ) {
9192 /* Get source and destination points */
9193 SquareToPos( s_row, s_col, &s_x, &s_y);
9194 SquareToPos( d_row, d_col, &d_x, &d_y);
9197 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
9199 else if( d_y < s_y ) {
9200 d_y += squareSize / 2 + squareSize / 4;
9203 d_y += squareSize / 2;
9207 d_x += squareSize / 2 - squareSize / 4;
9209 else if( d_x < s_x ) {
9210 d_x += squareSize / 2 + squareSize / 4;
9213 d_x += squareSize / 2;
9216 s_x += squareSize / 2;
9217 s_y += squareSize / 2;
9220 A_WIDTH = squareSize / 14.; //[HGM] make float
9222 DrawArrowBetweenPoints( s_x, s_y, d_x, d_y );
9224 hor = 64*s_col + 32; vert = 64*s_row + 32;
9225 for(i=0; i<= 64; i++) {
9226 damage[0][vert+6>>6][hor+6>>6] = True;
9227 damage[0][vert-6>>6][hor+6>>6] = True;
9228 damage[0][vert+6>>6][hor-6>>6] = True;
9229 damage[0][vert-6>>6][hor-6>>6] = True;
9230 hor += d_col - s_col; vert += d_row - s_row;
9234 Boolean IsDrawArrowEnabled()
9236 return appData.highlightMoveWithArrow && squareSize >= 32;
9239 void DrawArrowHighlight(int fromX, int fromY, int toX,int toY)
9241 if( IsDrawArrowEnabled() && fromX >= 0 && fromY >= 0 && toX >= 0 && toY >= 0)
9242 DrawArrowBetweenSquares(fromX, fromY, toX, toY);