2 * xboard.c -- X front end for XBoard
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
8 * 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
10 * The following terms apply to Digital Equipment Corporation's copyright
12 * ------------------------------------------------------------------------
15 * Permission to use, copy, modify, and distribute this software and its
16 * documentation for any purpose and without fee is hereby granted,
17 * provided that the above copyright notice appear in all copies and that
18 * both that copyright notice and this permission notice appear in
19 * supporting documentation, and that the name of Digital not be
20 * used in advertising or publicity pertaining to distribution of the
21 * software without specific, written prior permission.
23 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
30 * ------------------------------------------------------------------------
32 * The following terms apply to the enhanced version of XBoard
33 * distributed by the Free Software Foundation:
34 * ------------------------------------------------------------------------
36 * GNU XBoard is free software: you can redistribute it and/or modify
37 * it under the terms of the GNU General Public License as published by
38 * the Free Software Foundation, either version 3 of the License, or (at
39 * your option) any later version.
41 * GNU XBoard is distributed in the hope that it will be useful, but
42 * WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44 * General Public License for more details.
46 * You should have received a copy of the GNU General Public License
47 * along with this program. If not, see http://www.gnu.org/licenses/. *
49 *------------------------------------------------------------------------
50 ** See the file ChangeLog for a revision history. */
60 #include <sys/types.h>
66 # if HAVE_SYS_SOCKET_H
67 # include <sys/socket.h>
68 # include <netinet/in.h>
70 # else /* not HAVE_SYS_SOCKET_H */
71 # if HAVE_LAN_SOCKET_H
72 # include <lan/socket.h>
74 # include <lan/netdb.h>
75 # else /* not HAVE_LAN_SOCKET_H */
76 # define OMIT_SOCKETS 1
77 # endif /* not HAVE_LAN_SOCKET_H */
78 # endif /* not HAVE_SYS_SOCKET_H */
79 #endif /* !OMIT_SOCKETS */
84 #else /* not STDC_HEADERS */
85 extern char *getenv();
88 # else /* not HAVE_STRING_H */
90 # endif /* not HAVE_STRING_H */
91 #endif /* not STDC_HEADERS */
94 # include <sys/fcntl.h>
95 #else /* not HAVE_SYS_FCNTL_H */
98 # endif /* HAVE_FCNTL_H */
99 #endif /* not HAVE_SYS_FCNTL_H */
101 #if HAVE_SYS_SYSTEMINFO_H
102 # include <sys/systeminfo.h>
103 #endif /* HAVE_SYS_SYSTEMINFO_H */
105 #if TIME_WITH_SYS_TIME
106 # include <sys/time.h>
110 # include <sys/time.h>
121 # include <sys/wait.h>
126 # define NAMLEN(dirent) strlen((dirent)->d_name)
127 # define HAVE_DIR_STRUCT
129 # define dirent direct
130 # define NAMLEN(dirent) (dirent)->d_namlen
132 # include <sys/ndir.h>
133 # define HAVE_DIR_STRUCT
136 # include <sys/dir.h>
137 # define HAVE_DIR_STRUCT
141 # define HAVE_DIR_STRUCT
145 #include <X11/Intrinsic.h>
146 #include <X11/StringDefs.h>
147 #include <X11/Shell.h>
148 #include <X11/cursorfont.h>
149 #include <X11/Xatom.h>
150 #include <X11/Xmu/Atoms.h>
152 #include <X11/Xaw3d/Dialog.h>
153 #include <X11/Xaw3d/Form.h>
154 #include <X11/Xaw3d/List.h>
155 #include <X11/Xaw3d/Label.h>
156 #include <X11/Xaw3d/SimpleMenu.h>
157 #include <X11/Xaw3d/SmeBSB.h>
158 #include <X11/Xaw3d/SmeLine.h>
159 #include <X11/Xaw3d/Box.h>
160 #include <X11/Xaw3d/MenuButton.h>
161 #include <X11/Xaw3d/Text.h>
162 #include <X11/Xaw3d/AsciiText.h>
164 #include <X11/Xaw/Dialog.h>
165 #include <X11/Xaw/Form.h>
166 #include <X11/Xaw/List.h>
167 #include <X11/Xaw/Label.h>
168 #include <X11/Xaw/SimpleMenu.h>
169 #include <X11/Xaw/SmeBSB.h>
170 #include <X11/Xaw/SmeLine.h>
171 #include <X11/Xaw/Box.h>
172 #include <X11/Xaw/MenuButton.h>
173 #include <X11/Xaw/Text.h>
174 #include <X11/Xaw/AsciiText.h>
177 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
182 #include "pixmaps/pixmaps.h"
183 #define IMAGE_EXT "xpm"
185 #define IMAGE_EXT "xim"
186 #include "bitmaps/bitmaps.h"
189 #include "bitmaps/icon_white.bm"
190 #include "bitmaps/icon_black.bm"
191 #include "bitmaps/checkmark.bm"
193 #include "frontend.h"
195 #include "backendz.h"
199 #include "xgamelist.h"
200 #include "xhistory.h"
201 #include "xedittags.h"
204 // must be moved to xengineoutput.h
206 void EngineOutputProc P((Widget w, XEvent *event,
207 String *prms, Cardinal *nprms));
208 void EvalGraphProc P((Widget w, XEvent *event,
209 String *prms, Cardinal *nprms));
216 #define usleep(t) _sleep2(((t)+500)/1000)
220 # define _(s) gettext (s)
221 # define N_(s) gettext_noop (s)
239 int main P((int argc, char **argv));
240 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
241 char *init_path, char *mode, int (*show_entry)(), char **name_return));
242 RETSIGTYPE CmailSigHandler P((int sig));
243 RETSIGTYPE IntSigHandler P((int sig));
244 RETSIGTYPE TermSizeSigHandler P((int sig));
245 void CreateGCs P((int redo));
246 void CreateXIMPieces P((void));
247 void CreateXPMPieces P((void));
248 void CreateXPMBoard P((char *s, int n));
249 void CreatePieces P((void));
250 void CreatePieceMenus P((void));
251 Widget CreateMenuBar P((Menu *mb));
252 Widget CreateButtonBar P ((MenuItem *mi));
253 char *FindFont P((char *pattern, int targetPxlSize));
254 void PieceMenuPopup P((Widget w, XEvent *event,
255 String *params, Cardinal *num_params));
256 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
257 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
258 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
259 u_int wreq, u_int hreq));
260 void CreateGrid P((void));
261 int EventToSquare P((int x, int limit));
262 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
263 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
264 void HandleUserMove P((Widget w, XEvent *event,
265 String *prms, Cardinal *nprms));
266 void AnimateUserMove P((Widget w, XEvent * event,
267 String * params, Cardinal * nParams));
268 void HandlePV P((Widget w, XEvent * event,
269 String * params, Cardinal * nParams));
270 void SelectPV P((Widget w, XEvent * event,
271 String * params, Cardinal * nParams));
272 void StopPV P((Widget w, XEvent * event,
273 String * params, Cardinal * nParams));
274 void WhiteClock P((Widget w, XEvent *event,
275 String *prms, Cardinal *nprms));
276 void BlackClock P((Widget w, XEvent *event,
277 String *prms, Cardinal *nprms));
278 void DrawPositionProc P((Widget w, XEvent *event,
279 String *prms, Cardinal *nprms));
280 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
282 void CommentClick P((Widget w, XEvent * event,
283 String * params, Cardinal * nParams));
284 void CommentPopUp P((char *title, char *label));
285 void CommentPopDown P((void));
286 void CommentCallback P((Widget w, XtPointer client_data,
287 XtPointer call_data));
288 void ICSInputBoxPopUp P((void));
289 void ICSInputBoxPopDown P((void));
290 void FileNamePopUp P((char *label, char *def,
291 FileProc proc, char *openMode));
292 void FileNamePopDown P((void));
293 void FileNameCallback P((Widget w, XtPointer client_data,
294 XtPointer call_data));
295 void FileNameAction P((Widget w, XEvent *event,
296 String *prms, Cardinal *nprms));
297 void AskQuestionReplyAction P((Widget w, XEvent *event,
298 String *prms, Cardinal *nprms));
299 void AskQuestionProc P((Widget w, XEvent *event,
300 String *prms, Cardinal *nprms));
301 void AskQuestionPopDown P((void));
302 void PromotionPopDown P((void));
303 void PromotionCallback P((Widget w, XtPointer client_data,
304 XtPointer call_data));
305 void EditCommentPopDown P((void));
306 void EditCommentCallback P((Widget w, XtPointer client_data,
307 XtPointer call_data));
308 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
309 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
310 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
311 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
313 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
315 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
317 void LoadPositionProc P((Widget w, XEvent *event,
318 String *prms, Cardinal *nprms));
319 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
321 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
323 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
325 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
327 void PastePositionProc P((Widget w, XEvent *event, String *prms,
329 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
330 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
331 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
332 void SavePositionProc P((Widget w, XEvent *event,
333 String *prms, Cardinal *nprms));
334 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
335 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
337 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
338 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
339 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
341 void MachineWhiteProc P((Widget w, XEvent *event,
342 String *prms, Cardinal *nprms));
343 void AnalyzeModeProc P((Widget w, XEvent *event,
344 String *prms, Cardinal *nprms));
345 void AnalyzeFileProc P((Widget w, XEvent *event,
346 String *prms, Cardinal *nprms));
347 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
349 void IcsClientProc P((Widget w, XEvent *event, String *prms,
351 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
352 void EditPositionProc P((Widget w, XEvent *event,
353 String *prms, Cardinal *nprms));
354 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
355 void EditCommentProc P((Widget w, XEvent *event,
356 String *prms, Cardinal *nprms));
357 void IcsInputBoxProc P((Widget w, XEvent *event,
358 String *prms, Cardinal *nprms));
359 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
365 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
370 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
371 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
372 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
373 void StopObservingProc P((Widget w, XEvent *event, String *prms,
375 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
377 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
379 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
380 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
384 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
386 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
388 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
389 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
391 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
393 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
395 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
396 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
397 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
398 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
400 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
401 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
403 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
405 void HighlightArrowProc P((Widget w, XEvent *event, String *prms,
407 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
408 //void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
409 void OneClickProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
410 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
412 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
414 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
416 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
418 //void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
419 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
421 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
423 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
425 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
427 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
428 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
429 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
430 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
431 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
432 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
433 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
434 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
435 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
436 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void DisplayMove P((int moveNumber));
439 void DisplayTitle P((char *title));
440 void ICSInitScript P((void));
441 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
442 void ErrorPopUp P((char *title, char *text, int modal));
443 void ErrorPopDown P((void));
444 static char *ExpandPathName P((char *path));
445 static void CreateAnimVars P((void));
446 static void DragPieceMove P((int x, int y));
447 static void DrawDragPiece P((void));
448 char *ModeToWidgetName P((GameMode mode));
449 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
450 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
451 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
452 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
453 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
454 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
455 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
456 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
457 void BoardOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
458 void IcsOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
459 void LoadOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
460 void SaveOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
461 void GameListOptionsPopDown P(());
462 void ShufflePopDown P(());
463 void EnginePopDown P(());
464 void UciPopDown P(());
465 void TimeControlPopDown P(());
466 void NewVariantPopDown P(());
467 void SettingsPopDown P(());
468 void update_ics_width P(());
469 int get_term_width P(());
470 int CopyMemoProc P(());
471 void DrawArrowHighlight P((int fromX, int fromY, int toX,int toY));
472 Boolean IsDrawArrowEnabled P(());
475 * XBoard depends on Xt R4 or higher
477 int xtVersion = XtSpecificationRelease;
482 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
483 jailSquareColor, highlightSquareColor, premoveHighlightColor;
484 Pixel lowTimeWarningColor;
485 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
486 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
487 wjPieceGC, bjPieceGC, prelineGC, countGC;
488 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
489 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
490 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
491 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
492 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
493 ICSInputShell, fileNameShell, askQuestionShell;
494 Widget historyShell, evalGraphShell, gameListShell;
495 int hOffset; // [HGM] dual
496 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
497 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
498 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
499 Font clockFontID, coordFontID, countFontID;
500 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
501 XtAppContext appContext;
503 char *oldICSInteractionTitle;
507 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
509 Position commentX = -1, commentY = -1;
510 Dimension commentW, commentH;
511 typedef unsigned int BoardSize;
513 Boolean chessProgram;
515 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
516 int squareSize, smallLayout = 0, tinyLayout = 0,
517 marginW, marginH, // [HGM] for run-time resizing
518 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
519 ICSInputBoxUp = False, askQuestionUp = False,
520 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
521 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
522 Pixel timerForegroundPixel, timerBackgroundPixel;
523 Pixel buttonForegroundPixel, buttonBackgroundPixel;
524 char *chessDir, *programName, *programVersion,
525 *gameCopyFilename, *gamePasteFilename;
526 Boolean alwaysOnTop = False;
527 Boolean saveSettingsOnExit;
528 char *settingsFileName;
529 char *icsTextMenuString;
531 char *firstChessProgramNames;
532 char *secondChessProgramNames;
534 WindowPlacement wpMain;
535 WindowPlacement wpConsole;
536 WindowPlacement wpComment;
537 WindowPlacement wpMoveHistory;
538 WindowPlacement wpEvalGraph;
539 WindowPlacement wpEngineOutput;
540 WindowPlacement wpGameList;
541 WindowPlacement wpTags;
545 Pixmap pieceBitmap[2][(int)BlackPawn];
546 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
547 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
548 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
549 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
550 Pixmap xpmBoardBitmap[2];
551 int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
552 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
553 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
554 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
555 XImage *ximLightSquare, *ximDarkSquare;
558 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
559 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
561 #define White(piece) ((int)(piece) < (int)BlackPawn)
563 /* Variables for doing smooth animation. This whole thing
564 would be much easier if the board was double-buffered,
565 but that would require a fairly major rewrite. */
570 GC blitGC, pieceGC, outlineGC;
571 XPoint startSquare, prevFrame, mouseDelta;
575 int startBoardX, startBoardY;
578 /* There can be two pieces being animated at once: a player
579 can begin dragging a piece before the remote opponent has moved. */
581 static AnimState game, player;
583 /* Bitmaps for use as masks when drawing XPM pieces.
584 Need one for each black and white piece. */
585 static Pixmap xpmMask[BlackKing + 1];
587 /* This magic number is the number of intermediate frames used
588 in each half of the animation. For short moves it's reduced
589 by 1. The total number of frames will be factor * 2 + 1. */
592 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
594 MenuItem fileMenu[] = {
595 {N_("New Game Ctrl+N"), "New Game", ResetProc},
596 {N_("New Shuffle Game ..."), "New Shuffle Game", ShuffleMenuProc},
597 {N_("New Variant ... Alt+Shift+V"), "New Variant", NewVariantProc}, // [HGM] variant: not functional yet
598 {"----", NULL, NothingProc},
599 {N_("Load Game Ctrl+O"), "Load Game", LoadGameProc},
600 {N_("Load Position Ctrl+Shift+O"), "Load Position", LoadPositionProc},
601 // {N_("Load Next Game"), "Load Next Game", LoadNextGameProc},
602 // {N_("Load Previous Game"), "Load Previous Game", LoadPrevGameProc},
603 // {N_("Reload Same Game"), "Reload Same Game", ReloadGameProc},
604 {N_("Next Position Shift+PgDn"), "Load Next Position", LoadNextPositionProc},
605 {N_("Prev Position Shift+PgUp"), "Load Previous Position", LoadPrevPositionProc},
606 {"----", NULL, NothingProc},
607 // {N_("Reload Same Position"), "Reload Same Position", ReloadPositionProc},
608 {N_("Save Game Ctrl+S"), "Save Game", SaveGameProc},
609 {N_("Save Position Ctrl+Shift+S"), "Save Position", SavePositionProc},
610 {"----", NULL, NothingProc},
611 {N_("Mail Move"), "Mail Move", MailMoveProc},
612 {N_("Reload CMail Message"), "Reload CMail Message", ReloadCmailMsgProc},
613 {"----", NULL, NothingProc},
614 {N_("Quit Ctr+Q"), "Exit", QuitProc},
618 MenuItem editMenu[] = {
619 {N_("Copy Game Ctrl+C"), "Copy Game", CopyGameProc},
620 {N_("Copy Position Ctrl+Shift+C"), "Copy Position", CopyPositionProc},
621 {"----", NULL, NothingProc},
622 {N_("Paste Game Ctrl+V"), "Paste Game", PasteGameProc},
623 {N_("Paste Position Ctrl+Shift+V"), "Paste Position", PastePositionProc},
624 {"----", NULL, NothingProc},
625 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
626 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
627 {N_("Edit Tags"), "Edit Tags", EditTagsProc},
628 {N_("Edit Comment"), "Edit Comment", EditCommentProc},
629 {"----", NULL, NothingProc},
630 {N_("Revert Home"), "Revert", RevertProc},
631 {N_("Annotate"), "Annotate", AnnotateProc},
632 {N_("Truncate Game End"), "Truncate Game", TruncateGameProc},
633 {"----", NULL, NothingProc},
634 {N_("Backward Alt+Left"), "Backward", BackwardProc},
635 {N_("Forward Alt+Right"), "Forward", ForwardProc},
636 {N_("Back to Start Alt+Home"), "Back to Start", ToStartProc},
637 {N_("Forward to End Alt+End"), "Forward to End", ToEndProc},
641 MenuItem viewMenu[] = {
642 {N_("Flip View F2"), "Flip View", FlipViewProc},
643 {"----", NULL, NothingProc},
644 {N_("Engine Output Alt+Shift+O"), "Show Engine Output", EngineOutputProc},
645 {N_("Move History Alt+Shift+H"), "Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
646 {N_("Evaluation Graph Alt+Shift+E"), "Show Evaluation Graph", EvalGraphProc},
647 {N_("Game List Alt+Shift+G"), "Show Game List", ShowGameListProc},
648 {"----", NULL, NothingProc},
649 {N_("Tags"), "Show Tags", EditTagsProc},
650 {N_("Comments"), "Show Comments", EditCommentProc},
651 {N_("ICS Input Box"), "ICS Input Box", IcsInputBoxProc},
652 {"----", NULL, NothingProc},
653 {N_("Board..."), "Board Options", BoardOptionsProc},
654 {N_("Game List Tags..."), "Game List", GameListOptionsPopUp},
658 MenuItem modeMenu[] = {
659 {N_("Machine White Ctrl+W"), "Machine White", MachineWhiteProc},
660 {N_("Machine Black Ctrl+B"), "Machine Black", MachineBlackProc},
661 {N_("Two Machines Ctrl+T"), "Two Machines", TwoMachinesProc},
662 {N_("Analysis Mode Ctrl+A"), "Analysis Mode", AnalyzeModeProc},
663 {N_("Analyze File Ctrl+F"), "Analyze File", AnalyzeFileProc },
664 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
665 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
666 {N_("Training"), "Training", TrainingProc},
667 {N_("ICS Client"), "ICS Client", IcsClientProc},
668 {"----", NULL, NothingProc},
669 {N_("Pause Pause"), "Pause", PauseProc},
673 MenuItem actionMenu[] = {
674 {N_("Accept F3"), "Accept", AcceptProc},
675 {N_("Decline F4"), "Decline", DeclineProc},
676 {N_("Rematch F12"), "Rematch", RematchProc},
677 {"----", NULL, NothingProc},
678 {N_("Call Flag F5"), "Call Flag", CallFlagProc},
679 {N_("Draw F6"), "Draw", DrawProc},
680 {N_("Adjourn F7"), "Adjourn", AdjournProc},
681 {N_("Abort F8"),"Abort", AbortProc},
682 {N_("Resign F9"), "Resign", ResignProc},
683 {"----", NULL, NothingProc},
684 {N_("Stop Observing F10"), "Stop Observing", StopObservingProc},
685 {N_("Stop Examining F11"), "Stop Examining", StopExaminingProc},
686 {N_("Upload to Examine"), "Upload to Examine", UploadProc},
687 {"----", NULL, NothingProc},
688 {N_("Adjudicate to White"), "Adjudicate to White", AdjuWhiteProc},
689 {N_("Adjudicate to Black"), "Adjudicate to Black", AdjuBlackProc},
690 {N_("Adjudicate Draw"), "Adjudicate Draw", AdjuDrawProc},
694 MenuItem engineMenu[] = {
695 {N_("Engine #1 Settings ..."), "Engine #1 Settings", FirstSettingsProc},
696 {N_("Engine #2 Settings ..."), "Engine #2 Settings", SecondSettingsProc},
697 {"----", NULL, NothingProc},
698 {N_("Hint"), "Hint", HintProc},
699 {N_("Book"), "Book", BookProc},
700 {"----", NULL, NothingProc},
701 {N_("Move Now Ctrl+M"), "Move Now", MoveNowProc},
702 {N_("Retract Move Ctrl+X"), "Retract Move", RetractMoveProc},
706 MenuItem optionsMenu[] = {
707 {N_("Time Control ... Alt+Shift+T"), "Time Control", TimeControlProc},
708 {N_("Common Engine ... Alt+Shift+U"), "Common Engine", UciMenuProc},
709 {N_("Adjudications ... Alt+Shift+J"), "Adjudications", EngineMenuProc},
710 {N_("ICS ..."), "ICS", IcsOptionsProc},
711 {N_("Load Game ..."), "Load Game", LoadOptionsProc},
712 {N_("Save Game ..."), "Save Game", SaveOptionsProc},
713 // {N_(" ..."), "", OptionsProc},
714 {N_("Game List ..."), "Game List", GameListOptionsPopUp},
715 {"----", NULL, NothingProc},
716 {N_("Always Queen Ctrl+Shift+Q"), "Always Queen", AlwaysQueenProc},
717 {N_("Animate Dragging"), "Animate Dragging", AnimateDraggingProc},
718 {N_("Animate Moving Ctrl+Shift+A"), "Animate Moving", AnimateMovingProc},
719 {N_("Auto Flag Ctrl+Shift+F"), "Auto Flag", AutoflagProc},
720 {N_("Auto Flip View"), "Auto Flip View", AutoflipProc},
721 {N_("Blindfold"), "Blindfold", BlindfoldProc},
722 {N_("Flash Moves"), "Flash Moves", FlashMovesProc},
724 {N_("Highlight Dragging"), "Highlight Dragging", HighlightDraggingProc},
726 {N_("Highlight Last Move"), "Highlight Last Move", HighlightLastMoveProc},
727 {N_("Highlight With Arrow"), "Arrow", HighlightArrowProc},
728 {N_("Move Sound"), "Move Sound", MoveSoundProc},
729 // {N_("ICS Alarm"), "ICS Alarm", IcsAlarmProc},
730 {N_("One-Click Moving"), "OneClick", OneClickProc},
731 {N_("Periodic Updates"), "Periodic Updates", PeriodicUpdatesProc},
732 {N_("Ponder Next Move Ctrl+Shift+P"), "Ponder Next Move", PonderNextMoveProc},
733 {N_("Popup Exit Message"), "Popup Exit Message", PopupExitMessageProc},
734 {N_("Popup Move Errors"), "Popup Move Errors", PopupMoveErrorsProc},
735 // {N_("Premove"), "Premove", PremoveProc},
736 {N_("Show Coords"), "Show Coords", ShowCoordsProc},
737 {N_("Hide Thinking Ctrl+Shift+H"), "Hide Thinking", HideThinkingProc},
738 {N_("Test Legality Ctrl+Shift+L"), "Test Legality", TestLegalityProc},
739 {"----", NULL, NothingProc},
740 {N_("Save Settings Now"), "Save Settings Now", SaveSettingsProc},
741 {N_("Save Settings on Exit"), "Save Settings on Exit", SaveOnExitProc},
745 MenuItem helpMenu[] = {
746 {N_("Info XBoard"), "Info XBoard", InfoProc},
747 {N_("Man XBoard F1"), "Man XBoard", ManProc},
748 {"----", NULL, NothingProc},
749 {N_("About XBoard"), "About XBoard", AboutProc},
754 {N_("File"), "File", fileMenu},
755 {N_("Edit"), "Edit", editMenu},
756 {N_("View"), "View", viewMenu},
757 {N_("Mode"), "Mode", modeMenu},
758 {N_("Action"), "Action", actionMenu},
759 {N_("Engine"), "Engine", engineMenu},
760 {N_("Options"), "Options", optionsMenu},
761 {N_("Help"), "Help", helpMenu},
765 #define PAUSE_BUTTON "P"
766 MenuItem buttonBar[] = {
767 {"<<", "<<", ToStartProc},
768 {"<", "<", BackwardProc},
769 {PAUSE_BUTTON, PAUSE_BUTTON, PauseProc},
770 {">", ">", ForwardProc},
771 {">>", ">>", ToEndProc},
775 #define PIECE_MENU_SIZE 18
776 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
777 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
778 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
779 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
780 N_("Empty square"), N_("Clear board") },
781 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
782 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
783 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
784 N_("Empty square"), N_("Clear board") }
786 /* must be in same order as PieceMenuStrings! */
787 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
788 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
789 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
790 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
791 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
792 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
793 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
794 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
795 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
798 #define DROP_MENU_SIZE 6
799 String dropMenuStrings[DROP_MENU_SIZE] = {
800 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
802 /* must be in same order as PieceMenuStrings! */
803 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
804 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
805 WhiteRook, WhiteQueen
813 DropMenuEnables dmEnables[] = {
831 { XtNborderWidth, 0 },
832 { XtNdefaultDistance, 0 },
836 { XtNborderWidth, 0 },
837 { XtNresizable, (XtArgVal) True },
841 { XtNborderWidth, 0 },
847 { XtNjustify, (XtArgVal) XtJustifyRight },
848 { XtNlabel, (XtArgVal) "..." },
849 { XtNresizable, (XtArgVal) True },
850 { XtNresize, (XtArgVal) False }
853 Arg messageArgs[] = {
854 { XtNjustify, (XtArgVal) XtJustifyLeft },
855 { XtNlabel, (XtArgVal) "..." },
856 { XtNresizable, (XtArgVal) True },
857 { XtNresize, (XtArgVal) False }
861 { XtNborderWidth, 0 },
862 { XtNjustify, (XtArgVal) XtJustifyLeft }
865 XtResource clientResources[] = {
866 { "flashCount", "flashCount", XtRInt, sizeof(int),
867 XtOffset(AppDataPtr, flashCount), XtRImmediate,
868 (XtPointer) FLASH_COUNT },
871 XrmOptionDescRec shellOptions[] = {
872 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
873 { "-flash", "flashCount", XrmoptionNoArg, "3" },
874 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
877 XtActionsRec boardActions[] = {
878 { "DrawPosition", DrawPositionProc },
879 { "HandleUserMove", HandleUserMove },
880 { "AnimateUserMove", AnimateUserMove },
881 { "HandlePV", HandlePV },
882 { "SelectPV", SelectPV },
883 { "StopPV", StopPV },
884 { "FileNameAction", FileNameAction },
885 { "AskQuestionProc", AskQuestionProc },
886 { "AskQuestionReplyAction", AskQuestionReplyAction },
887 { "PieceMenuPopup", PieceMenuPopup },
888 { "WhiteClock", WhiteClock },
889 { "BlackClock", BlackClock },
890 { "Iconify", Iconify },
891 { "ResetProc", ResetProc },
892 { "NewVariantProc", NewVariantProc },
893 { "LoadGameProc", LoadGameProc },
894 { "LoadNextGameProc", LoadNextGameProc },
895 { "LoadPrevGameProc", LoadPrevGameProc },
896 { "LoadSelectedProc", LoadSelectedProc },
897 { "SetFilterProc", SetFilterProc },
898 { "ReloadGameProc", ReloadGameProc },
899 { "LoadPositionProc", LoadPositionProc },
900 { "LoadNextPositionProc", LoadNextPositionProc },
901 { "LoadPrevPositionProc", LoadPrevPositionProc },
902 { "ReloadPositionProc", ReloadPositionProc },
903 { "CopyPositionProc", CopyPositionProc },
904 { "PastePositionProc", PastePositionProc },
905 { "CopyGameProc", CopyGameProc },
906 { "PasteGameProc", PasteGameProc },
907 { "SaveGameProc", SaveGameProc },
908 { "SavePositionProc", SavePositionProc },
909 { "MailMoveProc", MailMoveProc },
910 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
911 { "QuitProc", QuitProc },
912 { "MachineWhiteProc", MachineWhiteProc },
913 { "MachineBlackProc", MachineBlackProc },
914 { "AnalysisModeProc", AnalyzeModeProc },
915 { "AnalyzeFileProc", AnalyzeFileProc },
916 { "TwoMachinesProc", TwoMachinesProc },
917 { "IcsClientProc", IcsClientProc },
918 { "EditGameProc", EditGameProc },
919 { "EditPositionProc", EditPositionProc },
920 { "TrainingProc", EditPositionProc },
921 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
922 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
923 { "ShowGameListProc", ShowGameListProc },
924 { "ShowMoveListProc", HistoryShowProc},
925 { "EditTagsProc", EditCommentProc },
926 { "EditCommentProc", EditCommentProc },
927 { "IcsInputBoxProc", IcsInputBoxProc },
928 { "PauseProc", PauseProc },
929 { "AcceptProc", AcceptProc },
930 { "DeclineProc", DeclineProc },
931 { "RematchProc", RematchProc },
932 { "CallFlagProc", CallFlagProc },
933 { "DrawProc", DrawProc },
934 { "AdjournProc", AdjournProc },
935 { "AbortProc", AbortProc },
936 { "ResignProc", ResignProc },
937 { "AdjuWhiteProc", AdjuWhiteProc },
938 { "AdjuBlackProc", AdjuBlackProc },
939 { "AdjuDrawProc", AdjuDrawProc },
940 { "EnterKeyProc", EnterKeyProc },
941 { "UpKeyProc", UpKeyProc },
942 { "DownKeyProc", DownKeyProc },
943 { "StopObservingProc", StopObservingProc },
944 { "StopExaminingProc", StopExaminingProc },
945 { "UploadProc", UploadProc },
946 { "BackwardProc", BackwardProc },
947 { "ForwardProc", ForwardProc },
948 { "ToStartProc", ToStartProc },
949 { "ToEndProc", ToEndProc },
950 { "RevertProc", RevertProc },
951 { "AnnotateProc", AnnotateProc },
952 { "TruncateGameProc", TruncateGameProc },
953 { "MoveNowProc", MoveNowProc },
954 { "RetractMoveProc", RetractMoveProc },
955 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
956 { "UciMenuProc", (XtActionProc) UciMenuProc },
957 { "TimeControlProc", (XtActionProc) TimeControlProc },
958 { "AlwaysQueenProc", AlwaysQueenProc },
959 { "AnimateDraggingProc", AnimateDraggingProc },
960 { "AnimateMovingProc", AnimateMovingProc },
961 { "AutoflagProc", AutoflagProc },
962 { "AutoflipProc", AutoflipProc },
963 { "BlindfoldProc", BlindfoldProc },
964 { "FlashMovesProc", FlashMovesProc },
965 { "FlipViewProc", FlipViewProc },
967 { "HighlightDraggingProc", HighlightDraggingProc },
969 { "HighlightLastMoveProc", HighlightLastMoveProc },
970 // { "IcsAlarmProc", IcsAlarmProc },
971 { "MoveSoundProc", MoveSoundProc },
972 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
973 { "PonderNextMoveProc", PonderNextMoveProc },
974 { "PopupExitMessageProc", PopupExitMessageProc },
975 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
976 // { "PremoveProc", PremoveProc },
977 { "ShowCoordsProc", ShowCoordsProc },
978 { "ShowThinkingProc", ShowThinkingProc },
979 { "HideThinkingProc", HideThinkingProc },
980 { "TestLegalityProc", TestLegalityProc },
981 { "SaveSettingsProc", SaveSettingsProc },
982 { "SaveOnExitProc", SaveOnExitProc },
983 { "InfoProc", InfoProc },
984 { "ManProc", ManProc },
985 { "HintProc", HintProc },
986 { "BookProc", BookProc },
987 { "AboutGameProc", AboutGameProc },
988 { "AboutProc", AboutProc },
989 { "DebugProc", DebugProc },
990 { "NothingProc", NothingProc },
991 { "CommentClick", (XtActionProc) CommentClick },
992 { "CommentPopDown", (XtActionProc) CommentPopDown },
993 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
994 { "TagsPopDown", (XtActionProc) TagsPopDown },
995 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
996 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
997 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
998 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
999 { "GameListPopDown", (XtActionProc) GameListPopDown },
1000 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
1001 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1002 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
1003 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1004 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1005 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
1006 { "EnginePopDown", (XtActionProc) EnginePopDown },
1007 { "UciPopDown", (XtActionProc) UciPopDown },
1008 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
1009 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
1010 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
1011 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1014 char globalTranslations[] =
1015 ":<Key>F9: ResignProc() \n \
1016 :Ctrl<Key>n: ResetProc() \n \
1017 :Meta<Key>V: NewVariantProc() \n \
1018 :Ctrl<Key>o: LoadGameProc() \n \
1019 :Meta<Key>Next: LoadNextGameProc() \n \
1020 :Meta<Key>Prior: LoadPrevGameProc() \n \
1021 :Ctrl<Key>s: SaveGameProc() \n \
1022 :Ctrl<Key>c: CopyGameProc() \n \
1023 :Ctrl<Key>v: PasteGameProc() \n \
1024 :Ctrl<Key>O: LoadPositionProc() \n \
1025 :Shift<Key>Next: LoadNextPositionProc() \n \
1026 :Shift<Key>Prior: LoadPrevPositionProc() \n \
1027 :Ctrl<Key>S: SavePositionProc() \n \
1028 :Ctrl<Key>C: CopyPositionProc() \n \
1029 :Ctrl<Key>V: PastePositionProc() \n \
1030 :Ctrl<Key>q: QuitProc() \n \
1031 :Ctrl<Key>w: MachineWhiteProc() \n \
1032 :Ctrl<Key>b: MachineBlackProc() \n \
1033 :Ctrl<Key>t: TwoMachinesProc() \n \
1034 :Ctrl<Key>a: AnalysisModeProc() \n \
1035 :Ctrl<Key>f: AnalyzeFileProc() \n \
1036 :Ctrl<Key>e: EditGameProc() \n \
1037 :Ctrl<Key>E: EditPositionProc() \n \
1038 :Meta<Key>O: EngineOutputProc() \n \
1039 :Meta<Key>E: EvalGraphProc() \n \
1040 :Meta<Key>G: ShowGameListProc() \n \
1041 :Meta<Key>H: ShowMoveListProc() \n \
1042 :<Key>Pause: PauseProc() \n \
1043 :<Key>F3: AcceptProc() \n \
1044 :<Key>F4: DeclineProc() \n \
1045 :<Key>F12: RematchProc() \n \
1046 :<Key>F5: CallFlagProc() \n \
1047 :<Key>F6: DrawProc() \n \
1048 :<Key>F7: AdjournProc() \n \
1049 :<Key>F8: AbortProc() \n \
1050 :<Key>F10: StopObservingProc() \n \
1051 :<Key>F11: StopExaminingProc() \n \
1052 :Meta Ctrl<Key>F12: DebugProc() \n \
1053 :Meta<Key>End: ToEndProc() \n \
1054 :Meta<Key>Right: ForwardProc() \n \
1055 :Meta<Key>Home: ToStartProc() \n \
1056 :Meta<Key>Left: BackwardProc() \n \
1057 :<Key>Home: RevertProc() \n \
1058 :<Key>End: TruncateGameProc() \n \
1059 :Ctrl<Key>m: MoveNowProc() \n \
1060 :Ctrl<Key>x: RetractMoveProc() \n \
1061 :Meta<Key>J: EngineMenuProc() \n \
1062 :Meta<Key>U: UciMenuProc() \n \
1063 :Meta<Key>T: TimeControlProc() \n \
1064 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1065 :Ctrl<Key>F: AutoflagProc() \n \
1066 :Ctrl<Key>A: AnimateMovingProc() \n \
1067 :Ctrl<Key>P: PonderNextMoveProc() \n \
1068 :Ctrl<Key>L: TestLegalityProc() \n \
1069 :Ctrl<Key>H: HideThinkingProc() \n \
1070 :<Key>-: Iconify() \n \
1071 :<Key>F1: ManProc() \n \
1072 :<Key>F2: FlipViewProc() \n \
1073 <KeyDown>.: BackwardProc() \n \
1074 <KeyUp>.: ForwardProc() \n \
1075 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1076 \"Send to chess program:\",,1) \n \
1077 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1078 \"Send to second chess program:\",,2) \n";
1080 char boardTranslations[] =
1081 "<Btn1Down>: HandleUserMove(0) \n \
1082 Shift<Btn1Up>: HandleUserMove(1) \n \
1083 <Btn1Up>: HandleUserMove(0) \n \
1084 <Btn1Motion>: AnimateUserMove() \n \
1085 <Btn3Motion>: HandlePV() \n \
1086 <Btn3Up>: PieceMenuPopup(menuB) \n \
1087 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1088 PieceMenuPopup(menuB) \n \
1089 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1090 PieceMenuPopup(menuW) \n \
1091 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1092 PieceMenuPopup(menuW) \n \
1093 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1094 PieceMenuPopup(menuB) \n";
1096 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1097 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1099 char ICSInputTranslations[] =
1100 "<Key>Up: UpKeyProc() \n "
1101 "<Key>Down: DownKeyProc() \n "
1102 "<Key>Return: EnterKeyProc() \n";
1104 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1105 // as the widget is destroyed before the up-click can call extend-end
1106 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1108 String xboardResources[] = {
1109 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1110 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1111 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1116 /* Max possible square size */
1117 #define MAXSQSIZE 256
1119 static int xpm_avail[MAXSQSIZE];
1121 #ifdef HAVE_DIR_STRUCT
1123 /* Extract piece size from filename */
1125 xpm_getsize(name, len, ext)
1136 if ((p=strchr(name, '.')) == NULL ||
1137 StrCaseCmp(p+1, ext) != 0)
1143 while (*p && isdigit(*p))
1150 /* Setup xpm_avail */
1152 xpm_getavail(dirname, ext)
1160 for (i=0; i<MAXSQSIZE; ++i)
1163 if (appData.debugMode)
1164 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1166 dir = opendir(dirname);
1169 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1170 programName, dirname);
1174 while ((ent=readdir(dir)) != NULL) {
1175 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1176 if (i > 0 && i < MAXSQSIZE)
1186 xpm_print_avail(fp, ext)
1192 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1193 for (i=1; i<MAXSQSIZE; ++i) {
1199 /* Return XPM piecesize closest to size */
1201 xpm_closest_to(dirname, size, ext)
1207 int sm_diff = MAXSQSIZE;
1211 xpm_getavail(dirname, ext);
1213 if (appData.debugMode)
1214 xpm_print_avail(stderr, ext);
1216 for (i=1; i<MAXSQSIZE; ++i) {
1219 diff = (diff<0) ? -diff : diff;
1220 if (diff < sm_diff) {
1228 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1234 #else /* !HAVE_DIR_STRUCT */
1235 /* If we are on a system without a DIR struct, we can't
1236 read the directory, so we can't collect a list of
1237 filenames, etc., so we can't do any size-fitting. */
1239 xpm_closest_to(dirname, size, ext)
1244 fprintf(stderr, _("\
1245 Warning: No DIR structure found on this system --\n\
1246 Unable to autosize for XPM/XIM pieces.\n\
1247 Please report this error to frankm@hiwaay.net.\n\
1248 Include system type & operating system in message.\n"));
1251 #endif /* HAVE_DIR_STRUCT */
1253 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1254 "magenta", "cyan", "white" };
1258 TextColors textColors[(int)NColorClasses];
1260 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1262 parse_color(str, which)
1266 char *p, buf[100], *d;
1269 if (strlen(str) > 99) /* watch bounds on buf */
1274 for (i=0; i<which; ++i) {
1281 /* Could be looking at something like:
1283 .. in which case we want to stop on a comma also */
1284 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1288 return -1; /* Use default for empty field */
1291 if (which == 2 || isdigit(*p))
1294 while (*p && isalpha(*p))
1299 for (i=0; i<8; ++i) {
1300 if (!StrCaseCmp(buf, cnames[i]))
1301 return which? (i+40) : (i+30);
1303 if (!StrCaseCmp(buf, "default")) return -1;
1305 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1310 parse_cpair(cc, str)
1314 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1315 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1320 /* bg and attr are optional */
1321 textColors[(int)cc].bg = parse_color(str, 1);
1322 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1323 textColors[(int)cc].attr = 0;
1329 /* Arrange to catch delete-window events */
1330 Atom wm_delete_window;
1332 CatchDeleteWindow(Widget w, String procname)
1335 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1336 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1337 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1344 XtSetArg(args[0], XtNiconic, False);
1345 XtSetValues(shellWidget, args, 1);
1347 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1350 //---------------------------------------------------------------------------------------------------------
1351 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1354 #define CW_USEDEFAULT (1<<31)
1355 #define ICS_TEXT_MENU_SIZE 90
1356 #define DEBUG_FILE "xboard.debug"
1357 #define SetCurrentDirectory chdir
1358 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1362 // these two must some day move to frontend.h, when they are implemented
1363 Boolean GameListIsUp();
1365 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1368 // front-end part of option handling
1370 // [HGM] This platform-dependent table provides the location for storing the color info
1371 extern char *crWhite, * crBlack;
1375 &appData.whitePieceColor,
1376 &appData.blackPieceColor,
1377 &appData.lightSquareColor,
1378 &appData.darkSquareColor,
1379 &appData.highlightSquareColor,
1380 &appData.premoveHighlightColor,
1381 &appData.lowTimeWarningColor,
1392 // [HGM] font: keep a font for each square size, even non-stndard ones
1393 #define NUM_SIZES 18
1394 #define MAX_SIZE 130
1395 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1396 char *fontTable[NUM_FONTS][MAX_SIZE];
1399 ParseFont(char *name, int number)
1400 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1402 if(sscanf(name, "size%d:", &size)) {
1403 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1404 // defer processing it until we know if it matches our board size
1405 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1406 fontTable[number][size] = strdup(strchr(name, ':')+1);
1407 fontValid[number][size] = True;
1412 case 0: // CLOCK_FONT
1413 appData.clockFont = strdup(name);
1415 case 1: // MESSAGE_FONT
1416 appData.font = strdup(name);
1418 case 2: // COORD_FONT
1419 appData.coordFont = strdup(name);
1424 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1429 { // only 2 fonts currently
1430 appData.clockFont = CLOCK_FONT_NAME;
1431 appData.coordFont = COORD_FONT_NAME;
1432 appData.font = DEFAULT_FONT_NAME;
1437 { // no-op, until we identify the code for this already in XBoard and move it here
1441 ParseColor(int n, char *name)
1442 { // in XBoard, just copy the color-name string
1443 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1447 ParseTextAttribs(ColorClass cc, char *s)
1449 (&appData.colorShout)[cc] = strdup(s);
1453 ParseBoardSize(void *addr, char *name)
1455 appData.boardSize = strdup(name);
1460 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1464 SetCommPortDefaults()
1465 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1468 // [HGM] args: these three cases taken out to stay in front-end
1470 SaveFontArg(FILE *f, ArgDescriptor *ad)
1473 int i, n = (int)(intptr_t)ad->argLoc;
1475 case 0: // CLOCK_FONT
1476 name = appData.clockFont;
1478 case 1: // MESSAGE_FONT
1479 name = appData.font;
1481 case 2: // COORD_FONT
1482 name = appData.coordFont;
1487 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1488 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1489 fontTable[n][squareSize] = strdup(name);
1490 fontValid[n][squareSize] = True;
1493 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1494 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1499 { // nothing to do, as the sounds are at all times represented by their text-string names already
1503 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1504 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1505 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
1509 SaveColor(FILE *f, ArgDescriptor *ad)
1510 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1511 if(colorVariable[(int)(intptr_t)ad->argLoc])
1512 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
1516 SaveBoardSize(FILE *f, char *name, void *addr)
1517 { // wrapper to shield back-end from BoardSize & sizeInfo
1518 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1522 ParseCommPortSettings(char *s)
1523 { // no such option in XBoard (yet)
1526 extern Widget engineOutputShell;
1527 extern Widget tagsShell, editTagsShell;
1529 GetActualPlacement(Widget wg, WindowPlacement *wp)
1539 XtSetArg(args[i], XtNx, &x); i++;
1540 XtSetArg(args[i], XtNy, &y); i++;
1541 XtSetArg(args[i], XtNwidth, &w); i++;
1542 XtSetArg(args[i], XtNheight, &h); i++;
1543 XtGetValues(wg, args, i);
1552 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1553 // In XBoard this will have to wait until awareness of window parameters is implemented
1554 GetActualPlacement(shellWidget, &wpMain);
1555 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1556 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1557 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1558 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1559 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1560 else GetActualPlacement(editShell, &wpComment);
1561 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1562 else GetActualPlacement(editTagsShell, &wpTags);
1566 PrintCommPortSettings(FILE *f, char *name)
1567 { // This option does not exist in XBoard
1571 MySearchPath(char *installDir, char *name, char *fullname)
1572 { // just append installDir and name. Perhaps ExpandPath should be used here?
1573 name = ExpandPathName(name);
1574 if(name && name[0] == '/')
1575 safeStrCpy(fullname, name, MSG_SIZ );
1577 sprintf(fullname, "%s%c%s", installDir, '/', name);
1583 MyGetFullPathName(char *name, char *fullname)
1584 { // should use ExpandPath?
1585 name = ExpandPathName(name);
1586 safeStrCpy(fullname, name, MSG_SIZ );
1591 EnsureOnScreen(int *x, int *y, int minX, int minY)
1598 { // [HGM] args: allows testing if main window is realized from back-end
1599 return xBoardWindow != 0;
1603 PopUpStartupDialog()
1604 { // start menu not implemented in XBoard
1608 ConvertToLine(int argc, char **argv)
1610 static char line[128*1024], buf[1024];
1614 for(i=1; i<argc; i++)
1616 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1617 && argv[i][0] != '{' )
1618 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1620 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1621 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1624 line[strlen(line)-1] = NULLCHAR;
1628 //--------------------------------------------------------------------------------------------
1630 extern Boolean twoBoards, partnerUp;
1633 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1635 #define BoardSize int
1636 void InitDrawingSizes(BoardSize boardSize, int flags)
1637 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1638 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1640 XtGeometryResult gres;
1643 if(!formWidget) return;
1646 * Enable shell resizing.
1648 shellArgs[0].value = (XtArgVal) &w;
1649 shellArgs[1].value = (XtArgVal) &h;
1650 XtGetValues(shellWidget, shellArgs, 2);
1652 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1653 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1654 XtSetValues(shellWidget, &shellArgs[2], 4);
1656 XtSetArg(args[0], XtNdefaultDistance, &sep);
1657 XtGetValues(formWidget, args, 1);
1659 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1660 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1661 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1663 hOffset = boardWidth + 10;
1664 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1665 secondSegments[i] = gridSegments[i];
1666 secondSegments[i].x1 += hOffset;
1667 secondSegments[i].x2 += hOffset;
1670 XtSetArg(args[0], XtNwidth, boardWidth);
1671 XtSetArg(args[1], XtNheight, boardHeight);
1672 XtSetValues(boardWidget, args, 2);
1674 timerWidth = (boardWidth - sep) / 2;
1675 XtSetArg(args[0], XtNwidth, timerWidth);
1676 XtSetValues(whiteTimerWidget, args, 1);
1677 XtSetValues(blackTimerWidget, args, 1);
1679 XawFormDoLayout(formWidget, False);
1681 if (appData.titleInWindow) {
1683 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1684 XtSetArg(args[i], XtNheight, &h); i++;
1685 XtGetValues(titleWidget, args, i);
1687 w = boardWidth - 2*bor;
1689 XtSetArg(args[0], XtNwidth, &w);
1690 XtGetValues(menuBarWidget, args, 1);
1691 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1694 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1695 if (gres != XtGeometryYes && appData.debugMode) {
1697 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1698 programName, gres, w, h, wr, hr);
1702 XawFormDoLayout(formWidget, True);
1705 * Inhibit shell resizing.
1707 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1708 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1709 shellArgs[4].value = shellArgs[2].value = w;
1710 shellArgs[5].value = shellArgs[3].value = h;
1711 XtSetValues(shellWidget, &shellArgs[0], 6);
1713 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1716 for(i=0; i<4; i++) {
1718 for(p=0; p<=(int)WhiteKing; p++)
1719 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1720 if(gameInfo.variant == VariantShogi) {
1721 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1722 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1723 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1724 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1725 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1728 if(gameInfo.variant == VariantGothic) {
1729 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1732 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1733 xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
1734 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1737 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1738 for(p=0; p<=(int)WhiteKing; p++)
1739 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1740 if(gameInfo.variant == VariantShogi) {
1741 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1742 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1743 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1744 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1745 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1748 if(gameInfo.variant == VariantGothic) {
1749 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1752 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1753 ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
1754 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1759 for(i=0; i<2; i++) {
1761 for(p=0; p<=(int)WhiteKing; p++)
1762 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1763 if(gameInfo.variant == VariantShogi) {
1764 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1765 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1766 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1767 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1768 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1771 if(gameInfo.variant == VariantGothic) {
1772 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1775 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1776 pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
1777 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1787 void ParseIcsTextColors()
1788 { // [HGM] tken out of main(), so it can be called from ICS-Options dialog
1789 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1790 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1791 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1792 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1793 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1794 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1795 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1796 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1797 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1798 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1800 if (appData.colorize) {
1802 _("%s: can't parse color names; disabling colorization\n"),
1805 appData.colorize = FALSE;
1810 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
1811 XrmValue vFrom, vTo;
1812 int forceMono = False;
1814 if (!appData.monoMode) {
1815 vFrom.addr = (caddr_t) appData.lightSquareColor;
1816 vFrom.size = strlen(appData.lightSquareColor);
1817 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1818 if (vTo.addr == NULL) {
1819 appData.monoMode = True;
1822 lightSquareColor = *(Pixel *) vTo.addr;
1825 if (!appData.monoMode) {
1826 vFrom.addr = (caddr_t) appData.darkSquareColor;
1827 vFrom.size = strlen(appData.darkSquareColor);
1828 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1829 if (vTo.addr == NULL) {
1830 appData.monoMode = True;
1833 darkSquareColor = *(Pixel *) vTo.addr;
1836 if (!appData.monoMode) {
1837 vFrom.addr = (caddr_t) appData.whitePieceColor;
1838 vFrom.size = strlen(appData.whitePieceColor);
1839 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1840 if (vTo.addr == NULL) {
1841 appData.monoMode = True;
1844 whitePieceColor = *(Pixel *) vTo.addr;
1847 if (!appData.monoMode) {
1848 vFrom.addr = (caddr_t) appData.blackPieceColor;
1849 vFrom.size = strlen(appData.blackPieceColor);
1850 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1851 if (vTo.addr == NULL) {
1852 appData.monoMode = True;
1855 blackPieceColor = *(Pixel *) vTo.addr;
1859 if (!appData.monoMode) {
1860 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1861 vFrom.size = strlen(appData.highlightSquareColor);
1862 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1863 if (vTo.addr == NULL) {
1864 appData.monoMode = True;
1867 highlightSquareColor = *(Pixel *) vTo.addr;
1871 if (!appData.monoMode) {
1872 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1873 vFrom.size = strlen(appData.premoveHighlightColor);
1874 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1875 if (vTo.addr == NULL) {
1876 appData.monoMode = True;
1879 premoveHighlightColor = *(Pixel *) vTo.addr;
1890 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1891 XSetWindowAttributes window_attributes;
1893 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1894 XrmValue vFrom, vTo;
1895 XtGeometryResult gres;
1898 int forceMono = False;
1900 srandom(time(0)); // [HGM] book: make random truly random
1902 setbuf(stdout, NULL);
1903 setbuf(stderr, NULL);
1906 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1907 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1911 programName = strrchr(argv[0], '/');
1912 if (programName == NULL)
1913 programName = argv[0];
1918 XtSetLanguageProc(NULL, NULL, NULL);
1919 bindtextdomain(PACKAGE, LOCALEDIR);
1920 textdomain(PACKAGE);
1924 XtAppInitialize(&appContext, "XBoard", shellOptions,
1925 XtNumber(shellOptions),
1926 &argc, argv, xboardResources, NULL, 0);
1927 appData.boardSize = "";
1928 InitAppData(ConvertToLine(argc, argv));
1930 if (p == NULL) p = "/tmp";
1931 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1932 gameCopyFilename = (char*) malloc(i);
1933 gamePasteFilename = (char*) malloc(i);
1934 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1935 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1937 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1938 clientResources, XtNumber(clientResources),
1941 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1942 static char buf[MSG_SIZ];
1943 EscapeExpand(buf, appData.initString);
1944 appData.initString = strdup(buf);
1945 EscapeExpand(buf, appData.secondInitString);
1946 appData.secondInitString = strdup(buf);
1947 EscapeExpand(buf, appData.firstComputerString);
1948 appData.firstComputerString = strdup(buf);
1949 EscapeExpand(buf, appData.secondComputerString);
1950 appData.secondComputerString = strdup(buf);
1953 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1956 if (chdir(chessDir) != 0) {
1957 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1963 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1964 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1965 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1966 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1969 setbuf(debugFP, NULL);
1972 /* [HGM,HR] make sure board size is acceptable */
1973 if(appData.NrFiles > BOARD_FILES ||
1974 appData.NrRanks > BOARD_RANKS )
1975 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1978 /* This feature does not work; animation needs a rewrite */
1979 appData.highlightDragging = FALSE;
1983 xDisplay = XtDisplay(shellWidget);
1984 xScreen = DefaultScreen(xDisplay);
1985 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1987 gameInfo.variant = StringToVariant(appData.variant);
1988 InitPosition(FALSE);
1991 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1993 if (isdigit(appData.boardSize[0])) {
1994 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1995 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1996 &fontPxlSize, &smallLayout, &tinyLayout);
1998 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1999 programName, appData.boardSize);
2003 /* Find some defaults; use the nearest known size */
2004 SizeDefaults *szd, *nearest;
2005 int distance = 99999;
2006 nearest = szd = sizeDefaults;
2007 while (szd->name != NULL) {
2008 if (abs(szd->squareSize - squareSize) < distance) {
2010 distance = abs(szd->squareSize - squareSize);
2011 if (distance == 0) break;
2015 if (i < 2) lineGap = nearest->lineGap;
2016 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
2017 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
2018 if (i < 5) fontPxlSize = nearest->fontPxlSize;
2019 if (i < 6) smallLayout = nearest->smallLayout;
2020 if (i < 7) tinyLayout = nearest->tinyLayout;
2023 SizeDefaults *szd = sizeDefaults;
2024 if (*appData.boardSize == NULLCHAR) {
2025 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
2026 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
2029 if (szd->name == NULL) szd--;
2030 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
2032 while (szd->name != NULL &&
2033 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
2034 if (szd->name == NULL) {
2035 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
2036 programName, appData.boardSize);
2040 squareSize = szd->squareSize;
2041 lineGap = szd->lineGap;
2042 clockFontPxlSize = szd->clockFontPxlSize;
2043 coordFontPxlSize = szd->coordFontPxlSize;
2044 fontPxlSize = szd->fontPxlSize;
2045 smallLayout = szd->smallLayout;
2046 tinyLayout = szd->tinyLayout;
2047 // [HGM] font: use defaults from settings file if available and not overruled
2049 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
2050 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
2051 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
2052 appData.font = fontTable[MESSAGE_FONT][squareSize];
2053 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
2054 appData.coordFont = fontTable[COORD_FONT][squareSize];
2056 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
2057 if (strlen(appData.pixmapDirectory) > 0) {
2058 p = ExpandPathName(appData.pixmapDirectory);
2060 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
2061 appData.pixmapDirectory);
2064 if (appData.debugMode) {
2065 fprintf(stderr, _("\
2066 XBoard square size (hint): %d\n\
2067 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
2069 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
2070 if (appData.debugMode) {
2071 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
2074 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
2076 /* [HR] height treated separately (hacked) */
2077 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
2078 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
2079 if (appData.showJail == 1) {
2080 /* Jail on top and bottom */
2081 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2082 XtSetArg(boardArgs[2], XtNheight,
2083 boardHeight + 2*(lineGap + squareSize));
2084 } else if (appData.showJail == 2) {
2086 XtSetArg(boardArgs[1], XtNwidth,
2087 boardWidth + 2*(lineGap + squareSize));
2088 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2091 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2092 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2096 * Determine what fonts to use.
2098 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2099 clockFontID = XLoadFont(xDisplay, appData.clockFont);
2100 clockFontStruct = XQueryFont(xDisplay, clockFontID);
2101 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2102 coordFontID = XLoadFont(xDisplay, appData.coordFont);
2103 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2104 appData.font = FindFont(appData.font, fontPxlSize);
2105 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
2106 countFontStruct = XQueryFont(xDisplay, countFontID);
2107 // appData.font = FindFont(appData.font, fontPxlSize);
2109 xdb = XtDatabase(xDisplay);
2110 XrmPutStringResource(&xdb, "*font", appData.font);
2113 * Detect if there are not enough colors available and adapt.
2115 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2116 appData.monoMode = True;
2119 forceMono = MakeColors();
2122 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2125 if (appData.bitmapDirectory == NULL ||
2126 appData.bitmapDirectory[0] == NULLCHAR)
2127 appData.bitmapDirectory = DEF_BITMAP_DIR;
2130 if (appData.lowTimeWarning && !appData.monoMode) {
2131 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2132 vFrom.size = strlen(appData.lowTimeWarningColor);
2133 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2134 if (vTo.addr == NULL)
2135 appData.monoMode = True;
2137 lowTimeWarningColor = *(Pixel *) vTo.addr;
2140 if (appData.monoMode && appData.debugMode) {
2141 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2142 (unsigned long) XWhitePixel(xDisplay, xScreen),
2143 (unsigned long) XBlackPixel(xDisplay, xScreen));
2146 ParseIcsTextColors();
2147 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2148 textColors[ColorNone].attr = 0;
2150 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2156 layoutName = "tinyLayout";
2157 } else if (smallLayout) {
2158 layoutName = "smallLayout";
2160 layoutName = "normalLayout";
2162 /* Outer layoutWidget is there only to provide a name for use in
2163 resources that depend on the layout style */
2165 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2166 layoutArgs, XtNumber(layoutArgs));
2168 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2169 formArgs, XtNumber(formArgs));
2170 XtSetArg(args[0], XtNdefaultDistance, &sep);
2171 XtGetValues(formWidget, args, 1);
2174 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2175 XtSetArg(args[0], XtNtop, XtChainTop);
2176 XtSetArg(args[1], XtNbottom, XtChainTop);
2177 XtSetArg(args[2], XtNright, XtChainLeft);
2178 XtSetValues(menuBarWidget, args, 3);
2180 widgetList[j++] = whiteTimerWidget =
2181 XtCreateWidget("whiteTime", labelWidgetClass,
2182 formWidget, timerArgs, XtNumber(timerArgs));
2183 XtSetArg(args[0], XtNfont, clockFontStruct);
2184 XtSetArg(args[1], XtNtop, XtChainTop);
2185 XtSetArg(args[2], XtNbottom, XtChainTop);
2186 XtSetValues(whiteTimerWidget, args, 3);
2188 widgetList[j++] = blackTimerWidget =
2189 XtCreateWidget("blackTime", labelWidgetClass,
2190 formWidget, timerArgs, XtNumber(timerArgs));
2191 XtSetArg(args[0], XtNfont, clockFontStruct);
2192 XtSetArg(args[1], XtNtop, XtChainTop);
2193 XtSetArg(args[2], XtNbottom, XtChainTop);
2194 XtSetValues(blackTimerWidget, args, 3);
2196 if (appData.titleInWindow) {
2197 widgetList[j++] = titleWidget =
2198 XtCreateWidget("title", labelWidgetClass, formWidget,
2199 titleArgs, XtNumber(titleArgs));
2200 XtSetArg(args[0], XtNtop, XtChainTop);
2201 XtSetArg(args[1], XtNbottom, XtChainTop);
2202 XtSetValues(titleWidget, args, 2);
2205 if (appData.showButtonBar) {
2206 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2207 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2208 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2209 XtSetArg(args[2], XtNtop, XtChainTop);
2210 XtSetArg(args[3], XtNbottom, XtChainTop);
2211 XtSetValues(buttonBarWidget, args, 4);
2214 widgetList[j++] = messageWidget =
2215 XtCreateWidget("message", labelWidgetClass, formWidget,
2216 messageArgs, XtNumber(messageArgs));
2217 XtSetArg(args[0], XtNtop, XtChainTop);
2218 XtSetArg(args[1], XtNbottom, XtChainTop);
2219 XtSetValues(messageWidget, args, 2);
2221 widgetList[j++] = boardWidget =
2222 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2223 XtNumber(boardArgs));
2225 XtManageChildren(widgetList, j);
2227 timerWidth = (boardWidth - sep) / 2;
2228 XtSetArg(args[0], XtNwidth, timerWidth);
2229 XtSetValues(whiteTimerWidget, args, 1);
2230 XtSetValues(blackTimerWidget, args, 1);
2232 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2233 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2234 XtGetValues(whiteTimerWidget, args, 2);
2236 if (appData.showButtonBar) {
2237 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2238 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2239 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2243 * formWidget uses these constraints but they are stored
2247 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2248 XtSetValues(menuBarWidget, args, i);
2249 if (appData.titleInWindow) {
2252 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2253 XtSetValues(whiteTimerWidget, args, i);
2255 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2256 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2257 XtSetValues(blackTimerWidget, args, i);
2259 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2260 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2261 XtSetValues(titleWidget, args, i);
2263 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2264 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2265 XtSetValues(messageWidget, args, i);
2266 if (appData.showButtonBar) {
2268 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2269 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2270 XtSetValues(buttonBarWidget, args, i);
2274 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2275 XtSetValues(whiteTimerWidget, args, i);
2277 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2278 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2279 XtSetValues(blackTimerWidget, args, i);
2281 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2282 XtSetValues(titleWidget, args, i);
2284 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2285 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2286 XtSetValues(messageWidget, args, i);
2287 if (appData.showButtonBar) {
2289 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2290 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2291 XtSetValues(buttonBarWidget, args, i);
2296 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2297 XtSetValues(whiteTimerWidget, args, i);
2299 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2300 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2301 XtSetValues(blackTimerWidget, args, i);
2303 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2304 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2305 XtSetValues(messageWidget, args, i);
2306 if (appData.showButtonBar) {
2308 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2309 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2310 XtSetValues(buttonBarWidget, args, i);
2314 XtSetArg(args[0], XtNfromVert, messageWidget);
2315 XtSetArg(args[1], XtNtop, XtChainTop);
2316 XtSetArg(args[2], XtNbottom, XtChainBottom);
2317 XtSetArg(args[3], XtNleft, XtChainLeft);
2318 XtSetArg(args[4], XtNright, XtChainRight);
2319 XtSetValues(boardWidget, args, 5);
2321 XtRealizeWidget(shellWidget);
2324 XtSetArg(args[0], XtNx, wpMain.x);
2325 XtSetArg(args[1], XtNy, wpMain.y);
2326 XtSetValues(shellWidget, args, 2);
2330 * Correct the width of the message and title widgets.
2331 * It is not known why some systems need the extra fudge term.
2332 * The value "2" is probably larger than needed.
2334 XawFormDoLayout(formWidget, False);
2336 #define WIDTH_FUDGE 2
2338 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2339 XtSetArg(args[i], XtNheight, &h); i++;
2340 XtGetValues(messageWidget, args, i);
2341 if (appData.showButtonBar) {
2343 XtSetArg(args[i], XtNwidth, &w); i++;
2344 XtGetValues(buttonBarWidget, args, i);
2345 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2347 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2350 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2351 if (gres != XtGeometryYes && appData.debugMode) {
2352 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2353 programName, gres, w, h, wr, hr);
2356 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2357 /* The size used for the child widget in layout lags one resize behind
2358 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2360 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2361 if (gres != XtGeometryYes && appData.debugMode) {
2362 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2363 programName, gres, w, h, wr, hr);
2366 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2367 XtSetArg(args[1], XtNright, XtChainRight);
2368 XtSetValues(messageWidget, args, 2);
2370 if (appData.titleInWindow) {
2372 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2373 XtSetArg(args[i], XtNheight, &h); i++;
2374 XtGetValues(titleWidget, args, i);
2376 w = boardWidth - 2*bor;
2378 XtSetArg(args[0], XtNwidth, &w);
2379 XtGetValues(menuBarWidget, args, 1);
2380 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2383 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2384 if (gres != XtGeometryYes && appData.debugMode) {
2386 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2387 programName, gres, w, h, wr, hr);
2390 XawFormDoLayout(formWidget, True);
2392 xBoardWindow = XtWindow(boardWidget);
2394 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2395 // not need to go into InitDrawingSizes().
2399 * Create X checkmark bitmap and initialize option menu checks.
2401 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2402 checkmark_bits, checkmark_width, checkmark_height);
2403 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2404 if (appData.alwaysPromoteToQueen) {
2405 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2408 if (appData.animateDragging) {
2409 XtSetValues(XtNameToWidget(menuBarWidget,
2410 "menuOptions.Animate Dragging"),
2413 if (appData.animate) {
2414 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2417 if (appData.autoCallFlag) {
2418 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2421 if (appData.autoFlipView) {
2422 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2425 if (appData.blindfold) {
2426 XtSetValues(XtNameToWidget(menuBarWidget,
2427 "menuOptions.Blindfold"), args, 1);
2429 if (appData.flashCount > 0) {
2430 XtSetValues(XtNameToWidget(menuBarWidget,
2431 "menuOptions.Flash Moves"),
2435 if (appData.highlightDragging) {
2436 XtSetValues(XtNameToWidget(menuBarWidget,
2437 "menuOptions.Highlight Dragging"),
2441 if (appData.highlightLastMove) {
2442 XtSetValues(XtNameToWidget(menuBarWidget,
2443 "menuOptions.Highlight Last Move"),
2446 if (appData.highlightMoveWithArrow) {
2447 XtSetValues(XtNameToWidget(menuBarWidget,
2448 "menuOptions.Arrow"),
2451 // if (appData.icsAlarm) {
2452 // XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2455 if (appData.ringBellAfterMoves) {
2456 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2459 if (appData.oneClick) {
2460 XtSetValues(XtNameToWidget(menuBarWidget,
2461 "menuOptions.OneClick"), args, 1);
2463 if (appData.periodicUpdates) {
2464 XtSetValues(XtNameToWidget(menuBarWidget,
2465 "menuOptions.Periodic Updates"), args, 1);
2467 if (appData.ponderNextMove) {
2468 XtSetValues(XtNameToWidget(menuBarWidget,
2469 "menuOptions.Ponder Next Move"), args, 1);
2471 if (appData.popupExitMessage) {
2472 XtSetValues(XtNameToWidget(menuBarWidget,
2473 "menuOptions.Popup Exit Message"), args, 1);
2475 if (appData.popupMoveErrors) {
2476 XtSetValues(XtNameToWidget(menuBarWidget,
2477 "menuOptions.Popup Move Errors"), args, 1);
2479 // if (appData.premove) {
2480 // XtSetValues(XtNameToWidget(menuBarWidget,
2481 // "menuOptions.Premove"), args, 1);
2483 if (appData.showCoords) {
2484 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2487 if (appData.hideThinkingFromHuman) {
2488 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2491 if (appData.testLegality) {
2492 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2495 if (saveSettingsOnExit) {
2496 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2503 ReadBitmap(&wIconPixmap, "icon_white.bm",
2504 icon_white_bits, icon_white_width, icon_white_height);
2505 ReadBitmap(&bIconPixmap, "icon_black.bm",
2506 icon_black_bits, icon_black_width, icon_black_height);
2507 iconPixmap = wIconPixmap;
2509 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2510 XtSetValues(shellWidget, args, i);
2513 * Create a cursor for the board widget.
2515 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2516 XChangeWindowAttributes(xDisplay, xBoardWindow,
2517 CWCursor, &window_attributes);
2520 * Inhibit shell resizing.
2522 shellArgs[0].value = (XtArgVal) &w;
2523 shellArgs[1].value = (XtArgVal) &h;
2524 XtGetValues(shellWidget, shellArgs, 2);
2525 shellArgs[4].value = shellArgs[2].value = w;
2526 shellArgs[5].value = shellArgs[3].value = h;
2527 XtSetValues(shellWidget, &shellArgs[2], 4);
2528 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2529 marginH = h - boardHeight;
2531 CatchDeleteWindow(shellWidget, "QuitProc");
2536 if (appData.bitmapDirectory[0] != NULLCHAR) {
2540 CreateXPMBoard(appData.liteBackTextureFile, 1);
2541 CreateXPMBoard(appData.darkBackTextureFile, 0);
2545 /* Create regular pieces */
2546 if (!useImages) CreatePieces();
2551 if (appData.animate || appData.animateDragging)
2554 XtAugmentTranslations(formWidget,
2555 XtParseTranslationTable(globalTranslations));
2556 XtAugmentTranslations(boardWidget,
2557 XtParseTranslationTable(boardTranslations));
2558 XtAugmentTranslations(whiteTimerWidget,
2559 XtParseTranslationTable(whiteTranslations));
2560 XtAugmentTranslations(blackTimerWidget,
2561 XtParseTranslationTable(blackTranslations));
2563 /* Why is the following needed on some versions of X instead
2564 * of a translation? */
2565 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2566 (XtEventHandler) EventProc, NULL);
2569 /* [AS] Restore layout */
2570 if( wpMoveHistory.visible ) {
2574 if( wpEvalGraph.visible )
2579 if( wpEngineOutput.visible ) {
2580 EngineOutputPopUp();
2585 if (errorExitStatus == -1) {
2586 if (appData.icsActive) {
2587 /* We now wait until we see "login:" from the ICS before
2588 sending the logon script (problems with timestamp otherwise) */
2589 /*ICSInitScript();*/
2590 if (appData.icsInputBox) ICSInputBoxPopUp();
2594 signal(SIGWINCH, TermSizeSigHandler);
2596 signal(SIGINT, IntSigHandler);
2597 signal(SIGTERM, IntSigHandler);
2598 if (*appData.cmailGameName != NULLCHAR) {
2599 signal(SIGUSR1, CmailSigHandler);
2602 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2604 XtSetKeyboardFocus(shellWidget, formWidget);
2606 XtAppMainLoop(appContext);
2607 if (appData.debugMode) fclose(debugFP); // [DM] debug
2614 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2615 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2617 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2618 unlink(gameCopyFilename);
2619 unlink(gamePasteFilename);
2622 RETSIGTYPE TermSizeSigHandler(int sig)
2635 CmailSigHandler(sig)
2641 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2643 /* Activate call-back function CmailSigHandlerCallBack() */
2644 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2646 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2650 CmailSigHandlerCallBack(isr, closure, message, count, error)
2658 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2660 /**** end signal code ****/
2666 /* try to open the icsLogon script, either in the location given
2667 * or in the users HOME directory
2674 f = fopen(appData.icsLogon, "r");
2677 homedir = getenv("HOME");
2678 if (homedir != NULL)
2680 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2681 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2682 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2683 f = fopen(buf, "r");
2688 ProcessICSInitScript(f);
2690 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2699 EditCommentPopDown();
2714 if (!menuBarWidget) return;
2715 w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2717 DisplayError("menuEdit.Revert", 0);
2719 XtSetSensitive(w, !grey);
2721 w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2723 DisplayError("menuEdit.Annotate", 0);
2725 XtSetSensitive(w, !grey);
2730 SetMenuEnables(enab)
2734 if (!menuBarWidget) return;
2735 while (enab->name != NULL) {
2736 w = XtNameToWidget(menuBarWidget, enab->name);
2738 DisplayError(enab->name, 0);
2740 XtSetSensitive(w, enab->value);
2746 Enables icsEnables[] = {
2747 { "menuFile.Mail Move", False },
2748 { "menuFile.Reload CMail Message", False },
2749 { "menuMode.Machine Black", False },
2750 { "menuMode.Machine White", False },
2751 { "menuMode.Analysis Mode", False },
2752 { "menuMode.Analyze File", False },
2753 { "menuMode.Two Machines", False },
2755 { "menuEngine.Hint", False },
2756 { "menuEngine.Book", False },
2757 { "menuEngine.Move Now", False },
2758 { "menuOptions.Periodic Updates", False },
2759 { "menuOptions.Hide Thinking", False },
2760 { "menuOptions.Ponder Next Move", False },
2761 { "menuEngine.Engine #1 Settings", False },
2763 { "menuEngine.Engine #2 Settings", False },
2764 { "menuEdit.Annotate", False },
2768 Enables ncpEnables[] = {
2769 { "menuFile.Mail Move", False },
2770 { "menuFile.Reload CMail Message", False },
2771 { "menuMode.Machine White", False },
2772 { "menuMode.Machine Black", False },
2773 { "menuMode.Analysis Mode", False },
2774 { "menuMode.Analyze File", False },
2775 { "menuMode.Two Machines", False },
2776 { "menuMode.ICS Client", False },
2777 { "menuView.ICS Input Box", False },
2778 { "Action", False },
2779 { "menuEdit.Revert", False },
2780 { "menuEdit.Annotate", False },
2781 { "menuEngine.Engine #1 Settings", False },
2782 { "menuEngine.Engine #2 Settings", False },
2783 { "menuEngine.Move Now", False },
2784 { "menuEngine.Retract Move", False },
2785 { "menuOptions.Auto Flag", False },
2786 { "menuOptions.Auto Flip View", False },
2787 { "menuOptions.ICS", False },
2788 // { "menuOptions.ICS Alarm", False },
2789 { "menuOptions.Move Sound", False },
2790 { "menuOptions.Hide Thinking", False },
2791 { "menuOptions.Periodic Updates", False },
2792 { "menuOptions.Ponder Next Move", False },
2793 { "menuEngine.Hint", False },
2794 { "menuEngine.Book", False },
2798 Enables gnuEnables[] = {
2799 { "menuMode.ICS Client", False },
2800 { "menuView.ICS Input Box", False },
2801 { "menuAction.Accept", False },
2802 { "menuAction.Decline", False },
2803 { "menuAction.Rematch", False },
2804 { "menuAction.Adjourn", False },
2805 { "menuAction.Stop Examining", False },
2806 { "menuAction.Stop Observing", False },
2807 { "menuAction.Upload to Examine", False },
2808 { "menuEdit.Revert", False },
2809 { "menuEdit.Annotate", False },
2810 { "menuOptions.ICS", False },
2812 /* The next two options rely on SetCmailMode being called *after* */
2813 /* SetGNUMode so that when GNU is being used to give hints these */
2814 /* menu options are still available */
2816 { "menuFile.Mail Move", False },
2817 { "menuFile.Reload CMail Message", False },
2821 Enables cmailEnables[] = {
2823 { "menuAction.Call Flag", False },
2824 { "menuAction.Draw", True },
2825 { "menuAction.Adjourn", False },
2826 { "menuAction.Abort", False },
2827 { "menuAction.Stop Observing", False },
2828 { "menuAction.Stop Examining", False },
2829 { "menuFile.Mail Move", True },
2830 { "menuFile.Reload CMail Message", True },
2834 Enables trainingOnEnables[] = {
2835 { "menuMode.Edit Comment", False },
2836 { "menuMode.Pause", False },
2837 { "menuEdit.Forward", False },
2838 { "menuEdit.Backward", False },
2839 { "menuEdit.Forward to End", False },
2840 { "menuEdit.Back to Start", False },
2841 { "menuEngine.Move Now", False },
2842 { "menuEdit.Truncate Game", False },
2846 Enables trainingOffEnables[] = {
2847 { "menuMode.Edit Comment", True },
2848 { "menuMode.Pause", True },
2849 { "menuEdit.Forward", True },
2850 { "menuEdit.Backward", True },
2851 { "menuEdit.Forward to End", True },
2852 { "menuEdit.Back to Start", True },
2853 { "menuEngine.Move Now", True },
2854 { "menuEdit.Truncate Game", True },
2858 Enables machineThinkingEnables[] = {
2859 { "menuFile.Load Game", False },
2860 // { "menuFile.Load Next Game", False },
2861 // { "menuFile.Load Previous Game", False },
2862 // { "menuFile.Reload Same Game", False },
2863 { "menuEdit.Paste Game", False },
2864 { "menuFile.Load Position", False },
2865 // { "menuFile.Load Next Position", False },
2866 // { "menuFile.Load Previous Position", False },
2867 // { "menuFile.Reload Same Position", False },
2868 { "menuEdit.Paste Position", False },
2869 { "menuMode.Machine White", False },
2870 { "menuMode.Machine Black", False },
2871 { "menuMode.Two Machines", False },
2872 { "menuEngine.Retract Move", False },
2876 Enables userThinkingEnables[] = {
2877 { "menuFile.Load Game", True },
2878 // { "menuFile.Load Next Game", True },
2879 // { "menuFile.Load Previous Game", True },
2880 // { "menuFile.Reload Same Game", True },
2881 { "menuEdit.Paste Game", True },
2882 { "menuFile.Load Position", True },
2883 // { "menuFile.Load Next Position", True },
2884 // { "menuFile.Load Previous Position", True },
2885 // { "menuFile.Reload Same Position", True },
2886 { "menuEdit.Paste Position", True },
2887 { "menuMode.Machine White", True },
2888 { "menuMode.Machine Black", True },
2889 { "menuMode.Two Machines", True },
2890 { "menuEngine.Retract Move", True },
2896 SetMenuEnables(icsEnables);
2899 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2900 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2907 SetMenuEnables(ncpEnables);
2913 SetMenuEnables(gnuEnables);
2919 SetMenuEnables(cmailEnables);
2925 SetMenuEnables(trainingOnEnables);
2926 if (appData.showButtonBar) {
2927 XtSetSensitive(buttonBarWidget, False);
2933 SetTrainingModeOff()
2935 SetMenuEnables(trainingOffEnables);
2936 if (appData.showButtonBar) {
2937 XtSetSensitive(buttonBarWidget, True);
2942 SetUserThinkingEnables()
2944 if (appData.noChessProgram) return;
2945 SetMenuEnables(userThinkingEnables);
2949 SetMachineThinkingEnables()
2951 if (appData.noChessProgram) return;
2952 SetMenuEnables(machineThinkingEnables);
2954 case MachinePlaysBlack:
2955 case MachinePlaysWhite:
2956 case TwoMachinesPlay:
2957 XtSetSensitive(XtNameToWidget(menuBarWidget,
2958 ModeToWidgetName(gameMode)), True);
2965 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2966 #define HISTORY_SIZE 64
2967 static char *history[HISTORY_SIZE];
2968 int histIn = 0, histP = 0;
2971 SaveInHistory(char *cmd)
2973 if (history[histIn] != NULL) {
2974 free(history[histIn]);
2975 history[histIn] = NULL;
2977 if (*cmd == NULLCHAR) return;
2978 history[histIn] = StrSave(cmd);
2979 histIn = (histIn + 1) % HISTORY_SIZE;
2980 if (history[histIn] != NULL) {
2981 free(history[histIn]);
2982 history[histIn] = NULL;
2988 PrevInHistory(char *cmd)
2991 if (histP == histIn) {
2992 if (history[histIn] != NULL) free(history[histIn]);
2993 history[histIn] = StrSave(cmd);
2995 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
2996 if (newhp == histIn || history[newhp] == NULL) return NULL;
2998 return history[histP];
3004 if (histP == histIn) return NULL;
3005 histP = (histP + 1) % HISTORY_SIZE;
3006 return history[histP];
3008 // end of borrowed code
3010 #define Abs(n) ((n)<0 ? -(n) : (n))
3013 * Find a font that matches "pattern" that is as close as
3014 * possible to the targetPxlSize. Prefer fonts that are k
3015 * pixels smaller to fonts that are k pixels larger. The
3016 * pattern must be in the X Consortium standard format,
3017 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3018 * The return value should be freed with XtFree when no
3022 FindFont(pattern, targetPxlSize)
3026 char **fonts, *p, *best, *scalable, *scalableTail;
3027 int i, j, nfonts, minerr, err, pxlSize;
3030 char **missing_list;
3032 char *def_string, *base_fnt_lst, strInt[3];
3034 XFontStruct **fnt_list;
3036 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3037 snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
3038 p = strstr(pattern, "--");
3039 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3040 strcat(base_fnt_lst, strInt);
3041 strcat(base_fnt_lst, strchr(p + 2, '-'));
3043 if ((fntSet = XCreateFontSet(xDisplay,
3047 &def_string)) == NULL) {
3049 fprintf(stderr, _("Unable to create font set.\n"));
3053 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3055 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3057 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3058 programName, pattern);
3066 for (i=0; i<nfonts; i++) {
3069 if (*p != '-') continue;
3071 if (*p == NULLCHAR) break;
3072 if (*p++ == '-') j++;
3074 if (j < 7) continue;
3077 scalable = fonts[i];
3080 err = pxlSize - targetPxlSize;
3081 if (Abs(err) < Abs(minerr) ||
3082 (minerr > 0 && err < 0 && -err == minerr)) {
3088 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3089 /* If the error is too big and there is a scalable font,
3090 use the scalable font. */
3091 int headlen = scalableTail - scalable;
3092 p = (char *) XtMalloc(strlen(scalable) + 10);
3093 while (isdigit(*scalableTail)) scalableTail++;
3094 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3096 p = (char *) XtMalloc(strlen(best) + 2);
3097 safeStrCpy(p, best, strlen(best)+1 );
3099 if (appData.debugMode) {
3100 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3101 pattern, targetPxlSize, p);
3104 if (missing_count > 0)
3105 XFreeStringList(missing_list);
3106 XFreeFontSet(xDisplay, fntSet);
3108 XFreeFontNames(fonts);
3114 { // [HGM] deletes GCs that are to be remade, to prevent resource leak;
3115 // must be called before all non-first callse to CreateGCs()
3116 XtReleaseGC(shellWidget, highlineGC);
3117 XtReleaseGC(shellWidget, lightSquareGC);
3118 XtReleaseGC(shellWidget, darkSquareGC);
3119 if (appData.monoMode) {
3120 if (DefaultDepth(xDisplay, xScreen) == 1) {
3121 XtReleaseGC(shellWidget, wbPieceGC);
3123 XtReleaseGC(shellWidget, bwPieceGC);
3126 XtReleaseGC(shellWidget, prelineGC);
3127 XtReleaseGC(shellWidget, jailSquareGC);
3128 XtReleaseGC(shellWidget, wdPieceGC);
3129 XtReleaseGC(shellWidget, wlPieceGC);
3130 XtReleaseGC(shellWidget, wjPieceGC);
3131 XtReleaseGC(shellWidget, bdPieceGC);
3132 XtReleaseGC(shellWidget, blPieceGC);
3133 XtReleaseGC(shellWidget, bjPieceGC);
3137 void CreateGCs(int redo)
3139 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3140 | GCBackground | GCFunction | GCPlaneMask;
3141 XGCValues gc_values;
3144 gc_values.plane_mask = AllPlanes;
3145 gc_values.line_width = lineGap;
3146 gc_values.line_style = LineSolid;
3147 gc_values.function = GXcopy;
3150 DeleteGCs(); // called a second time; clean up old GCs first
3151 } else { // [HGM] grid and font GCs created on first call only
3152 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3153 gc_values.background = XBlackPixel(xDisplay, xScreen);
3154 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3156 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3157 gc_values.background = XWhitePixel(xDisplay, xScreen);
3158 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3159 XSetFont(xDisplay, coordGC, coordFontID);
3161 // [HGM] make font for holdings counts (white on black)
3162 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3163 gc_values.background = XBlackPixel(xDisplay, xScreen);
3164 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3165 XSetFont(xDisplay, countGC, countFontID);
3167 if (appData.monoMode) {
3168 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3169 gc_values.background = XWhitePixel(xDisplay, xScreen);
3170 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3172 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3173 gc_values.background = XBlackPixel(xDisplay, xScreen);
3174 lightSquareGC = wbPieceGC
3175 = XtGetGC(shellWidget, value_mask, &gc_values);
3177 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3178 gc_values.background = XWhitePixel(xDisplay, xScreen);
3179 darkSquareGC = bwPieceGC
3180 = XtGetGC(shellWidget, value_mask, &gc_values);
3182 if (DefaultDepth(xDisplay, xScreen) == 1) {
3183 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3184 gc_values.function = GXcopyInverted;
3185 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3186 gc_values.function = GXcopy;
3187 if (XBlackPixel(xDisplay, xScreen) == 1) {
3188 bwPieceGC = darkSquareGC;
3189 wbPieceGC = copyInvertedGC;
3191 bwPieceGC = copyInvertedGC;
3192 wbPieceGC = lightSquareGC;
3196 gc_values.foreground = highlightSquareColor;
3197 gc_values.background = highlightSquareColor;
3198 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3200 gc_values.foreground = premoveHighlightColor;
3201 gc_values.background = premoveHighlightColor;
3202 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3204 gc_values.foreground = lightSquareColor;
3205 gc_values.background = darkSquareColor;
3206 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3208 gc_values.foreground = darkSquareColor;
3209 gc_values.background = lightSquareColor;
3210 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3212 gc_values.foreground = jailSquareColor;
3213 gc_values.background = jailSquareColor;
3214 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3216 gc_values.foreground = whitePieceColor;
3217 gc_values.background = darkSquareColor;
3218 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3220 gc_values.foreground = whitePieceColor;
3221 gc_values.background = lightSquareColor;
3222 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3224 gc_values.foreground = whitePieceColor;
3225 gc_values.background = jailSquareColor;
3226 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3228 gc_values.foreground = blackPieceColor;
3229 gc_values.background = darkSquareColor;
3230 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3232 gc_values.foreground = blackPieceColor;
3233 gc_values.background = lightSquareColor;
3234 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3236 gc_values.foreground = blackPieceColor;
3237 gc_values.background = jailSquareColor;
3238 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3242 void loadXIM(xim, xmask, filename, dest, mask)
3255 fp = fopen(filename, "rb");
3257 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3264 for (y=0; y<h; ++y) {
3265 for (x=0; x<h; ++x) {
3270 XPutPixel(xim, x, y, blackPieceColor);
3272 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3275 XPutPixel(xim, x, y, darkSquareColor);
3277 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3280 XPutPixel(xim, x, y, whitePieceColor);
3282 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3285 XPutPixel(xim, x, y, lightSquareColor);
3287 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3295 /* create Pixmap of piece */
3296 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3298 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3301 /* create Pixmap of clipmask
3302 Note: We assume the white/black pieces have the same
3303 outline, so we make only 6 masks. This is okay
3304 since the XPM clipmask routines do the same. */
3306 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3308 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3311 /* now create the 1-bit version */
3312 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3315 values.foreground = 1;
3316 values.background = 0;
3318 /* Don't use XtGetGC, not read only */
3319 maskGC = XCreateGC(xDisplay, *mask,
3320 GCForeground | GCBackground, &values);
3321 XCopyPlane(xDisplay, temp, *mask, maskGC,
3322 0, 0, squareSize, squareSize, 0, 0, 1);
3323 XFreePixmap(xDisplay, temp);
3328 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3330 void CreateXIMPieces()
3335 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3340 /* The XSynchronize calls were copied from CreatePieces.
3341 Not sure if needed, but can't hurt */
3342 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3345 /* temp needed by loadXIM() */
3346 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3347 0, 0, ss, ss, AllPlanes, XYPixmap);
3349 if (strlen(appData.pixmapDirectory) == 0) {
3353 if (appData.monoMode) {
3354 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3358 fprintf(stderr, _("\nLoading XIMs...\n"));
3360 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3361 fprintf(stderr, "%d", piece+1);
3362 for (kind=0; kind<4; kind++) {
3363 fprintf(stderr, ".");
3364 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3365 ExpandPathName(appData.pixmapDirectory),
3366 piece <= (int) WhiteKing ? "" : "w",
3367 pieceBitmapNames[piece],
3369 ximPieceBitmap[kind][piece] =
3370 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3371 0, 0, ss, ss, AllPlanes, XYPixmap);
3372 if (appData.debugMode)
3373 fprintf(stderr, _("(File:%s:) "), buf);
3374 loadXIM(ximPieceBitmap[kind][piece],
3376 &(xpmPieceBitmap2[kind][piece]),
3377 &(ximMaskPm2[piece]));
3378 if(piece <= (int)WhiteKing)
3379 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3381 fprintf(stderr," ");
3383 /* Load light and dark squares */
3384 /* If the LSQ and DSQ pieces don't exist, we will
3385 draw them with solid squares. */
3386 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3387 if (access(buf, 0) != 0) {
3391 fprintf(stderr, _("light square "));
3393 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3394 0, 0, ss, ss, AllPlanes, XYPixmap);
3395 if (appData.debugMode)
3396 fprintf(stderr, _("(File:%s:) "), buf);
3398 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3399 fprintf(stderr, _("dark square "));
3400 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3401 ExpandPathName(appData.pixmapDirectory), ss);
3402 if (appData.debugMode)
3403 fprintf(stderr, _("(File:%s:) "), buf);
3405 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3406 0, 0, ss, ss, AllPlanes, XYPixmap);
3407 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3408 xpmJailSquare = xpmLightSquare;
3410 fprintf(stderr, _("Done.\n"));
3412 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3416 void CreateXPMBoard(char *s, int kind)
3420 if(s == NULL || *s == 0 || *s == '*') { useTexture &= ~(kind+1); return; }
3421 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3422 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3426 void FreeXPMPieces()
3427 { // [HGM] to prevent resoucre leak on calling CreaeXPMPieces() a second time,
3428 // thisroutine has to be called t free the old piece pixmaps
3430 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++)
3431 for (kind=0; kind<4; kind++) XFreePixmap(xDisplay, xpmPieceBitmap2[kind][piece]);
3433 XFreePixmap(xDisplay, xpmLightSquare);
3434 XFreePixmap(xDisplay, xpmDarkSquare);
3438 void CreateXPMPieces()
3442 u_int ss = squareSize;
3444 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3445 XpmColorSymbol symbols[4];
3446 static int redo = False;
3448 if(redo) FreeXPMPieces(); else redo = 1;
3450 /* The XSynchronize calls were copied from CreatePieces.
3451 Not sure if needed, but can't hurt */
3452 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3454 /* Setup translations so piece colors match square colors */
3455 symbols[0].name = "light_piece";
3456 symbols[0].value = appData.whitePieceColor;
3457 symbols[1].name = "dark_piece";
3458 symbols[1].value = appData.blackPieceColor;
3459 symbols[2].name = "light_square";
3460 symbols[2].value = appData.lightSquareColor;
3461 symbols[3].name = "dark_square";
3462 symbols[3].value = appData.darkSquareColor;
3464 attr.valuemask = XpmColorSymbols;
3465 attr.colorsymbols = symbols;
3466 attr.numsymbols = 4;
3468 if (appData.monoMode) {
3469 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3473 if (strlen(appData.pixmapDirectory) == 0) {
3474 XpmPieces* pieces = builtInXpms;
3477 while (pieces->size != squareSize && pieces->size) pieces++;
3478 if (!pieces->size) {
3479 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3482 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3483 for (kind=0; kind<4; kind++) {
3485 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3486 pieces->xpm[piece][kind],
3487 &(xpmPieceBitmap2[kind][piece]),
3488 NULL, &attr)) != 0) {
3489 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3493 if(piece <= (int) WhiteKing)
3494 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3498 xpmJailSquare = xpmLightSquare;
3502 fprintf(stderr, _("\nLoading XPMs...\n"));
3505 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3506 fprintf(stderr, "%d ", piece+1);
3507 for (kind=0; kind<4; kind++) {
3508 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3509 ExpandPathName(appData.pixmapDirectory),
3510 piece > (int) WhiteKing ? "w" : "",
3511 pieceBitmapNames[piece],
3513 if (appData.debugMode) {
3514 fprintf(stderr, _("(File:%s:) "), buf);
3516 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3517 &(xpmPieceBitmap2[kind][piece]),
3518 NULL, &attr)) != 0) {
3519 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3520 // [HGM] missing: read of unorthodox piece failed; substitute King.
3521 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3522 ExpandPathName(appData.pixmapDirectory),
3524 if (appData.debugMode) {
3525 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3527 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3528 &(xpmPieceBitmap2[kind][piece]),
3532 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3537 if(piece <= (int) WhiteKing)
3538 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3541 /* Load light and dark squares */
3542 /* If the LSQ and DSQ pieces don't exist, we will
3543 draw them with solid squares. */
3544 fprintf(stderr, _("light square "));
3545 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3546 if (access(buf, 0) != 0) {
3550 if (appData.debugMode)
3551 fprintf(stderr, _("(File:%s:) "), buf);
3553 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3554 &xpmLightSquare, NULL, &attr)) != 0) {
3555 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3558 fprintf(stderr, _("dark square "));
3559 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3560 ExpandPathName(appData.pixmapDirectory), ss);
3561 if (appData.debugMode) {
3562 fprintf(stderr, _("(File:%s:) "), buf);
3564 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3565 &xpmDarkSquare, NULL, &attr)) != 0) {
3566 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3570 xpmJailSquare = xpmLightSquare;
3571 fprintf(stderr, _("Done.\n"));
3573 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3576 #endif /* HAVE_LIBXPM */
3579 /* No built-in bitmaps */
3584 u_int ss = squareSize;
3586 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3589 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3590 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3591 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3592 pieceBitmapNames[piece],
3593 ss, kind == SOLID ? 's' : 'o');
3594 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3595 if(piece <= (int)WhiteKing)
3596 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3600 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3604 /* With built-in bitmaps */
3607 BuiltInBits* bib = builtInBits;
3610 u_int ss = squareSize;
3612 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3615 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3617 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3618 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3619 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3620 pieceBitmapNames[piece],
3621 ss, kind == SOLID ? 's' : 'o');
3622 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3623 bib->bits[kind][piece], ss, ss);
3624 if(piece <= (int)WhiteKing)
3625 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3629 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3634 void ReadBitmap(pm, name, bits, wreq, hreq)
3637 unsigned char bits[];
3643 char msg[MSG_SIZ], fullname[MSG_SIZ];
3645 if (*appData.bitmapDirectory != NULLCHAR) {
3646 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3647 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3648 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3649 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3650 &w, &h, pm, &x_hot, &y_hot);
3651 fprintf(stderr, "load %s\n", name);
3652 if (errcode != BitmapSuccess) {
3654 case BitmapOpenFailed:
3655 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3657 case BitmapFileInvalid:
3658 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3660 case BitmapNoMemory:
3661 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3665 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3669 fprintf(stderr, _("%s: %s...using built-in\n"),
3671 } else if (w != wreq || h != hreq) {
3673 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3674 programName, fullname, w, h, wreq, hreq);
3680 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3689 if (lineGap == 0) return;
3691 /* [HR] Split this into 2 loops for non-square boards. */
3693 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3694 gridSegments[i].x1 = 0;
3695 gridSegments[i].x2 =
3696 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3697 gridSegments[i].y1 = gridSegments[i].y2
3698 = lineGap / 2 + (i * (squareSize + lineGap));
3701 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3702 gridSegments[j + i].y1 = 0;
3703 gridSegments[j + i].y2 =
3704 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3705 gridSegments[j + i].x1 = gridSegments[j + i].x2
3706 = lineGap / 2 + (j * (squareSize + lineGap));
3710 static void MenuBarSelect(w, addr, index)
3715 XtActionProc proc = (XtActionProc) addr;
3717 (proc)(NULL, NULL, NULL, NULL);
3720 void CreateMenuBarPopup(parent, name, mb)
3730 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3733 XtSetArg(args[j], XtNleftMargin, 20); j++;
3734 XtSetArg(args[j], XtNrightMargin, 20); j++;
3736 while (mi->string != NULL) {
3737 if (strcmp(mi->string, "----") == 0) {
3738 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3741 XtSetArg(args[j], XtNlabel, XtNewString(mi->string));
3742 entry = XtCreateManagedWidget(mi->ref, smeBSBObjectClass,
3744 XtAddCallback(entry, XtNcallback,
3745 (XtCallbackProc) MenuBarSelect,
3746 (caddr_t) mi->proc);
3752 Widget CreateMenuBar(mb)
3756 Widget anchor, menuBar;
3758 char menuName[MSG_SIZ];
3761 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3762 XtSetArg(args[j], XtNvSpace, 0); j++;
3763 XtSetArg(args[j], XtNborderWidth, 0); j++;
3764 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3765 formWidget, args, j);
3767 while (mb->name != NULL) {
3768 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3769 strncat(menuName, mb->ref, MSG_SIZ - strlen(menuName) - 1);
3771 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3774 shortName[0] = mb->name[0];
3775 shortName[1] = NULLCHAR;
3776 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3779 XtSetArg(args[j], XtNlabel, XtNewString(mb->name)); j++;
3782 XtSetArg(args[j], XtNborderWidth, 0); j++;
3783 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3785 CreateMenuBarPopup(menuBar, menuName, mb);
3791 Widget CreateButtonBar(mi)
3795 Widget button, buttonBar;
3799 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3801 XtSetArg(args[j], XtNhSpace, 0); j++;
3803 XtSetArg(args[j], XtNborderWidth, 0); j++;
3804 XtSetArg(args[j], XtNvSpace, 0); j++;
3805 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3806 formWidget, args, j);
3808 while (mi->string != NULL) {
3811 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3812 XtSetArg(args[j], XtNborderWidth, 0); j++;
3814 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3815 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3816 buttonBar, args, j);
3817 XtAddCallback(button, XtNcallback,
3818 (XtCallbackProc) MenuBarSelect,
3819 (caddr_t) mi->proc);
3826 CreatePieceMenu(name, color)
3833 ChessSquare selection;
3835 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3836 boardWidget, args, 0);
3838 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3839 String item = pieceMenuStrings[color][i];
3841 if (strcmp(item, "----") == 0) {
3842 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3845 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3846 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3848 selection = pieceMenuTranslation[color][i];
3849 XtAddCallback(entry, XtNcallback,
3850 (XtCallbackProc) PieceMenuSelect,
3851 (caddr_t) selection);
3852 if (selection == WhitePawn || selection == BlackPawn) {
3853 XtSetArg(args[0], XtNpopupOnEntry, entry);
3854 XtSetValues(menu, args, 1);
3867 ChessSquare selection;
3869 whitePieceMenu = CreatePieceMenu("menuW", 0);
3870 blackPieceMenu = CreatePieceMenu("menuB", 1);
3872 XtRegisterGrabAction(PieceMenuPopup, True,
3873 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3874 GrabModeAsync, GrabModeAsync);
3876 XtSetArg(args[0], XtNlabel, _("Drop"));
3877 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3878 boardWidget, args, 1);
3879 for (i = 0; i < DROP_MENU_SIZE; i++) {
3880 String item = dropMenuStrings[i];
3882 if (strcmp(item, "----") == 0) {
3883 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3886 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3887 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3889 selection = dropMenuTranslation[i];
3890 XtAddCallback(entry, XtNcallback,
3891 (XtCallbackProc) DropMenuSelect,
3892 (caddr_t) selection);
3897 void SetupDropMenu()
3905 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3906 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3907 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3908 dmEnables[i].piece);
3909 XtSetSensitive(entry, p != NULL || !appData.testLegality
3910 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3911 && !appData.icsActive));
3913 while (p && *p++ == dmEnables[i].piece) count++;
3914 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3916 XtSetArg(args[j], XtNlabel, label); j++;
3917 XtSetValues(entry, args, j);
3921 void PieceMenuPopup(w, event, params, num_params)
3925 Cardinal *num_params;
3927 String whichMenu; int menuNr;
3928 if (event->type == ButtonRelease)
3929 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3930 else if (event->type == ButtonPress)
3931 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3933 case 0: whichMenu = params[0]; break;
3934 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3936 case -1: if (errorUp) ErrorPopDown();
3939 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3942 static void PieceMenuSelect(w, piece, junk)
3947 if (pmFromX < 0 || pmFromY < 0) return;
3948 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3951 static void DropMenuSelect(w, piece, junk)
3956 if (pmFromX < 0 || pmFromY < 0) return;
3957 DropMenuEvent(piece, pmFromX, pmFromY);
3960 void WhiteClock(w, event, prms, nprms)
3969 void BlackClock(w, event, prms, nprms)
3980 * If the user selects on a border boundary, return -1; if off the board,
3981 * return -2. Otherwise map the event coordinate to the square.
3983 int EventToSquare(x, limit)
3991 if ((x % (squareSize + lineGap)) >= squareSize)
3993 x /= (squareSize + lineGap);
3999 static void do_flash_delay(msec)
4005 static void drawHighlight(file, rank, gc)
4011 if (lineGap == 0) return;
4014 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
4015 (squareSize + lineGap);
4016 y = lineGap/2 + rank * (squareSize + lineGap);
4018 x = lineGap/2 + file * (squareSize + lineGap);
4019 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
4020 (squareSize + lineGap);
4023 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
4024 squareSize+lineGap, squareSize+lineGap);
4027 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
4028 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4031 SetHighlights(fromX, fromY, toX, toY)
4032 int fromX, fromY, toX, toY;
4034 if (hi1X != fromX || hi1Y != fromY) {
4035 if (hi1X >= 0 && hi1Y >= 0) {
4036 drawHighlight(hi1X, hi1Y, lineGC);
4038 } // [HGM] first erase both, then draw new!
4039 if (hi2X != toX || hi2Y != toY) {
4040 if (hi2X >= 0 && hi2Y >= 0) {
4041 drawHighlight(hi2X, hi2Y, lineGC);
4044 if (hi1X != fromX || hi1Y != fromY) {
4045 if (fromX >= 0 && fromY >= 0) {
4046 drawHighlight(fromX, fromY, highlineGC);
4049 if (hi2X != toX || hi2Y != toY) {
4050 if (toX >= 0 && toY >= 0) {
4051 drawHighlight(toX, toY, highlineGC);
4063 SetHighlights(-1, -1, -1, -1);
4068 SetPremoveHighlights(fromX, fromY, toX, toY)
4069 int fromX, fromY, toX, toY;
4071 if (pm1X != fromX || pm1Y != fromY) {
4072 if (pm1X >= 0 && pm1Y >= 0) {
4073 drawHighlight(pm1X, pm1Y, lineGC);
4075 if (fromX >= 0 && fromY >= 0) {
4076 drawHighlight(fromX, fromY, prelineGC);
4079 if (pm2X != toX || pm2Y != toY) {
4080 if (pm2X >= 0 && pm2Y >= 0) {
4081 drawHighlight(pm2X, pm2Y, lineGC);
4083 if (toX >= 0 && toY >= 0) {
4084 drawHighlight(toX, toY, prelineGC);
4094 ClearPremoveHighlights()
4096 SetPremoveHighlights(-1, -1, -1, -1);
4099 static int CutOutSquare(x, y, x0, y0, kind)
4100 int x, y, *x0, *y0, kind;
4102 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
4103 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
4105 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
4106 if(textureW[kind] < W*squareSize)
4107 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
4109 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
4110 if(textureH[kind] < H*squareSize)
4111 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
4113 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
4117 static void BlankSquare(x, y, color, piece, dest, fac)
4118 int x, y, color, fac;
4121 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
4123 if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
4124 XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
4125 squareSize, squareSize, x*fac, y*fac);
4127 if (useImages && useImageSqs) {
4131 pm = xpmLightSquare;
4136 case 2: /* neutral */
4141 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4142 squareSize, squareSize, x*fac, y*fac);
4152 case 2: /* neutral */
4157 XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
4162 I split out the routines to draw a piece so that I could
4163 make a generic flash routine.
4165 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4167 int square_color, x, y;
4170 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4171 switch (square_color) {
4173 case 2: /* neutral */
4175 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4176 ? *pieceToOutline(piece)
4177 : *pieceToSolid(piece),
4178 dest, bwPieceGC, 0, 0,
4179 squareSize, squareSize, x, y);
4182 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4183 ? *pieceToSolid(piece)
4184 : *pieceToOutline(piece),
4185 dest, wbPieceGC, 0, 0,
4186 squareSize, squareSize, x, y);
4191 static void monoDrawPiece(piece, square_color, x, y, dest)
4193 int square_color, x, y;
4196 switch (square_color) {
4198 case 2: /* neutral */
4200 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4201 ? *pieceToOutline(piece)
4202 : *pieceToSolid(piece),
4203 dest, bwPieceGC, 0, 0,
4204 squareSize, squareSize, x, y, 1);
4207 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4208 ? *pieceToSolid(piece)
4209 : *pieceToOutline(piece),
4210 dest, wbPieceGC, 0, 0,
4211 squareSize, squareSize, x, y, 1);
4216 static void colorDrawPiece(piece, square_color, x, y, dest)
4218 int square_color, x, y;
4221 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4222 switch (square_color) {
4224 XCopyPlane(xDisplay, *pieceToSolid(piece),
4225 dest, (int) piece < (int) BlackPawn
4226 ? wlPieceGC : blPieceGC, 0, 0,
4227 squareSize, squareSize, x, y, 1);
4230 XCopyPlane(xDisplay, *pieceToSolid(piece),
4231 dest, (int) piece < (int) BlackPawn
4232 ? wdPieceGC : bdPieceGC, 0, 0,
4233 squareSize, squareSize, x, y, 1);
4235 case 2: /* neutral */
4237 XCopyPlane(xDisplay, *pieceToSolid(piece),
4238 dest, (int) piece < (int) BlackPawn
4239 ? wjPieceGC : bjPieceGC, 0, 0,
4240 squareSize, squareSize, x, y, 1);
4245 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4247 int square_color, x, y;
4250 int kind, p = piece;
4252 switch (square_color) {
4254 case 2: /* neutral */
4256 if ((int)piece < (int) BlackPawn) {
4264 if ((int)piece < (int) BlackPawn) {
4272 if(appData.upsideDown && flipView) { kind ^= 2; p += p < BlackPawn ? BlackPawn : -BlackPawn; }// swap white and black pieces
4273 if(useTexture & square_color+1) {
4274 BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
4275 XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
4276 XSetClipOrigin(xDisplay, wlPieceGC, x, y);
4277 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);
4278 XSetClipMask(xDisplay, wlPieceGC, None);
4279 XSetClipOrigin(xDisplay, wlPieceGC, 0, 0);
4281 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4282 dest, wlPieceGC, 0, 0,
4283 squareSize, squareSize, x, y);
4286 typedef void (*DrawFunc)();
4288 DrawFunc ChooseDrawFunc()
4290 if (appData.monoMode) {
4291 if (DefaultDepth(xDisplay, xScreen) == 1) {
4292 return monoDrawPiece_1bit;
4294 return monoDrawPiece;
4298 return colorDrawPieceImage;
4300 return colorDrawPiece;
4304 /* [HR] determine square color depending on chess variant. */
4305 static int SquareColor(row, column)
4310 if (gameInfo.variant == VariantXiangqi) {
4311 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4313 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4315 } else if (row <= 4) {
4321 square_color = ((column + row) % 2) == 1;
4324 /* [hgm] holdings: next line makes all holdings squares light */
4325 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4327 return square_color;
4330 void DrawSquare(row, column, piece, do_flash)
4331 int row, column, do_flash;
4334 int square_color, x, y, direction, font_ascent, font_descent;
4337 XCharStruct overall;
4341 /* Calculate delay in milliseconds (2-delays per complete flash) */
4342 flash_delay = 500 / appData.flashRate;
4345 x = lineGap + ((BOARD_WIDTH-1)-column) *
4346 (squareSize + lineGap);
4347 y = lineGap + row * (squareSize + lineGap);
4349 x = lineGap + column * (squareSize + lineGap);
4350 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4351 (squareSize + lineGap);
4354 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4356 square_color = SquareColor(row, column);
4358 if ( // [HGM] holdings: blank out area between board and holdings
4359 column == BOARD_LEFT-1 || column == BOARD_RGHT
4360 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4361 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4362 BlankSquare(x, y, 2, EmptySquare, xBoardWindow, 1);
4364 // [HGM] print piece counts next to holdings
4365 string[1] = NULLCHAR;
4366 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4367 string[0] = '0' + piece;
4368 XTextExtents(countFontStruct, string, 1, &direction,
4369 &font_ascent, &font_descent, &overall);
4370 if (appData.monoMode) {
4371 XDrawImageString(xDisplay, xBoardWindow, countGC,
4372 x + squareSize - overall.width - 2,
4373 y + font_ascent + 1, string, 1);
4375 XDrawString(xDisplay, xBoardWindow, countGC,
4376 x + squareSize - overall.width - 2,
4377 y + font_ascent + 1, string, 1);
4380 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4381 string[0] = '0' + piece;
4382 XTextExtents(countFontStruct, string, 1, &direction,
4383 &font_ascent, &font_descent, &overall);
4384 if (appData.monoMode) {
4385 XDrawImageString(xDisplay, xBoardWindow, countGC,
4386 x + 2, y + font_ascent + 1, string, 1);
4388 XDrawString(xDisplay, xBoardWindow, countGC,
4389 x + 2, y + font_ascent + 1, string, 1);
4393 if (piece == EmptySquare || appData.blindfold) {
4394 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4396 drawfunc = ChooseDrawFunc();
4397 if (do_flash && appData.flashCount > 0) {
4398 for (i=0; i<appData.flashCount; ++i) {
4400 drawfunc(piece, square_color, x, y, xBoardWindow);
4401 XSync(xDisplay, False);
4402 do_flash_delay(flash_delay);
4404 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4405 XSync(xDisplay, False);
4406 do_flash_delay(flash_delay);
4409 drawfunc(piece, square_color, x, y, xBoardWindow);
4413 string[1] = NULLCHAR;
4414 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4415 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4416 string[0] = 'a' + column - BOARD_LEFT;
4417 XTextExtents(coordFontStruct, string, 1, &direction,
4418 &font_ascent, &font_descent, &overall);
4419 if (appData.monoMode) {
4420 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4421 x + squareSize - overall.width - 2,
4422 y + squareSize - font_descent - 1, string, 1);
4424 XDrawString(xDisplay, xBoardWindow, coordGC,
4425 x + squareSize - overall.width - 2,
4426 y + squareSize - font_descent - 1, string, 1);
4429 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4430 string[0] = ONE + row;
4431 XTextExtents(coordFontStruct, string, 1, &direction,
4432 &font_ascent, &font_descent, &overall);
4433 if (appData.monoMode) {
4434 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4435 x + 2, y + font_ascent + 1, string, 1);
4437 XDrawString(xDisplay, xBoardWindow, coordGC,
4438 x + 2, y + font_ascent + 1, string, 1);
4441 if(!partnerUp && marker[row][column]) {
4442 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4443 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4448 /* Why is this needed on some versions of X? */
4449 void EventProc(widget, unused, event)
4454 if (!XtIsRealized(widget))
4457 switch (event->type) {
4459 if (event->xexpose.count > 0) return; /* no clipping is done */
4460 XDrawPosition(widget, True, NULL);
4461 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4462 flipView = !flipView; partnerUp = !partnerUp;
4463 XDrawPosition(widget, True, NULL);
4464 flipView = !flipView; partnerUp = !partnerUp;
4468 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
4475 void DrawPosition(fullRedraw, board)
4476 /*Boolean*/int fullRedraw;
4479 XDrawPosition(boardWidget, fullRedraw, board);
4482 /* Returns 1 if there are "too many" differences between b1 and b2
4483 (i.e. more than 1 move was made) */
4484 static int too_many_diffs(b1, b2)
4490 for (i=0; i<BOARD_HEIGHT; ++i) {
4491 for (j=0; j<BOARD_WIDTH; ++j) {
4492 if (b1[i][j] != b2[i][j]) {
4493 if (++c > 4) /* Castling causes 4 diffs */
4502 /* Matrix describing castling maneuvers */
4503 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4504 static int castling_matrix[4][5] = {
4505 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4506 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4507 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4508 { 7, 7, 4, 5, 6 } /* 0-0, black */
4511 /* Checks whether castling occurred. If it did, *rrow and *rcol
4512 are set to the destination (row,col) of the rook that moved.
4514 Returns 1 if castling occurred, 0 if not.
4516 Note: Only handles a max of 1 castling move, so be sure
4517 to call too_many_diffs() first.
4519 static int check_castle_draw(newb, oldb, rrow, rcol)
4526 /* For each type of castling... */
4527 for (i=0; i<4; ++i) {
4528 r = castling_matrix[i];
4530 /* Check the 4 squares involved in the castling move */
4532 for (j=1; j<=4; ++j) {
4533 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4540 /* All 4 changed, so it must be a castling move */
4549 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4550 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4552 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4555 void DrawSeekBackground( int left, int top, int right, int bottom )
4557 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4560 void DrawSeekText(char *buf, int x, int y)
4562 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4565 void DrawSeekDot(int x, int y, int colorNr)
4567 int square = colorNr & 0x80;
4570 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4572 XFillRectangle(xDisplay, xBoardWindow, color,
4573 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4575 XFillArc(xDisplay, xBoardWindow, color,
4576 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4579 static int damage[2][BOARD_RANKS][BOARD_FILES];
4582 * event handler for redrawing the board
4584 void XDrawPosition(w, repaint, board)
4586 /*Boolean*/int repaint;
4590 static int lastFlipView = 0;
4591 static int lastBoardValid[2] = {0, 0};
4592 static Board lastBoard[2];
4595 int nr = twoBoards*partnerUp;
4597 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4599 if (board == NULL) {
4600 if (!lastBoardValid[nr]) return;
4601 board = lastBoard[nr];
4603 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4604 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4605 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Flip View"),
4610 * It would be simpler to clear the window with XClearWindow()
4611 * but this causes a very distracting flicker.
4614 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4616 if ( lineGap && IsDrawArrowEnabled())
4617 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4618 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4620 /* If too much changes (begin observing new game, etc.), don't
4622 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4624 /* Special check for castling so we don't flash both the king
4625 and the rook (just flash the king). */
4627 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4628 /* Draw rook with NO flashing. King will be drawn flashing later */
4629 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4630 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4634 /* First pass -- Draw (newly) empty squares and repair damage.
4635 This prevents you from having a piece show up twice while it
4636 is flashing on its new square */
4637 for (i = 0; i < BOARD_HEIGHT; i++)
4638 for (j = 0; j < BOARD_WIDTH; j++)
4639 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4640 || damage[nr][i][j]) {
4641 DrawSquare(i, j, board[i][j], 0);
4642 damage[nr][i][j] = False;
4645 /* Second pass -- Draw piece(s) in new position and flash them */
4646 for (i = 0; i < BOARD_HEIGHT; i++)
4647 for (j = 0; j < BOARD_WIDTH; j++)
4648 if (board[i][j] != lastBoard[nr][i][j]) {
4649 DrawSquare(i, j, board[i][j], do_flash);
4653 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4654 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4655 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4657 for (i = 0; i < BOARD_HEIGHT; i++)
4658 for (j = 0; j < BOARD_WIDTH; j++) {
4659 DrawSquare(i, j, board[i][j], 0);
4660 damage[nr][i][j] = False;
4664 CopyBoard(lastBoard[nr], board);
4665 lastBoardValid[nr] = 1;
4666 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4667 lastFlipView = flipView;
4669 /* Draw highlights */
4670 if (pm1X >= 0 && pm1Y >= 0) {
4671 drawHighlight(pm1X, pm1Y, prelineGC);
4673 if (pm2X >= 0 && pm2Y >= 0) {
4674 drawHighlight(pm2X, pm2Y, prelineGC);
4676 if (hi1X >= 0 && hi1Y >= 0) {
4677 drawHighlight(hi1X, hi1Y, highlineGC);
4679 if (hi2X >= 0 && hi2Y >= 0) {
4680 drawHighlight(hi2X, hi2Y, highlineGC);
4682 DrawArrowHighlight(hi1X, hi1Y, hi2X, hi2Y);
4684 /* If piece being dragged around board, must redraw that too */
4687 XSync(xDisplay, False);
4692 * event handler for redrawing the board
4694 void DrawPositionProc(w, event, prms, nprms)
4700 XDrawPosition(w, True, NULL);
4705 * event handler for parsing user moves
4707 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4708 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4709 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4710 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4711 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4712 // and at the end FinishMove() to perform the move after optional promotion popups.
4713 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4714 void HandleUserMove(w, event, prms, nprms)
4720 if (w != boardWidget || errorExitStatus != -1) return;
4721 if(nprms) shiftKey = !strcmp(prms[0], "1");
4724 if (event->type == ButtonPress) {
4725 XtPopdown(promotionShell);
4726 XtDestroyWidget(promotionShell);
4727 promotionUp = False;
4735 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4736 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4737 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4740 void AnimateUserMove (Widget w, XEvent * event,
4741 String * params, Cardinal * nParams)
4743 DragPieceMove(event->xmotion.x, event->xmotion.y);
4746 void HandlePV (Widget w, XEvent * event,
4747 String * params, Cardinal * nParams)
4748 { // [HGM] pv: walk PV
4749 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4752 Widget CommentCreate(name, text, mutable, callback, lines)
4754 int /*Boolean*/ mutable;
4755 XtCallbackProc callback;
4759 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4764 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4765 XtGetValues(boardWidget, args, j);
4768 XtSetArg(args[j], XtNresizable, True); j++;
4771 XtCreatePopupShell(name, topLevelShellWidgetClass,
4772 shellWidget, args, j);
4775 XtCreatePopupShell(name, transientShellWidgetClass,
4776 shellWidget, args, j);
4779 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4780 layoutArgs, XtNumber(layoutArgs));
4782 XtCreateManagedWidget("form", formWidgetClass, layout,
4783 formArgs, XtNumber(formArgs));
4787 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4788 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4790 XtSetArg(args[j], XtNstring, text); j++;
4791 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4792 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4793 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4794 XtSetArg(args[j], XtNright, XtChainRight); j++;
4795 XtSetArg(args[j], XtNresizable, True); j++;
4796 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4797 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4798 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4799 XtSetArg(args[j], XtNautoFill, True); j++;
4800 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4802 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4803 XtOverrideTranslations(edit, XtParseTranslationTable(commentTranslations));
4807 XtSetArg(args[j], XtNfromVert, edit); j++;
4808 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4809 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4810 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4811 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4813 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4814 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4817 XtSetArg(args[j], XtNfromVert, edit); j++;
4818 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4819 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4820 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4821 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4822 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4824 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4825 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4828 XtSetArg(args[j], XtNfromVert, edit); j++;
4829 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4830 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4831 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4832 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4833 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4835 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4836 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4839 XtSetArg(args[j], XtNfromVert, edit); j++;
4840 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4841 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4842 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4843 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4845 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4846 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4849 XtSetArg(args[j], XtNfromVert, edit); j++;
4850 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4851 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4852 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4853 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4854 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4856 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4857 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4860 XtRealizeWidget(shell);
4862 if (commentX == -1) {
4865 Dimension pw_height;
4866 Dimension ew_height;
4869 XtSetArg(args[j], XtNheight, &ew_height); j++;
4870 XtGetValues(edit, args, j);
4873 XtSetArg(args[j], XtNheight, &pw_height); j++;
4874 XtGetValues(shell, args, j);
4875 commentH = pw_height + (lines - 1) * ew_height;
4876 commentW = bw_width - 16;
4878 XSync(xDisplay, False);
4880 /* This code seems to tickle an X bug if it is executed too soon
4881 after xboard starts up. The coordinates get transformed as if
4882 the main window was positioned at (0, 0).
4884 XtTranslateCoords(shellWidget,
4885 (bw_width - commentW) / 2, 0 - commentH / 2,
4886 &commentX, &commentY);
4888 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4889 RootWindowOfScreen(XtScreen(shellWidget)),
4890 (bw_width - commentW) / 2, 0 - commentH / 2,
4895 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4898 if(wpComment.width > 0) {
4899 commentX = wpComment.x;
4900 commentY = wpComment.y;
4901 commentW = wpComment.width;
4902 commentH = wpComment.height;
4906 XtSetArg(args[j], XtNheight, commentH); j++;
4907 XtSetArg(args[j], XtNwidth, commentW); j++;
4908 XtSetArg(args[j], XtNx, commentX); j++;
4909 XtSetArg(args[j], XtNy, commentY); j++;
4910 XtSetValues(shell, args, j);
4911 XtSetKeyboardFocus(shell, edit);
4916 /* Used for analysis window and ICS input window */
4917 Widget MiscCreate(name, text, mutable, callback, lines)
4919 int /*Boolean*/ mutable;
4920 XtCallbackProc callback;
4924 Widget shell, layout, form, edit;
4926 Dimension bw_width, pw_height, ew_height, w, h;
4932 XtSetArg(args[j], XtNresizable, True); j++;
4935 XtCreatePopupShell(name, topLevelShellWidgetClass,
4936 shellWidget, args, j);
4939 XtCreatePopupShell(name, transientShellWidgetClass,
4940 shellWidget, args, j);
4943 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4944 layoutArgs, XtNumber(layoutArgs));
4946 XtCreateManagedWidget("form", formWidgetClass, layout,
4947 formArgs, XtNumber(formArgs));
4951 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4952 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4954 XtSetArg(args[j], XtNstring, text); j++;
4955 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4956 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4957 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4958 XtSetArg(args[j], XtNright, XtChainRight); j++;
4959 XtSetArg(args[j], XtNresizable, True); j++;
4960 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4961 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4962 XtSetArg(args[j], XtNautoFill, True); j++;
4963 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4965 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4967 XtRealizeWidget(shell);
4970 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4971 XtGetValues(boardWidget, args, j);
4974 XtSetArg(args[j], XtNheight, &ew_height); j++;
4975 XtGetValues(edit, args, j);
4978 XtSetArg(args[j], XtNheight, &pw_height); j++;
4979 XtGetValues(shell, args, j);
4980 h = pw_height + (lines - 1) * ew_height;
4983 XSync(xDisplay, False);
4985 /* This code seems to tickle an X bug if it is executed too soon
4986 after xboard starts up. The coordinates get transformed as if
4987 the main window was positioned at (0, 0).
4989 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4991 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4992 RootWindowOfScreen(XtScreen(shellWidget)),
4993 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4997 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5000 XtSetArg(args[j], XtNheight, h); j++;
5001 XtSetArg(args[j], XtNwidth, w); j++;
5002 XtSetArg(args[j], XtNx, x); j++;
5003 XtSetArg(args[j], XtNy, y); j++;
5004 XtSetValues(shell, args, j);
5010 static int savedIndex; /* gross that this is global */
5012 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
5015 XawTextPosition index, dummy;
5018 XawTextGetSelectionPos(w, &index, &dummy);
5019 XtSetArg(arg, XtNstring, &val);
5020 XtGetValues(w, &arg, 1);
5021 ReplaceComment(savedIndex, val);
5022 if(savedIndex != currentMove) ToNrEvent(savedIndex);
5023 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
5026 void EditCommentPopUp(index, title, text)
5035 if (text == NULL) text = "";
5037 if (editShell == NULL) {
5039 CommentCreate(title, text, True, EditCommentCallback, 4);
5040 XtRealizeWidget(editShell);
5041 CatchDeleteWindow(editShell, "EditCommentPopDown");
5043 edit = XtNameToWidget(editShell, "*form.text");
5045 XtSetArg(args[j], XtNstring, text); j++;
5046 XtSetValues(edit, args, j);
5048 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5049 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5050 XtSetValues(editShell, args, j);
5053 XtPopup(editShell, XtGrabNone);
5057 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5058 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"),
5060 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"),
5064 void EditCommentCallback(w, client_data, call_data)
5066 XtPointer client_data, call_data;
5074 XtSetArg(args[j], XtNlabel, &name); j++;
5075 XtGetValues(w, args, j);
5077 if (strcmp(name, _("ok")) == 0) {
5078 edit = XtNameToWidget(editShell, "*form.text");
5080 XtSetArg(args[j], XtNstring, &val); j++;
5081 XtGetValues(edit, args, j);
5082 ReplaceComment(savedIndex, val);
5083 EditCommentPopDown();
5084 } else if (strcmp(name, _("cancel")) == 0) {
5085 EditCommentPopDown();
5086 } else if (strcmp(name, _("clear")) == 0) {
5087 edit = XtNameToWidget(editShell, "*form.text");
5088 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5089 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5093 void EditCommentPopDown()
5098 if (!editUp) return;
5100 XtSetArg(args[j], XtNx, &commentX); j++;
5101 XtSetArg(args[j], XtNy, &commentY); j++;
5102 XtSetArg(args[j], XtNheight, &commentH); j++;
5103 XtSetArg(args[j], XtNwidth, &commentW); j++;
5104 XtGetValues(editShell, args, j);
5105 XtPopdown(editShell);
5108 XtSetArg(args[j], XtNleftBitmap, None); j++;
5109 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"),
5111 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"),
5115 void ICSInputBoxPopUp()
5120 char *title = _("ICS Input");
5123 if (ICSInputShell == NULL) {
5124 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
5125 tr = XtParseTranslationTable(ICSInputTranslations);
5126 edit = XtNameToWidget(ICSInputShell, "*form.text");
5127 XtOverrideTranslations(edit, tr);
5128 XtRealizeWidget(ICSInputShell);
5129 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
5132 edit = XtNameToWidget(ICSInputShell, "*form.text");
5134 XtSetArg(args[j], XtNstring, ""); j++;
5135 XtSetValues(edit, args, j);
5137 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5138 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5139 XtSetValues(ICSInputShell, args, j);
5142 XtPopup(ICSInputShell, XtGrabNone);
5143 XtSetKeyboardFocus(ICSInputShell, edit);
5145 ICSInputBoxUp = True;
5147 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5148 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.ICS Input Box"),
5152 void ICSInputSendText()
5159 edit = XtNameToWidget(ICSInputShell, "*form.text");
5161 XtSetArg(args[j], XtNstring, &val); j++;
5162 XtGetValues(edit, args, j);
5164 SendMultiLineToICS(val);
5165 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5166 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5169 void ICSInputBoxPopDown()
5174 if (!ICSInputBoxUp) return;
5176 XtPopdown(ICSInputShell);
5177 ICSInputBoxUp = False;
5179 XtSetArg(args[j], XtNleftBitmap, None); j++;
5180 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.ICS Input Box"),
5184 void CommentPopUp(title, text)
5191 savedIndex = currentMove; // [HGM] vari
5192 if (commentShell == NULL) {
5194 CommentCreate(title, text, False, CommentCallback, 4);
5195 XtRealizeWidget(commentShell);
5196 CatchDeleteWindow(commentShell, "CommentPopDown");
5198 edit = XtNameToWidget(commentShell, "*form.text");
5200 XtSetArg(args[j], XtNstring, text); j++;
5201 XtSetValues(edit, args, j);
5203 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5204 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5205 XtSetValues(commentShell, args, j);
5208 XtPopup(commentShell, XtGrabNone);
5209 XSync(xDisplay, False);
5214 void CommentCallback(w, client_data, call_data)
5216 XtPointer client_data, call_data;
5223 XtSetArg(args[j], XtNlabel, &name); j++;
5224 XtGetValues(w, args, j);
5226 if (strcmp(name, _("close")) == 0) {
5228 } else if (strcmp(name, _("edit")) == 0) {
5235 void CommentPopDown()
5240 if (!commentUp) return;
5242 XtSetArg(args[j], XtNx, &commentX); j++;
5243 XtSetArg(args[j], XtNy, &commentY); j++;
5244 XtSetArg(args[j], XtNwidth, &commentW); j++;
5245 XtSetArg(args[j], XtNheight, &commentH); j++;
5246 XtGetValues(commentShell, args, j);
5247 XtPopdown(commentShell);
5248 XSync(xDisplay, False);
5252 void FileNamePopUp(label, def, proc, openMode)
5258 fileProc = proc; /* I can't see a way not */
5259 fileOpenMode = openMode; /* to use globals here */
5260 { // [HGM] use file-selector dialog stolen from Ghostview
5262 int index; // this is not supported yet
5264 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5265 def, openMode, NULL, &name))
5266 (void) (*fileProc)(f, index=0, name);
5270 void FileNamePopDown()
5272 if (!filenameUp) return;
5273 XtPopdown(fileNameShell);
5274 XtDestroyWidget(fileNameShell);
5279 void FileNameCallback(w, client_data, call_data)
5281 XtPointer client_data, call_data;
5286 XtSetArg(args[0], XtNlabel, &name);
5287 XtGetValues(w, args, 1);
5289 if (strcmp(name, _("cancel")) == 0) {
5294 FileNameAction(w, NULL, NULL, NULL);
5297 void FileNameAction(w, event, prms, nprms)
5309 name = XawDialogGetValueString(w = XtParent(w));
5311 if ((name != NULL) && (*name != NULLCHAR)) {
5312 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
5313 XtPopdown(w = XtParent(XtParent(w)));
5317 p = strrchr(buf, ' ');
5324 fullname = ExpandPathName(buf);
5326 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5329 f = fopen(fullname, fileOpenMode);
5331 DisplayError(_("Failed to open file"), errno);
5333 (void) (*fileProc)(f, index, buf);
5340 XtPopdown(w = XtParent(XtParent(w)));
5346 void PromotionPopUp()
5349 Widget dialog, layout;
5351 Dimension bw_width, pw_width;
5355 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5356 XtGetValues(boardWidget, args, j);
5359 XtSetArg(args[j], XtNresizable, True); j++;
5360 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5362 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5363 shellWidget, args, j);
5365 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5366 layoutArgs, XtNumber(layoutArgs));
5369 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5370 XtSetArg(args[j], XtNborderWidth, 0); j++;
5371 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5374 if(gameInfo.variant != VariantShogi) {
5375 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) {
5376 XawDialogAddButton(dialog, _("Warlord"), PromotionCallback,
5377 (XtPointer) dialog);
5378 XawDialogAddButton(dialog, _("General"), PromotionCallback,
5379 (XtPointer) dialog);
5380 XawDialogAddButton(dialog, _("Lieutenant"), PromotionCallback,
5381 (XtPointer) dialog);
5382 XawDialogAddButton(dialog, _("Captain"), PromotionCallback,
5383 (XtPointer) dialog);
5385 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5386 (XtPointer) dialog);
5387 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5388 (XtPointer) dialog);
5389 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5390 (XtPointer) dialog);
5391 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5392 (XtPointer) dialog);
5394 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5395 gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
\r
5396 gameInfo.variant == VariantGiveaway) {
5397 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5398 (XtPointer) dialog);
5400 if(gameInfo.variant == VariantCapablanca ||
5401 gameInfo.variant == VariantGothic ||
5402 gameInfo.variant == VariantCapaRandom) {
5403 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5404 (XtPointer) dialog);
5405 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5406 (XtPointer) dialog);
5408 } else // [HGM] shogi
5410 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5411 (XtPointer) dialog);
5412 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5413 (XtPointer) dialog);
5415 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5416 (XtPointer) dialog);
5418 XtRealizeWidget(promotionShell);
5419 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5422 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5423 XtGetValues(promotionShell, args, j);
5425 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5426 lineGap + squareSize/3 +
5427 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5428 0 : 6*(squareSize + lineGap)), &x, &y);
5431 XtSetArg(args[j], XtNx, x); j++;
5432 XtSetArg(args[j], XtNy, y); j++;
5433 XtSetValues(promotionShell, args, j);
5435 XtPopup(promotionShell, XtGrabNone);
5440 void PromotionPopDown()
5442 if (!promotionUp) return;
5443 XtPopdown(promotionShell);
5444 XtDestroyWidget(promotionShell);
5445 promotionUp = False;
5448 void PromotionCallback(w, client_data, call_data)
5450 XtPointer client_data, call_data;
5456 XtSetArg(args[0], XtNlabel, &name);
5457 XtGetValues(w, args, 1);
5461 if (fromX == -1) return;
5463 if (strcmp(name, _("cancel")) == 0) {
5467 } else if (strcmp(name, _("Knight")) == 0) {
5469 } else if (strcmp(name, _("Promote")) == 0) {
5471 } else if (strcmp(name, _("Defer")) == 0) {
5474 promoChar = ToLower(name[0]);
5477 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5479 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5480 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5485 void ErrorCallback(w, client_data, call_data)
5487 XtPointer client_data, call_data;
5490 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5492 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5498 if (!errorUp) return;
5500 XtPopdown(errorShell);
5501 XtDestroyWidget(errorShell);
5502 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5505 void ErrorPopUp(title, label, modal)
5506 char *title, *label;
5510 Widget dialog, layout;
5514 Dimension bw_width, pw_width;
5515 Dimension pw_height;
5519 XtSetArg(args[i], XtNresizable, True); i++;
5520 XtSetArg(args[i], XtNtitle, title); i++;
5522 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5523 shellWidget, args, i);
5525 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5526 layoutArgs, XtNumber(layoutArgs));
5529 XtSetArg(args[i], XtNlabel, label); i++;
5530 XtSetArg(args[i], XtNborderWidth, 0); i++;
5531 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5534 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5536 XtRealizeWidget(errorShell);
5537 CatchDeleteWindow(errorShell, "ErrorPopDown");
5540 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5541 XtGetValues(boardWidget, args, i);
5543 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5544 XtSetArg(args[i], XtNheight, &pw_height); i++;
5545 XtGetValues(errorShell, args, i);
5548 /* This code seems to tickle an X bug if it is executed too soon
5549 after xboard starts up. The coordinates get transformed as if
5550 the main window was positioned at (0, 0).
5552 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5553 0 - pw_height + squareSize / 3, &x, &y);
5555 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5556 RootWindowOfScreen(XtScreen(boardWidget)),
5557 (bw_width - pw_width) / 2,
5558 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5562 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5565 XtSetArg(args[i], XtNx, x); i++;
5566 XtSetArg(args[i], XtNy, y); i++;
5567 XtSetValues(errorShell, args, i);
5570 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5573 /* Disable all user input other than deleting the window */
5574 static int frozen = 0;
5578 /* Grab by a widget that doesn't accept input */
5579 XtAddGrab(messageWidget, TRUE, FALSE);
5583 /* Undo a FreezeUI */
5586 if (!frozen) return;
5587 XtRemoveGrab(messageWidget);
5591 char *ModeToWidgetName(mode)
5595 case BeginningOfGame:
5596 if (appData.icsActive)
5597 return "menuMode.ICS Client";
5598 else if (appData.noChessProgram ||
5599 *appData.cmailGameName != NULLCHAR)
5600 return "menuMode.Edit Game";
5602 return "menuMode.Machine Black";
5603 case MachinePlaysBlack:
5604 return "menuMode.Machine Black";
5605 case MachinePlaysWhite:
5606 return "menuMode.Machine White";
5608 return "menuMode.Analysis Mode";
5610 return "menuMode.Analyze File";
5611 case TwoMachinesPlay:
5612 return "menuMode.Two Machines";
5614 return "menuMode.Edit Game";
5615 case PlayFromGameFile:
5616 return "menuFile.Load Game";
5618 return "menuMode.Edit Position";
5620 return "menuMode.Training";
5621 case IcsPlayingWhite:
5622 case IcsPlayingBlack:
5626 return "menuMode.ICS Client";
5633 void ModeHighlight()
5636 static int oldPausing = FALSE;
5637 static GameMode oldmode = (GameMode) -1;
5640 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5642 if (pausing != oldPausing) {
5643 oldPausing = pausing;
5645 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5647 XtSetArg(args[0], XtNleftBitmap, None);
5649 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5652 if (appData.showButtonBar) {
5653 /* Always toggle, don't set. Previous code messes up when
5654 invoked while the button is pressed, as releasing it
5655 toggles the state again. */
5658 XtSetArg(args[0], XtNbackground, &oldbg);
5659 XtSetArg(args[1], XtNforeground, &oldfg);
5660 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5662 XtSetArg(args[0], XtNbackground, oldfg);
5663 XtSetArg(args[1], XtNforeground, oldbg);
5665 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5669 wname = ModeToWidgetName(oldmode);
5670 if (wname != NULL) {
5671 XtSetArg(args[0], XtNleftBitmap, None);
5672 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5674 wname = ModeToWidgetName(gameMode);
5675 if (wname != NULL) {
5676 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5677 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5681 /* Maybe all the enables should be handled here, not just this one */
5682 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5683 gameMode == Training || gameMode == PlayFromGameFile);
5688 * Button/menu procedures
5690 void ResetProc(w, event, prms, nprms)
5699 int LoadGamePopUp(f, gameNumber, title)
5704 cmailMsgLoaded = FALSE;
5705 if (gameNumber == 0) {
5706 int error = GameListBuild(f);
5708 DisplayError(_("Cannot build game list"), error);
5709 } else if (!ListEmpty(&gameList) &&
5710 ((ListGame *) gameList.tailPred)->number > 1) {
5711 GameListPopUp(f, title);
5717 return LoadGame(f, gameNumber, title, FALSE);
5720 void LoadGameProc(w, event, prms, nprms)
5726 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5729 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5732 void LoadNextGameProc(w, event, prms, nprms)
5741 void LoadPrevGameProc(w, event, prms, nprms)
5750 void ReloadGameProc(w, event, prms, nprms)
5759 void LoadNextPositionProc(w, event, prms, nprms)
5768 void LoadPrevPositionProc(w, event, prms, nprms)
5777 void ReloadPositionProc(w, event, prms, nprms)
5786 void LoadPositionProc(w, event, prms, nprms)
5792 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5795 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5798 void SaveGameProc(w, event, prms, nprms)
5804 FileNamePopUp(_("Save game file name?"),
5805 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5809 void SavePositionProc(w, event, prms, nprms)
5815 FileNamePopUp(_("Save position file name?"),
5816 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5820 void ReloadCmailMsgProc(w, event, prms, nprms)
5826 ReloadCmailMsgEvent(FALSE);
5829 void MailMoveProc(w, event, prms, nprms)
5838 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5839 char *selected_fen_position=NULL;
5842 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5843 Atom *type_return, XtPointer *value_return,
5844 unsigned long *length_return, int *format_return)
5846 char *selection_tmp;
5848 if (!selected_fen_position) return False; /* should never happen */
5849 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5850 /* note: since no XtSelectionDoneProc was registered, Xt will
5851 * automatically call XtFree on the value returned. So have to
5852 * make a copy of it allocated with XtMalloc */
5853 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5854 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
5856 *value_return=selection_tmp;
5857 *length_return=strlen(selection_tmp);
5858 *type_return=*target;
5859 *format_return = 8; /* bits per byte */
5861 } else if (*target == XA_TARGETS(xDisplay)) {
5862 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5863 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5864 targets_tmp[1] = XA_STRING;
5865 *value_return = targets_tmp;
5866 *type_return = XA_ATOM;
5868 *format_return = 8 * sizeof(Atom);
5869 if (*format_return > 32) {
5870 *length_return *= *format_return / 32;
5871 *format_return = 32;
5879 /* note: when called from menu all parameters are NULL, so no clue what the
5880 * Widget which was clicked on was, or what the click event was
5882 void CopyPositionProc(w, event, prms, nprms)
5889 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5890 * have a notion of a position that is selected but not copied.
5891 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5893 if(gameMode == EditPosition) EditPositionDone(TRUE);
5894 if (selected_fen_position) free(selected_fen_position);
5895 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5896 if (!selected_fen_position) return;
5897 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5899 SendPositionSelection,
5900 NULL/* lose_ownership_proc */ ,
5901 NULL/* transfer_done_proc */);
5902 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5904 SendPositionSelection,
5905 NULL/* lose_ownership_proc */ ,
5906 NULL/* transfer_done_proc */);
5909 /* function called when the data to Paste is ready */
5911 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5912 Atom *type, XtPointer value, unsigned long *len, int *format)
5915 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5916 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5917 EditPositionPasteFEN(fenstr);
5921 /* called when Paste Position button is pressed,
5922 * all parameters will be NULL */
5923 void PastePositionProc(w, event, prms, nprms)
5929 XtGetSelectionValue(menuBarWidget,
5930 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5931 /* (XtSelectionCallbackProc) */ PastePositionCB,
5932 NULL, /* client_data passed to PastePositionCB */
5934 /* better to use the time field from the event that triggered the
5935 * call to this function, but that isn't trivial to get
5943 SendGameSelection(Widget w, Atom *selection, Atom *target,
5944 Atom *type_return, XtPointer *value_return,
5945 unsigned long *length_return, int *format_return)
5947 char *selection_tmp;
5949 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5950 FILE* f = fopen(gameCopyFilename, "r");
5953 if (f == NULL) return False;
5957 selection_tmp = XtMalloc(len + 1);
5958 count = fread(selection_tmp, 1, len, f);
5961 XtFree(selection_tmp);
5964 selection_tmp[len] = NULLCHAR;
5965 *value_return = selection_tmp;
5966 *length_return = len;
5967 *type_return = *target;
5968 *format_return = 8; /* bits per byte */
5970 } else if (*target == XA_TARGETS(xDisplay)) {
5971 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5972 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5973 targets_tmp[1] = XA_STRING;
5974 *value_return = targets_tmp;
5975 *type_return = XA_ATOM;
5977 *format_return = 8 * sizeof(Atom);
5978 if (*format_return > 32) {
5979 *length_return *= *format_return / 32;
5980 *format_return = 32;
5988 /* note: when called from menu all parameters are NULL, so no clue what the
5989 * Widget which was clicked on was, or what the click event was
5991 void CopyGameProc(w, event, prms, nprms)
5999 ret = SaveGameToFile(gameCopyFilename, FALSE);
6003 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
6004 * have a notion of a game that is selected but not copied.
6005 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
6007 XtOwnSelection(menuBarWidget, XA_PRIMARY,
6010 NULL/* lose_ownership_proc */ ,
6011 NULL/* transfer_done_proc */);
6012 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
6015 NULL/* lose_ownership_proc */ ,
6016 NULL/* transfer_done_proc */);
6019 /* function called when the data to Paste is ready */
6021 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
6022 Atom *type, XtPointer value, unsigned long *len, int *format)
6025 if (value == NULL || *len == 0) {
6026 return; /* nothing had been selected to copy */
6028 f = fopen(gamePasteFilename, "w");
6030 DisplayError(_("Can't open temp file"), errno);
6033 fwrite(value, 1, *len, f);
6036 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
6039 /* called when Paste Game button is pressed,
6040 * all parameters will be NULL */
6041 void PasteGameProc(w, event, prms, nprms)
6047 XtGetSelectionValue(menuBarWidget,
6048 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
6049 /* (XtSelectionCallbackProc) */ PasteGameCB,
6050 NULL, /* client_data passed to PasteGameCB */
6052 /* better to use the time field from the event that triggered the
6053 * call to this function, but that isn't trivial to get
6063 SaveGameProc(NULL, NULL, NULL, NULL);
6067 void QuitProc(w, event, prms, nprms)
6076 void PauseProc(w, event, prms, nprms)
6086 void MachineBlackProc(w, event, prms, nprms)
6092 MachineBlackEvent();
6095 void MachineWhiteProc(w, event, prms, nprms)
6101 MachineWhiteEvent();
6104 void AnalyzeModeProc(w, event, prms, nprms)
6112 if (!first.analysisSupport) {
6113 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6114 DisplayError(buf, 0);
6117 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
6118 if (appData.icsActive) {
6119 if (gameMode != IcsObserving) {
6120 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
6121 DisplayError(buf, 0);
6123 if (appData.icsEngineAnalyze) {
6124 if (appData.debugMode)
6125 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
6131 /* if enable, use want disable icsEngineAnalyze */
6132 if (appData.icsEngineAnalyze) {
6137 appData.icsEngineAnalyze = TRUE;
6138 if (appData.debugMode)
6139 fprintf(debugFP, _("ICS engine analyze starting... \n"));
6141 if (!appData.showThinking)
6142 ShowThinkingProc(w,event,prms,nprms);
6147 void AnalyzeFileProc(w, event, prms, nprms)
6153 if (!first.analysisSupport) {
6155 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6156 DisplayError(buf, 0);
6161 if (!appData.showThinking)
6162 ShowThinkingProc(w,event,prms,nprms);
6165 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
6166 AnalysisPeriodicEvent(1);
6169 void TwoMachinesProc(w, event, prms, nprms)
6178 void IcsClientProc(w, event, prms, nprms)
6187 void EditGameProc(w, event, prms, nprms)
6196 void EditPositionProc(w, event, prms, nprms)
6202 EditPositionEvent();
6205 void TrainingProc(w, event, prms, nprms)
6214 void EditCommentProc(w, event, prms, nprms)
6221 EditCommentPopDown();
6227 void IcsInputBoxProc(w, event, prms, nprms)
6233 if (ICSInputBoxUp) {
6234 ICSInputBoxPopDown();
6240 void AcceptProc(w, event, prms, nprms)
6249 void DeclineProc(w, event, prms, nprms)
6258 void RematchProc(w, event, prms, nprms)
6267 void CallFlagProc(w, event, prms, nprms)
6276 void DrawProc(w, event, prms, nprms)
6285 void AbortProc(w, event, prms, nprms)
6294 void AdjournProc(w, event, prms, nprms)
6303 void ResignProc(w, event, prms, nprms)
6312 void AdjuWhiteProc(w, event, prms, nprms)
6318 UserAdjudicationEvent(+1);
6321 void AdjuBlackProc(w, event, prms, nprms)
6327 UserAdjudicationEvent(-1);
6330 void AdjuDrawProc(w, event, prms, nprms)
6336 UserAdjudicationEvent(0);
6339 void EnterKeyProc(w, event, prms, nprms)
6345 if (ICSInputBoxUp == True)
6349 void UpKeyProc(w, event, prms, nprms)
6354 { // [HGM] input: let up-arrow recall previous line from history
6361 if (!ICSInputBoxUp) return;
6362 edit = XtNameToWidget(ICSInputShell, "*form.text");
6364 XtSetArg(args[j], XtNstring, &val); j++;
6365 XtGetValues(edit, args, j);
6366 val = PrevInHistory(val);
6367 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6368 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6370 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6371 XawTextReplace(edit, 0, 0, &t);
6372 XawTextSetInsertionPoint(edit, 9999);
6376 void DownKeyProc(w, event, prms, nprms)
6381 { // [HGM] input: let down-arrow recall next line from history
6386 if (!ICSInputBoxUp) return;
6387 edit = XtNameToWidget(ICSInputShell, "*form.text");
6388 val = NextInHistory();
6389 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6390 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6392 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6393 XawTextReplace(edit, 0, 0, &t);
6394 XawTextSetInsertionPoint(edit, 9999);
6398 void StopObservingProc(w, event, prms, nprms)
6404 StopObservingEvent();
6407 void StopExaminingProc(w, event, prms, nprms)
6413 StopExaminingEvent();
6416 void UploadProc(w, event, prms, nprms)
6426 void ForwardProc(w, event, prms, nprms)
6436 void BackwardProc(w, event, prms, nprms)
6445 void ToStartProc(w, event, prms, nprms)
6454 void ToEndProc(w, event, prms, nprms)
6463 void RevertProc(w, event, prms, nprms)
6472 void AnnotateProc(w, event, prms, nprms)
6481 void TruncateGameProc(w, event, prms, nprms)
6487 TruncateGameEvent();
6489 void RetractMoveProc(w, event, prms, nprms)
6498 void MoveNowProc(w, event, prms, nprms)
6508 void AlwaysQueenProc(w, event, prms, nprms)
6516 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6518 if (appData.alwaysPromoteToQueen) {
6519 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6521 XtSetArg(args[0], XtNleftBitmap, None);
6523 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6527 void AnimateDraggingProc(w, event, prms, nprms)
6535 appData.animateDragging = !appData.animateDragging;
6537 if (appData.animateDragging) {
6538 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6541 XtSetArg(args[0], XtNleftBitmap, None);
6543 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6547 void AnimateMovingProc(w, event, prms, nprms)
6555 appData.animate = !appData.animate;
6557 if (appData.animate) {
6558 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6561 XtSetArg(args[0], XtNleftBitmap, None);
6563 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6567 void AutoflagProc(w, event, prms, nprms)
6575 appData.autoCallFlag = !appData.autoCallFlag;
6577 if (appData.autoCallFlag) {
6578 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6580 XtSetArg(args[0], XtNleftBitmap, None);
6582 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6586 void AutoflipProc(w, event, prms, nprms)
6594 appData.autoFlipView = !appData.autoFlipView;
6596 if (appData.autoFlipView) {
6597 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6599 XtSetArg(args[0], XtNleftBitmap, None);
6601 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6605 void BlindfoldProc(w, event, prms, nprms)
6613 appData.blindfold = !appData.blindfold;
6615 if (appData.blindfold) {
6616 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6618 XtSetArg(args[0], XtNleftBitmap, None);
6620 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6623 DrawPosition(True, NULL);
6626 void TestLegalityProc(w, event, prms, nprms)
6634 appData.testLegality = !appData.testLegality;
6636 if (appData.testLegality) {
6637 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6639 XtSetArg(args[0], XtNleftBitmap, None);
6641 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6646 void FlashMovesProc(w, event, prms, nprms)
6654 if (appData.flashCount == 0) {
6655 appData.flashCount = 3;
6657 appData.flashCount = -appData.flashCount;
6660 if (appData.flashCount > 0) {
6661 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6663 XtSetArg(args[0], XtNleftBitmap, None);
6665 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6669 void FlipViewProc(w, event, prms, nprms)
6675 flipView = !flipView;
6676 DrawPosition(True, NULL);
6680 void HighlightDraggingProc(w, event, prms, nprms)
6688 appData.highlightDragging = !appData.highlightDragging;
6690 if (appData.highlightDragging) {
6691 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6693 XtSetArg(args[0], XtNleftBitmap, None);
6695 XtSetValues(XtNameToWidget(menuBarWidget,
6696 "menuOptions.Highlight Dragging"), args, 1);
6700 void HighlightLastMoveProc(w, event, prms, nprms)
6708 appData.highlightLastMove = !appData.highlightLastMove;
6710 if (appData.highlightLastMove) {
6711 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6713 XtSetArg(args[0], XtNleftBitmap, None);
6715 XtSetValues(XtNameToWidget(menuBarWidget,
6716 "menuOptions.Highlight Last Move"), args, 1);
6719 void HighlightArrowProc(w, event, prms, nprms)
6727 appData.highlightMoveWithArrow = !appData.highlightMoveWithArrow;
6729 if (appData.highlightMoveWithArrow) {
6730 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6732 XtSetArg(args[0], XtNleftBitmap, None);
6734 XtSetValues(XtNameToWidget(menuBarWidget,
6735 "menuOptions.Arrow"), args, 1);
6739 void IcsAlarmProc(w, event, prms, nprms)
6747 appData.icsAlarm = !appData.icsAlarm;
6749 if (appData.icsAlarm) {
6750 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6752 XtSetArg(args[0], XtNleftBitmap, None);
6754 XtSetValues(XtNameToWidget(menuBarWidget,
6755 "menuOptions.ICS Alarm"), args, 1);
6759 void MoveSoundProc(w, event, prms, nprms)
6767 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6769 if (appData.ringBellAfterMoves) {
6770 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6772 XtSetArg(args[0], XtNleftBitmap, None);
6774 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6778 void OneClickProc(w, event, prms, nprms)
6786 appData.oneClick = !appData.oneClick;
6788 if (appData.oneClick) {
6789 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6791 XtSetArg(args[0], XtNleftBitmap, None);
6793 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.OneClick"),
6797 void PeriodicUpdatesProc(w, event, prms, nprms)
6805 PeriodicUpdatesEvent(!appData.periodicUpdates);
6807 if (appData.periodicUpdates) {
6808 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6810 XtSetArg(args[0], XtNleftBitmap, None);
6812 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6816 void PonderNextMoveProc(w, event, prms, nprms)
6824 PonderNextMoveEvent(!appData.ponderNextMove);
6826 if (appData.ponderNextMove) {
6827 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6829 XtSetArg(args[0], XtNleftBitmap, None);
6831 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6835 void PopupExitMessageProc(w, event, prms, nprms)
6843 appData.popupExitMessage = !appData.popupExitMessage;
6845 if (appData.popupExitMessage) {
6846 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6848 XtSetArg(args[0], XtNleftBitmap, None);
6850 XtSetValues(XtNameToWidget(menuBarWidget,
6851 "menuOptions.Popup Exit Message"), args, 1);
6854 void PopupMoveErrorsProc(w, event, prms, nprms)
6862 appData.popupMoveErrors = !appData.popupMoveErrors;
6864 if (appData.popupMoveErrors) {
6865 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6867 XtSetArg(args[0], XtNleftBitmap, None);
6869 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6874 void PremoveProc(w, event, prms, nprms)
6882 appData.premove = !appData.premove;
6884 if (appData.premove) {
6885 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6887 XtSetArg(args[0], XtNleftBitmap, None);
6889 XtSetValues(XtNameToWidget(menuBarWidget,
6890 "menuOptions.Premove"), args, 1);
6894 void ShowCoordsProc(w, event, prms, nprms)
6902 appData.showCoords = !appData.showCoords;
6904 if (appData.showCoords) {
6905 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6907 XtSetArg(args[0], XtNleftBitmap, None);
6909 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6912 DrawPosition(True, NULL);
6915 void ShowThinkingProc(w, event, prms, nprms)
6921 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6922 ShowThinkingEvent();
6925 void HideThinkingProc(w, event, prms, nprms)
6933 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6934 ShowThinkingEvent();
6936 if (appData.hideThinkingFromHuman) {
6937 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6939 XtSetArg(args[0], XtNleftBitmap, None);
6941 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6945 void SaveOnExitProc(w, event, prms, nprms)
6953 saveSettingsOnExit = !saveSettingsOnExit;
6955 if (saveSettingsOnExit) {
6956 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6958 XtSetArg(args[0], XtNleftBitmap, None);
6960 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6964 void SaveSettingsProc(w, event, prms, nprms)
6970 SaveSettings(settingsFileName);
6973 void InfoProc(w, event, prms, nprms)
6980 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6985 void ManProc(w, event, prms, nprms)
6993 if (nprms && *nprms > 0)
6997 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
7001 void HintProc(w, event, prms, nprms)
7010 void BookProc(w, event, prms, nprms)
7019 void AboutProc(w, event, prms, nprms)
7027 char *zippy = " (with Zippy code)";
7031 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
7032 programVersion, zippy,
7033 "Copyright 1991 Digital Equipment Corporation",
7034 "Enhancements Copyright 1992-2009 Free Software Foundation",
7035 "Enhancements Copyright 2005 Alessandro Scotti",
7036 PACKAGE, " is free software and carries NO WARRANTY;",
7037 "see the file COPYING for more information.");
7038 ErrorPopUp(_("About XBoard"), buf, FALSE);
7041 void DebugProc(w, event, prms, nprms)
7047 appData.debugMode = !appData.debugMode;
7050 void AboutGameProc(w, event, prms, nprms)
7059 void NothingProc(w, event, prms, nprms)
7068 void Iconify(w, event, prms, nprms)
7077 XtSetArg(args[0], XtNiconic, True);
7078 XtSetValues(shellWidget, args, 1);
7081 void DisplayMessage(message, extMessage)
7082 char *message, *extMessage;
7084 /* display a message in the message widget */
7093 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
7098 message = extMessage;
7102 /* need to test if messageWidget already exists, since this function
7103 can also be called during the startup, if for example a Xresource
7104 is not set up correctly */
7107 XtSetArg(arg, XtNlabel, message);
7108 XtSetValues(messageWidget, &arg, 1);
7114 void DisplayTitle(text)
7119 char title[MSG_SIZ];
7122 if (text == NULL) text = "";
7124 if (appData.titleInWindow) {
7126 XtSetArg(args[i], XtNlabel, text); i++;
7127 XtSetValues(titleWidget, args, i);
7130 if (*text != NULLCHAR) {
7131 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
7132 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
7133 } else if (appData.icsActive) {
7134 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7135 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7136 } else if (appData.cmailGameName[0] != NULLCHAR) {
7137 snprintf(icon, sizeof(icon), "%s", "CMail");
7138 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7140 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7141 } else if (gameInfo.variant == VariantGothic) {
7142 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7143 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
7146 } else if (gameInfo.variant == VariantFalcon) {
7147 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7148 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
7150 } else if (appData.noChessProgram) {
7151 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7152 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
7154 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
7155 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7158 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7159 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7160 XtSetValues(shellWidget, args, i);
7165 DisplayError(message, error)
7172 if (appData.debugMode || appData.matchMode) {
7173 fprintf(stderr, "%s: %s\n", programName, message);
7176 if (appData.debugMode || appData.matchMode) {
7177 fprintf(stderr, "%s: %s: %s\n",
7178 programName, message, strerror(error));
7180 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7183 ErrorPopUp(_("Error"), message, FALSE);
7187 void DisplayMoveError(message)
7192 DrawPosition(FALSE, NULL);
7193 if (appData.debugMode || appData.matchMode) {
7194 fprintf(stderr, "%s: %s\n", programName, message);
7196 if (appData.popupMoveErrors) {
7197 ErrorPopUp(_("Error"), message, FALSE);
7199 DisplayMessage(message, "");
7204 void DisplayFatalError(message, error, status)
7210 errorExitStatus = status;
7212 fprintf(stderr, "%s: %s\n", programName, message);
7214 fprintf(stderr, "%s: %s: %s\n",
7215 programName, message, strerror(error));
7216 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7219 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7220 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7226 void DisplayInformation(message)
7230 ErrorPopUp(_("Information"), message, TRUE);
7233 void DisplayNote(message)
7237 ErrorPopUp(_("Note"), message, FALSE);
7241 NullXErrorCheck(dpy, error_event)
7243 XErrorEvent *error_event;
7248 void DisplayIcsInteractionTitle(message)
7251 if (oldICSInteractionTitle == NULL) {
7252 /* Magic to find the old window title, adapted from vim */
7253 char *wina = getenv("WINDOWID");
7255 Window win = (Window) atoi(wina);
7256 Window root, parent, *children;
7257 unsigned int nchildren;
7258 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7260 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7261 if (!XQueryTree(xDisplay, win, &root, &parent,
7262 &children, &nchildren)) break;
7263 if (children) XFree((void *)children);
7264 if (parent == root || parent == 0) break;
7267 XSetErrorHandler(oldHandler);
7269 if (oldICSInteractionTitle == NULL) {
7270 oldICSInteractionTitle = "xterm";
7273 printf("\033]0;%s\007", message);
7277 char pendingReplyPrefix[MSG_SIZ];
7278 ProcRef pendingReplyPR;
7280 void AskQuestionProc(w, event, prms, nprms)
7287 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7291 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7294 void AskQuestionPopDown()
7296 if (!askQuestionUp) return;
7297 XtPopdown(askQuestionShell);
7298 XtDestroyWidget(askQuestionShell);
7299 askQuestionUp = False;
7302 void AskQuestionReplyAction(w, event, prms, nprms)
7312 reply = XawDialogGetValueString(w = XtParent(w));
7313 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
7314 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
7315 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
7316 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
7317 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7318 AskQuestionPopDown();
7320 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7323 void AskQuestionCallback(w, client_data, call_data)
7325 XtPointer client_data, call_data;
7330 XtSetArg(args[0], XtNlabel, &name);
7331 XtGetValues(w, args, 1);
7333 if (strcmp(name, _("cancel")) == 0) {
7334 AskQuestionPopDown();
7336 AskQuestionReplyAction(w, NULL, NULL, NULL);
7340 void AskQuestion(title, question, replyPrefix, pr)
7341 char *title, *question, *replyPrefix;
7345 Widget popup, layout, dialog, edit;
7351 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
7352 pendingReplyPR = pr;
7355 XtSetArg(args[i], XtNresizable, True); i++;
7356 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7357 askQuestionShell = popup =
7358 XtCreatePopupShell(title, transientShellWidgetClass,
7359 shellWidget, args, i);
7362 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7363 layoutArgs, XtNumber(layoutArgs));
7366 XtSetArg(args[i], XtNlabel, question); i++;
7367 XtSetArg(args[i], XtNvalue, ""); i++;
7368 XtSetArg(args[i], XtNborderWidth, 0); i++;
7369 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7372 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7373 (XtPointer) dialog);
7374 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7375 (XtPointer) dialog);
7377 XtRealizeWidget(popup);
7378 CatchDeleteWindow(popup, "AskQuestionPopDown");
7380 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7381 &x, &y, &win_x, &win_y, &mask);
7383 XtSetArg(args[0], XtNx, x - 10);
7384 XtSetArg(args[1], XtNy, y - 30);
7385 XtSetValues(popup, args, 2);
7387 XtPopup(popup, XtGrabExclusive);
7388 askQuestionUp = True;
7390 edit = XtNameToWidget(dialog, "*value");
7391 XtSetKeyboardFocus(popup, edit);
7399 if (*name == NULLCHAR) {
7401 } else if (strcmp(name, "$") == 0) {
7402 putc(BELLCHAR, stderr);
7405 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7413 PlaySound(appData.soundMove);
7419 PlaySound(appData.soundIcsWin);
7425 PlaySound(appData.soundIcsLoss);
7431 PlaySound(appData.soundIcsDraw);
7435 PlayIcsUnfinishedSound()
7437 PlaySound(appData.soundIcsUnfinished);
7443 PlaySound(appData.soundIcsAlarm);
7449 system("stty echo");
7455 system("stty -echo");
7459 Colorize(cc, continuation)
7464 int count, outCount, error;
7466 if (textColors[(int)cc].bg > 0) {
7467 if (textColors[(int)cc].fg > 0) {
7468 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7469 textColors[(int)cc].fg, textColors[(int)cc].bg);
7471 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7472 textColors[(int)cc].bg);
7475 if (textColors[(int)cc].fg > 0) {
7476 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7477 textColors[(int)cc].fg);
7479 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7482 count = strlen(buf);
7483 outCount = OutputToProcess(NoProc, buf, count, &error);
7484 if (outCount < count) {
7485 DisplayFatalError(_("Error writing to display"), error, 1);
7488 if (continuation) return;
7491 PlaySound(appData.soundShout);
7494 PlaySound(appData.soundSShout);
7497 PlaySound(appData.soundChannel1);
7500 PlaySound(appData.soundChannel);
7503 PlaySound(appData.soundKibitz);
7506 PlaySound(appData.soundTell);
7508 case ColorChallenge:
7509 PlaySound(appData.soundChallenge);
7512 PlaySound(appData.soundRequest);
7515 PlaySound(appData.soundSeek);
7526 return getpwuid(getuid())->pw_name;
7530 ExpandPathName(path)
7533 static char static_buf[4*MSG_SIZ];
7534 char *d, *s, buf[4*MSG_SIZ];
7540 while (*s && isspace(*s))
7549 if (*(s+1) == '/') {
7550 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7554 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7555 { char *p; if(p = strchr(buf, '/')) *p = 0; }
7556 pwd = getpwnam(buf);
7559 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7563 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7564 strcat(d, strchr(s+1, '/'));
7568 safeStrCpy(d, s, 4*MSG_SIZ );
7575 static char host_name[MSG_SIZ];
7577 #if HAVE_GETHOSTNAME
7578 gethostname(host_name, MSG_SIZ);
7580 #else /* not HAVE_GETHOSTNAME */
7581 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7582 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7584 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7586 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7587 #endif /* not HAVE_GETHOSTNAME */
7590 XtIntervalId delayedEventTimerXID = 0;
7591 DelayedEventCallback delayedEventCallback = 0;
7596 delayedEventTimerXID = 0;
7597 delayedEventCallback();
7601 ScheduleDelayedEvent(cb, millisec)
7602 DelayedEventCallback cb; long millisec;
7604 if(delayedEventTimerXID && delayedEventCallback == cb)
7605 // [HGM] alive: replace, rather than add or flush identical event
7606 XtRemoveTimeOut(delayedEventTimerXID);
7607 delayedEventCallback = cb;
7608 delayedEventTimerXID =
7609 XtAppAddTimeOut(appContext, millisec,
7610 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7613 DelayedEventCallback
7616 if (delayedEventTimerXID) {
7617 return delayedEventCallback;
7624 CancelDelayedEvent()
7626 if (delayedEventTimerXID) {
7627 XtRemoveTimeOut(delayedEventTimerXID);
7628 delayedEventTimerXID = 0;
7632 XtIntervalId loadGameTimerXID = 0;
7634 int LoadGameTimerRunning()
7636 return loadGameTimerXID != 0;
7639 int StopLoadGameTimer()
7641 if (loadGameTimerXID != 0) {
7642 XtRemoveTimeOut(loadGameTimerXID);
7643 loadGameTimerXID = 0;
7651 LoadGameTimerCallback(arg, id)
7655 loadGameTimerXID = 0;
7660 StartLoadGameTimer(millisec)
7664 XtAppAddTimeOut(appContext, millisec,
7665 (XtTimerCallbackProc) LoadGameTimerCallback,
7669 XtIntervalId analysisClockXID = 0;
7672 AnalysisClockCallback(arg, id)
7676 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7677 || appData.icsEngineAnalyze) { // [DM]
7678 AnalysisPeriodicEvent(0);
7679 StartAnalysisClock();
7684 StartAnalysisClock()
7687 XtAppAddTimeOut(appContext, 2000,
7688 (XtTimerCallbackProc) AnalysisClockCallback,
7692 XtIntervalId clockTimerXID = 0;
7694 int ClockTimerRunning()
7696 return clockTimerXID != 0;
7699 int StopClockTimer()
7701 if (clockTimerXID != 0) {
7702 XtRemoveTimeOut(clockTimerXID);
7711 ClockTimerCallback(arg, id)
7720 StartClockTimer(millisec)
7724 XtAppAddTimeOut(appContext, millisec,
7725 (XtTimerCallbackProc) ClockTimerCallback,
7730 DisplayTimerLabel(w, color, timer, highlight)
7739 /* check for low time warning */
7740 Pixel foregroundOrWarningColor = timerForegroundPixel;
7743 appData.lowTimeWarning &&
7744 (timer / 1000) < appData.icsAlarmTime)
7745 foregroundOrWarningColor = lowTimeWarningColor;
7747 if (appData.clockMode) {
7748 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7749 XtSetArg(args[0], XtNlabel, buf);
7751 snprintf(buf, MSG_SIZ, "%s ", color);
7752 XtSetArg(args[0], XtNlabel, buf);
7757 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7758 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7760 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7761 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7764 XtSetValues(w, args, 3);
7768 DisplayWhiteClock(timeRemaining, highlight)
7774 if(appData.noGUI) return;
7775 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7776 if (highlight && iconPixmap == bIconPixmap) {
7777 iconPixmap = wIconPixmap;
7778 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7779 XtSetValues(shellWidget, args, 1);
7784 DisplayBlackClock(timeRemaining, highlight)
7790 if(appData.noGUI) return;
7791 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7792 if (highlight && iconPixmap == wIconPixmap) {
7793 iconPixmap = bIconPixmap;
7794 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7795 XtSetValues(shellWidget, args, 1);
7813 int StartChildProcess(cmdLine, dir, pr)
7820 int to_prog[2], from_prog[2];
7824 if (appData.debugMode) {
7825 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7828 /* We do NOT feed the cmdLine to the shell; we just
7829 parse it into blank-separated arguments in the
7830 most simple-minded way possible.
7833 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7836 while(*p == ' ') p++;
7838 if(*p == '"' || *p == '\'')
7839 p = strchr(++argv[i-1], *p);
7840 else p = strchr(p, ' ');
7841 if (p == NULL) break;
7846 SetUpChildIO(to_prog, from_prog);
7848 if ((pid = fork()) == 0) {
7850 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7851 close(to_prog[1]); // first close the unused pipe ends
7852 close(from_prog[0]);
7853 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7854 dup2(from_prog[1], 1);
7855 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7856 close(from_prog[1]); // and closing again loses one of the pipes!
7857 if(fileno(stderr) >= 2) // better safe than sorry...
7858 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7860 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7865 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7867 execvp(argv[0], argv);
7869 /* If we get here, exec failed */
7874 /* Parent process */
7876 close(from_prog[1]);
7878 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7881 cp->fdFrom = from_prog[0];
7882 cp->fdTo = to_prog[1];
7887 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7888 static RETSIGTYPE AlarmCallBack(int n)
7894 DestroyChildProcess(pr, signalType)
7898 ChildProc *cp = (ChildProc *) pr;
7900 if (cp->kind != CPReal) return;
7902 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7903 signal(SIGALRM, AlarmCallBack);
7905 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7906 kill(cp->pid, SIGKILL); // kill it forcefully
7907 wait((int *) 0); // and wait again
7911 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7913 /* Process is exiting either because of the kill or because of
7914 a quit command sent by the backend; either way, wait for it to die.
7923 InterruptChildProcess(pr)
7926 ChildProc *cp = (ChildProc *) pr;
7928 if (cp->kind != CPReal) return;
7929 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7932 int OpenTelnet(host, port, pr)
7937 char cmdLine[MSG_SIZ];
7939 if (port[0] == NULLCHAR) {
7940 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7942 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7944 return StartChildProcess(cmdLine, "", pr);
7947 int OpenTCP(host, port, pr)
7953 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7954 #else /* !OMIT_SOCKETS */
7956 struct sockaddr_in sa;
7958 unsigned short uport;
7961 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7965 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7966 sa.sin_family = AF_INET;
7967 sa.sin_addr.s_addr = INADDR_ANY;
7968 uport = (unsigned short) 0;
7969 sa.sin_port = htons(uport);
7970 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7974 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7975 if (!(hp = gethostbyname(host))) {
7977 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7978 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7979 hp->h_addrtype = AF_INET;
7981 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7982 hp->h_addr_list[0] = (char *) malloc(4);
7983 hp->h_addr_list[0][0] = b0;
7984 hp->h_addr_list[0][1] = b1;
7985 hp->h_addr_list[0][2] = b2;
7986 hp->h_addr_list[0][3] = b3;
7991 sa.sin_family = hp->h_addrtype;
7992 uport = (unsigned short) atoi(port);
7993 sa.sin_port = htons(uport);
7994 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7996 if (connect(s, (struct sockaddr *) &sa,
7997 sizeof(struct sockaddr_in)) < 0) {
8001 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8008 #endif /* !OMIT_SOCKETS */
8013 int OpenCommPort(name, pr)
8020 fd = open(name, 2, 0);
8021 if (fd < 0) return errno;
8023 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8033 int OpenLoopback(pr)
8039 SetUpChildIO(to, from);
8041 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8044 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
8051 int OpenRcmd(host, user, cmd, pr)
8052 char *host, *user, *cmd;
8055 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
8059 #define INPUT_SOURCE_BUF_SIZE 8192
8068 char buf[INPUT_SOURCE_BUF_SIZE];
8073 DoInputCallback(closure, source, xid)
8078 InputSource *is = (InputSource *) closure;
8083 if (is->lineByLine) {
8084 count = read(is->fd, is->unused,
8085 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
8087 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
8090 is->unused += count;
8092 while (p < is->unused) {
8093 q = memchr(p, '\n', is->unused - p);
8094 if (q == NULL) break;
8096 (is->func)(is, is->closure, p, q - p, 0);
8100 while (p < is->unused) {
8105 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8110 (is->func)(is, is->closure, is->buf, count, error);
8114 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8121 ChildProc *cp = (ChildProc *) pr;
8123 is = (InputSource *) calloc(1, sizeof(InputSource));
8124 is->lineByLine = lineByLine;
8128 is->fd = fileno(stdin);
8130 is->kind = cp->kind;
8131 is->fd = cp->fdFrom;
8134 is->unused = is->buf;
8137 is->xid = XtAppAddInput(appContext, is->fd,
8138 (XtPointer) (XtInputReadMask),
8139 (XtInputCallbackProc) DoInputCallback,
8141 is->closure = closure;
8142 return (InputSourceRef) is;
8146 RemoveInputSource(isr)
8149 InputSource *is = (InputSource *) isr;
8151 if (is->xid == 0) return;
8152 XtRemoveInput(is->xid);
8156 int OutputToProcess(pr, message, count, outError)
8162 static int line = 0;
8163 ChildProc *cp = (ChildProc *) pr;
8168 if (appData.noJoin || !appData.useInternalWrap)
8169 outCount = fwrite(message, 1, count, stdout);
8172 int width = get_term_width();
8173 int len = wrap(NULL, message, count, width, &line);
8174 char *msg = malloc(len);
8178 outCount = fwrite(message, 1, count, stdout);
8181 dbgchk = wrap(msg, message, count, width, &line);
8182 if (dbgchk != len && appData.debugMode)
8183 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8184 outCount = fwrite(msg, 1, dbgchk, stdout);
8190 outCount = write(cp->fdTo, message, count);
8200 /* Output message to process, with "ms" milliseconds of delay
8201 between each character. This is needed when sending the logon
8202 script to ICC, which for some reason doesn't like the
8203 instantaneous send. */
8204 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8211 ChildProc *cp = (ChildProc *) pr;
8216 r = write(cp->fdTo, message++, 1);
8229 /**** Animation code by Hugh Fisher, DCS, ANU.
8231 Known problem: if a window overlapping the board is
8232 moved away while a piece is being animated underneath,
8233 the newly exposed area won't be updated properly.
8234 I can live with this.
8236 Known problem: if you look carefully at the animation
8237 of pieces in mono mode, they are being drawn as solid
8238 shapes without interior detail while moving. Fixing
8239 this would be a major complication for minimal return.
8242 /* Masks for XPM pieces. Black and white pieces can have
8243 different shapes, but in the interest of retaining my
8244 sanity pieces must have the same outline on both light
8245 and dark squares, and all pieces must use the same
8246 background square colors/images. */
8248 static int xpmDone = 0;
8251 CreateAnimMasks (pieceDepth)
8258 unsigned long plane;
8261 /* Need a bitmap just to get a GC with right depth */
8262 buf = XCreatePixmap(xDisplay, xBoardWindow,
8264 values.foreground = 1;
8265 values.background = 0;
8266 /* Don't use XtGetGC, not read only */
8267 maskGC = XCreateGC(xDisplay, buf,
8268 GCForeground | GCBackground, &values);
8269 XFreePixmap(xDisplay, buf);
8271 buf = XCreatePixmap(xDisplay, xBoardWindow,
8272 squareSize, squareSize, pieceDepth);
8273 values.foreground = XBlackPixel(xDisplay, xScreen);
8274 values.background = XWhitePixel(xDisplay, xScreen);
8275 bufGC = XCreateGC(xDisplay, buf,
8276 GCForeground | GCBackground, &values);
8278 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8279 /* Begin with empty mask */
8280 if(!xpmDone) // [HGM] pieces: keep using existing
8281 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8282 squareSize, squareSize, 1);
8283 XSetFunction(xDisplay, maskGC, GXclear);
8284 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8285 0, 0, squareSize, squareSize);
8287 /* Take a copy of the piece */
8292 XSetFunction(xDisplay, bufGC, GXcopy);
8293 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8295 0, 0, squareSize, squareSize, 0, 0);
8297 /* XOR the background (light) over the piece */
8298 XSetFunction(xDisplay, bufGC, GXxor);
8300 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8301 0, 0, squareSize, squareSize, 0, 0);
8303 XSetForeground(xDisplay, bufGC, lightSquareColor);
8304 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8307 /* We now have an inverted piece image with the background
8308 erased. Construct mask by just selecting all the non-zero
8309 pixels - no need to reconstruct the original image. */
8310 XSetFunction(xDisplay, maskGC, GXor);
8312 /* Might be quicker to download an XImage and create bitmap
8313 data from it rather than this N copies per piece, but it
8314 only takes a fraction of a second and there is a much
8315 longer delay for loading the pieces. */
8316 for (n = 0; n < pieceDepth; n ++) {
8317 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8318 0, 0, squareSize, squareSize,
8324 XFreePixmap(xDisplay, buf);
8325 XFreeGC(xDisplay, bufGC);
8326 XFreeGC(xDisplay, maskGC);
8330 InitAnimState (anim, info)
8332 XWindowAttributes * info;
8337 /* Each buffer is square size, same depth as window */
8338 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8339 squareSize, squareSize, info->depth);
8340 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8341 squareSize, squareSize, info->depth);
8343 /* Create a plain GC for blitting */
8344 mask = GCForeground | GCBackground | GCFunction |
8345 GCPlaneMask | GCGraphicsExposures;
8346 values.foreground = XBlackPixel(xDisplay, xScreen);
8347 values.background = XWhitePixel(xDisplay, xScreen);
8348 values.function = GXcopy;
8349 values.plane_mask = AllPlanes;
8350 values.graphics_exposures = False;
8351 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8353 /* Piece will be copied from an existing context at
8354 the start of each new animation/drag. */
8355 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8357 /* Outline will be a read-only copy of an existing */
8358 anim->outlineGC = None;
8364 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8365 XWindowAttributes info;
8367 if (xpmDone && gameInfo.variant == old) return;
8368 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8369 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8371 InitAnimState(&game, &info);
8372 InitAnimState(&player, &info);
8374 /* For XPM pieces, we need bitmaps to use as masks. */
8376 CreateAnimMasks(info.depth);
8382 static Boolean frameWaiting;
8384 static RETSIGTYPE FrameAlarm (sig)
8387 frameWaiting = False;
8388 /* In case System-V style signals. Needed?? */
8389 signal(SIGALRM, FrameAlarm);
8396 struct itimerval delay;
8398 XSync(xDisplay, False);
8401 frameWaiting = True;
8402 signal(SIGALRM, FrameAlarm);
8403 delay.it_interval.tv_sec =
8404 delay.it_value.tv_sec = time / 1000;
8405 delay.it_interval.tv_usec =
8406 delay.it_value.tv_usec = (time % 1000) * 1000;
8407 setitimer(ITIMER_REAL, &delay, NULL);
8408 while (frameWaiting) pause();
8409 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8410 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8411 setitimer(ITIMER_REAL, &delay, NULL);
8421 XSync(xDisplay, False);
8423 usleep(time * 1000);
8428 /* Convert board position to corner of screen rect and color */
8431 ScreenSquare(column, row, pt, color)
8432 int column; int row; XPoint * pt; int * color;
8435 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8436 pt->y = lineGap + row * (squareSize + lineGap);
8438 pt->x = lineGap + column * (squareSize + lineGap);
8439 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8441 *color = SquareColor(row, column);
8444 /* Convert window coords to square */
8447 BoardSquare(x, y, column, row)
8448 int x; int y; int * column; int * row;
8450 *column = EventToSquare(x, BOARD_WIDTH);
8451 if (flipView && *column >= 0)
8452 *column = BOARD_WIDTH - 1 - *column;
8453 *row = EventToSquare(y, BOARD_HEIGHT);
8454 if (!flipView && *row >= 0)
8455 *row = BOARD_HEIGHT - 1 - *row;
8460 #undef Max /* just in case */
8462 #define Max(a, b) ((a) > (b) ? (a) : (b))
8463 #define Min(a, b) ((a) < (b) ? (a) : (b))
8466 SetRect(rect, x, y, width, height)
8467 XRectangle * rect; int x; int y; int width; int height;
8471 rect->width = width;
8472 rect->height = height;
8475 /* Test if two frames overlap. If they do, return
8476 intersection rect within old and location of
8477 that rect within new. */
8480 Intersect(old, new, size, area, pt)
8481 XPoint * old; XPoint * new;
8482 int size; XRectangle * area; XPoint * pt;
8484 if (old->x > new->x + size || new->x > old->x + size ||
8485 old->y > new->y + size || new->y > old->y + size) {
8488 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8489 size - abs(old->x - new->x), size - abs(old->y - new->y));
8490 pt->x = Max(old->x - new->x, 0);
8491 pt->y = Max(old->y - new->y, 0);
8496 /* For two overlapping frames, return the rect(s)
8497 in the old that do not intersect with the new. */
8500 CalcUpdateRects(old, new, size, update, nUpdates)
8501 XPoint * old; XPoint * new; int size;
8502 XRectangle update[]; int * nUpdates;
8506 /* If old = new (shouldn't happen) then nothing to draw */
8507 if (old->x == new->x && old->y == new->y) {
8511 /* Work out what bits overlap. Since we know the rects
8512 are the same size we don't need a full intersect calc. */
8514 /* Top or bottom edge? */
8515 if (new->y > old->y) {
8516 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8518 } else if (old->y > new->y) {
8519 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8520 size, old->y - new->y);
8523 /* Left or right edge - don't overlap any update calculated above. */
8524 if (new->x > old->x) {
8525 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8526 new->x - old->x, size - abs(new->y - old->y));
8528 } else if (old->x > new->x) {
8529 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8530 old->x - new->x, size - abs(new->y - old->y));
8537 /* Generate a series of frame coords from start->mid->finish.
8538 The movement rate doubles until the half way point is
8539 reached, then halves back down to the final destination,
8540 which gives a nice slow in/out effect. The algorithmn
8541 may seem to generate too many intermediates for short
8542 moves, but remember that the purpose is to attract the
8543 viewers attention to the piece about to be moved and
8544 then to where it ends up. Too few frames would be less
8548 Tween(start, mid, finish, factor, frames, nFrames)
8549 XPoint * start; XPoint * mid;
8550 XPoint * finish; int factor;
8551 XPoint frames[]; int * nFrames;
8553 int fraction, n, count;
8557 /* Slow in, stepping 1/16th, then 1/8th, ... */
8559 for (n = 0; n < factor; n++)
8561 for (n = 0; n < factor; n++) {
8562 frames[count].x = start->x + (mid->x - start->x) / fraction;
8563 frames[count].y = start->y + (mid->y - start->y) / fraction;
8565 fraction = fraction / 2;
8569 frames[count] = *mid;
8572 /* Slow out, stepping 1/2, then 1/4, ... */
8574 for (n = 0; n < factor; n++) {
8575 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8576 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8578 fraction = fraction * 2;
8583 /* Draw a piece on the screen without disturbing what's there */
8586 SelectGCMask(piece, clip, outline, mask)
8587 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8591 /* Bitmap for piece being moved. */
8592 if (appData.monoMode) {
8593 *mask = *pieceToSolid(piece);
8594 } else if (useImages) {
8596 *mask = xpmMask[piece];
8598 *mask = ximMaskPm[piece];
8601 *mask = *pieceToSolid(piece);
8604 /* GC for piece being moved. Square color doesn't matter, but
8605 since it gets modified we make a copy of the original. */
8607 if (appData.monoMode)
8612 if (appData.monoMode)
8617 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8619 /* Outline only used in mono mode and is not modified */
8621 *outline = bwPieceGC;
8623 *outline = wbPieceGC;
8627 OverlayPiece(piece, clip, outline, dest)
8628 ChessSquare piece; GC clip; GC outline; Drawable dest;
8633 /* Draw solid rectangle which will be clipped to shape of piece */
8634 XFillRectangle(xDisplay, dest, clip,
8635 0, 0, squareSize, squareSize);
8636 if (appData.monoMode)
8637 /* Also draw outline in contrasting color for black
8638 on black / white on white cases */
8639 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8640 0, 0, squareSize, squareSize, 0, 0, 1);
8642 /* Copy the piece */
8647 if(appData.upsideDown && flipView) kind ^= 2;
8648 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8650 0, 0, squareSize, squareSize,
8655 /* Animate the movement of a single piece */
8658 BeginAnimation(anim, piece, startColor, start)
8666 if(appData.upsideDown && flipView) piece += piece < BlackPawn ? BlackPawn : -BlackPawn;
8667 /* The old buffer is initialised with the start square (empty) */
8668 BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0);
8669 anim->prevFrame = *start;
8671 /* The piece will be drawn using its own bitmap as a matte */
8672 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8673 XSetClipMask(xDisplay, anim->pieceGC, mask);
8677 AnimationFrame(anim, frame, piece)
8682 XRectangle updates[4];
8687 /* Save what we are about to draw into the new buffer */
8688 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8689 frame->x, frame->y, squareSize, squareSize,
8692 /* Erase bits of the previous frame */
8693 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8694 /* Where the new frame overlapped the previous,
8695 the contents in newBuf are wrong. */
8696 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8697 overlap.x, overlap.y,
8698 overlap.width, overlap.height,
8700 /* Repaint the areas in the old that don't overlap new */
8701 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8702 for (i = 0; i < count; i++)
8703 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8704 updates[i].x - anim->prevFrame.x,
8705 updates[i].y - anim->prevFrame.y,
8706 updates[i].width, updates[i].height,
8707 updates[i].x, updates[i].y);
8709 /* Easy when no overlap */
8710 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8711 0, 0, squareSize, squareSize,
8712 anim->prevFrame.x, anim->prevFrame.y);
8715 /* Save this frame for next time round */
8716 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8717 0, 0, squareSize, squareSize,
8719 anim->prevFrame = *frame;
8721 /* Draw piece over original screen contents, not current,
8722 and copy entire rect. Wipes out overlapping piece images. */
8723 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8724 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8725 0, 0, squareSize, squareSize,
8726 frame->x, frame->y);
8730 EndAnimation (anim, finish)
8734 XRectangle updates[4];
8739 /* The main code will redraw the final square, so we
8740 only need to erase the bits that don't overlap. */
8741 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8742 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8743 for (i = 0; i < count; i++)
8744 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8745 updates[i].x - anim->prevFrame.x,
8746 updates[i].y - anim->prevFrame.y,
8747 updates[i].width, updates[i].height,
8748 updates[i].x, updates[i].y);
8750 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8751 0, 0, squareSize, squareSize,
8752 anim->prevFrame.x, anim->prevFrame.y);
8757 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8759 ChessSquare piece; int startColor;
8760 XPoint * start; XPoint * finish;
8761 XPoint frames[]; int nFrames;
8765 BeginAnimation(anim, piece, startColor, start);
8766 for (n = 0; n < nFrames; n++) {
8767 AnimationFrame(anim, &(frames[n]), piece);
8768 FrameDelay(appData.animSpeed);
8770 EndAnimation(anim, finish);
8774 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
8777 ChessSquare piece = board[fromY][toY];
8778 board[fromY][toY] = EmptySquare;
8779 DrawPosition(FALSE, board);
8781 x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap);
8782 y = lineGap + toY * (squareSize + lineGap);
8784 x = lineGap + toX * (squareSize + lineGap);
8785 y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap);
8787 for(i=1; i<4*kFactor; i++) {
8788 int r = squareSize * 9 * i/(20*kFactor - 5);
8789 XFillArc(xDisplay, xBoardWindow, highlineGC,
8790 x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360);
8791 FrameDelay(appData.animSpeed);
8793 board[fromY][toY] = piece;
8796 /* Main control logic for deciding what to animate and how */
8799 AnimateMove(board, fromX, fromY, toX, toY)
8808 XPoint start, finish, mid;
8809 XPoint frames[kFactor * 2 + 1];
8810 int nFrames, startColor, endColor;
8812 /* Are we animating? */
8813 if (!appData.animate || appData.blindfold)
8816 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8817 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8818 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8820 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8821 piece = board[fromY][fromX];
8822 if (piece >= EmptySquare) return;
8827 hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1;
8830 if (appData.debugMode) {
8831 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8832 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8833 piece, fromX, fromY, toX, toY); }
8835 ScreenSquare(fromX, fromY, &start, &startColor);
8836 ScreenSquare(toX, toY, &finish, &endColor);
8839 /* Knight: make straight movement then diagonal */
8840 if (abs(toY - fromY) < abs(toX - fromX)) {
8841 mid.x = start.x + (finish.x - start.x) / 2;
8845 mid.y = start.y + (finish.y - start.y) / 2;
8848 mid.x = start.x + (finish.x - start.x) / 2;
8849 mid.y = start.y + (finish.y - start.y) / 2;
8852 /* Don't use as many frames for very short moves */
8853 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8854 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8856 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8857 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8858 if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
8860 for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
8861 if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
8864 /* Be sure end square is redrawn */
8865 damage[0][toY][toX] = True;
8869 DragPieceBegin(x, y)
8872 int boardX, boardY, color;
8875 /* Are we animating? */
8876 if (!appData.animateDragging || appData.blindfold)
8879 /* Figure out which square we start in and the
8880 mouse position relative to top left corner. */
8881 BoardSquare(x, y, &boardX, &boardY);
8882 player.startBoardX = boardX;
8883 player.startBoardY = boardY;
8884 ScreenSquare(boardX, boardY, &corner, &color);
8885 player.startSquare = corner;
8886 player.startColor = color;
8887 /* As soon as we start dragging, the piece will jump slightly to
8888 be centered over the mouse pointer. */
8889 player.mouseDelta.x = squareSize/2;
8890 player.mouseDelta.y = squareSize/2;
8891 /* Initialise animation */
8892 player.dragPiece = PieceForSquare(boardX, boardY);
8894 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8895 player.dragActive = True;
8896 BeginAnimation(&player, player.dragPiece, color, &corner);
8897 /* Mark this square as needing to be redrawn. Note that
8898 we don't remove the piece though, since logically (ie
8899 as seen by opponent) the move hasn't been made yet. */
8900 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8901 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8902 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8903 corner.x, corner.y, squareSize, squareSize,
8904 0, 0); // [HGM] zh: unstack in stead of grab
8905 if(gatingPiece != EmptySquare) {
8906 /* Kludge alert: When gating we want the introduced
8907 piece to appear on the from square. To generate an
8908 image of it, we draw it on the board, copy the image,
8909 and draw the original piece again. */
8910 ChessSquare piece = boards[currentMove][boardY][boardX];
8911 DrawSquare(boardY, boardX, gatingPiece, 0);
8912 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8913 corner.x, corner.y, squareSize, squareSize, 0, 0);
8914 DrawSquare(boardY, boardX, piece, 0);
8916 damage[0][boardY][boardX] = True;
8918 player.dragActive = False;
8928 /* Are we animating? */
8929 if (!appData.animateDragging || appData.blindfold)
8933 if (! player.dragActive)
8935 /* Move piece, maintaining same relative position
8936 of mouse within square */
8937 corner.x = x - player.mouseDelta.x;
8938 corner.y = y - player.mouseDelta.y;
8939 AnimationFrame(&player, &corner, player.dragPiece);
8941 if (appData.highlightDragging) {
8943 BoardSquare(x, y, &boardX, &boardY);
8944 SetHighlights(fromX, fromY, boardX, boardY);
8953 int boardX, boardY, color;
8956 /* Are we animating? */
8957 if (!appData.animateDragging || appData.blindfold)
8961 if (! player.dragActive)
8963 /* Last frame in sequence is square piece is
8964 placed on, which may not match mouse exactly. */
8965 BoardSquare(x, y, &boardX, &boardY);
8966 ScreenSquare(boardX, boardY, &corner, &color);
8967 EndAnimation(&player, &corner);
8969 /* Be sure end square is redrawn */
8970 damage[0][boardY][boardX] = True;
8972 /* This prevents weird things happening with fast successive
8973 clicks which on my Sun at least can cause motion events
8974 without corresponding press/release. */
8975 player.dragActive = False;
8978 /* Handle expose event while piece being dragged */
8983 if (!player.dragActive || appData.blindfold)
8986 /* What we're doing: logically, the move hasn't been made yet,
8987 so the piece is still in it's original square. But visually
8988 it's being dragged around the board. So we erase the square
8989 that the piece is on and draw it at the last known drag point. */
8990 BlankSquare(player.startSquare.x, player.startSquare.y,
8991 player.startColor, EmptySquare, xBoardWindow, 1);
8992 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8993 damage[0][player.startBoardY][player.startBoardX] = TRUE;
8996 #include <sys/ioctl.h>
8997 int get_term_width()
8999 int fd, default_width;
9002 default_width = 79; // this is FICS default anyway...
9004 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
9006 if (!ioctl(fd, TIOCGSIZE, &win))
9007 default_width = win.ts_cols;
9008 #elif defined(TIOCGWINSZ)
9010 if (!ioctl(fd, TIOCGWINSZ, &win))
9011 default_width = win.ws_col;
9013 return default_width;
9019 static int old_width = 0;
9020 int new_width = get_term_width();
9022 if (old_width != new_width)
9023 ics_printf("set width %d\n", new_width);
9024 old_width = new_width;
9027 void NotifyFrontendLogin()
9032 /* [AS] Arrow highlighting support */
9034 static double A_WIDTH = 5; /* Width of arrow body */
9036 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
9037 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
9039 static double Sqr( double x )
9044 static int Round( double x )
9046 return (int) (x + 0.5);
9049 void SquareToPos(int rank, int file, int *x, int *y)
9052 *x = lineGap + ((BOARD_WIDTH-1)-file) * (squareSize + lineGap);
9053 *y = lineGap + rank * (squareSize + lineGap);
9055 *x = lineGap + file * (squareSize + lineGap);
9056 *y = lineGap + ((BOARD_HEIGHT-1)-rank) * (squareSize + lineGap);
9060 /* Draw an arrow between two points using current settings */
9061 void DrawArrowBetweenPoints( int s_x, int s_y, int d_x, int d_y )
9064 double dx, dy, j, k, x, y;
9067 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
9069 arrow[0].x = s_x + A_WIDTH + 0.5;
9072 arrow[1].x = s_x + A_WIDTH + 0.5;
9073 arrow[1].y = d_y - h;
9075 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9076 arrow[2].y = d_y - h;
9081 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
9082 arrow[5].y = d_y - h;
9084 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9085 arrow[4].y = d_y - h;
9087 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
9090 else if( d_y == s_y ) {
9091 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
9094 arrow[0].y = s_y + A_WIDTH + 0.5;
9096 arrow[1].x = d_x - w;
9097 arrow[1].y = s_y + A_WIDTH + 0.5;
9099 arrow[2].x = d_x - w;
9100 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9105 arrow[5].x = d_x - w;
9106 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
9108 arrow[4].x = d_x - w;
9109 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9112 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
9115 /* [AS] Needed a lot of paper for this! :-) */
9116 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
9117 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
9119 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
9121 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
9126 arrow[0].x = Round(x - j);
9127 arrow[0].y = Round(y + j*dx);
9129 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
9130 arrow[1].y = Round(arrow[0].y - 2*j*dx);
9133 x = (double) d_x - k;
9134 y = (double) d_y - k*dy;
9137 x = (double) d_x + k;
9138 y = (double) d_y + k*dy;
9141 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
9143 arrow[6].x = Round(x - j);
9144 arrow[6].y = Round(y + j*dx);
9146 arrow[2].x = Round(arrow[6].x + 2*j);
9147 arrow[2].y = Round(arrow[6].y - 2*j*dx);
9149 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
9150 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
9155 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
9156 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
9159 XFillPolygon(xDisplay, xBoardWindow, highlineGC, arrow, 7, Nonconvex, CoordModeOrigin);
9160 // Polygon( hdc, arrow, 7 );
9163 /* [AS] Draw an arrow between two squares */
9164 void DrawArrowBetweenSquares( int s_col, int s_row, int d_col, int d_row )
9166 int s_x, s_y, d_x, d_y, hor, vert, i;
9168 if( s_col == d_col && s_row == d_row ) {
9172 /* Get source and destination points */
9173 SquareToPos( s_row, s_col, &s_x, &s_y);
9174 SquareToPos( d_row, d_col, &d_x, &d_y);
9177 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
9179 else if( d_y < s_y ) {
9180 d_y += squareSize / 2 + squareSize / 4;
9183 d_y += squareSize / 2;
9187 d_x += squareSize / 2 - squareSize / 4;
9189 else if( d_x < s_x ) {
9190 d_x += squareSize / 2 + squareSize / 4;
9193 d_x += squareSize / 2;
9196 s_x += squareSize / 2;
9197 s_y += squareSize / 2;
9200 A_WIDTH = squareSize / 14.; //[HGM] make float
9202 DrawArrowBetweenPoints( s_x, s_y, d_x, d_y );
9204 hor = 64*s_col + 32; vert = 64*s_row + 32;
9205 for(i=0; i<= 64; i++) {
9206 damage[0][vert+6>>6][hor+6>>6] = True;
9207 damage[0][vert-6>>6][hor+6>>6] = True;
9208 damage[0][vert+6>>6][hor-6>>6] = True;
9209 damage[0][vert-6>>6][hor-6>>6] = True;
9210 hor += d_col - s_col; vert += d_row - s_row;
9214 Boolean IsDrawArrowEnabled()
9216 return appData.highlightMoveWithArrow && squareSize >= 32;
9219 void DrawArrowHighlight(int fromX, int fromY, int toX,int toY)
9221 if( IsDrawArrowEnabled() && fromX >= 0 && fromY >= 0 && toX >= 0 && toY >= 0)
9222 DrawArrowBetweenSquares(fromX, fromY, toX, toY);