2 * xboard.c -- X front end for XBoard
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
8 * 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
10 * The following terms apply to Digital Equipment Corporation's copyright
12 * ------------------------------------------------------------------------
15 * Permission to use, copy, modify, and distribute this software and its
16 * documentation for any purpose and without fee is hereby granted,
17 * provided that the above copyright notice appear in all copies and that
18 * both that copyright notice and this permission notice appear in
19 * supporting documentation, and that the name of Digital not be
20 * used in advertising or publicity pertaining to distribution of the
21 * software without specific, written prior permission.
23 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
30 * ------------------------------------------------------------------------
32 * The following terms apply to the enhanced version of XBoard
33 * distributed by the Free Software Foundation:
34 * ------------------------------------------------------------------------
36 * GNU XBoard is free software: you can redistribute it and/or modify
37 * it under the terms of the GNU General Public License as published by
38 * the Free Software Foundation, either version 3 of the License, or (at
39 * your option) any later version.
41 * GNU XBoard is distributed in the hope that it will be useful, but
42 * WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44 * General Public License for more details.
46 * You should have received a copy of the GNU General Public License
47 * along with this program. If not, see http://www.gnu.org/licenses/. *
49 *------------------------------------------------------------------------
50 ** See the file ChangeLog for a revision history. */
60 #include <sys/types.h>
66 # if HAVE_SYS_SOCKET_H
67 # include <sys/socket.h>
68 # include <netinet/in.h>
70 # else /* not HAVE_SYS_SOCKET_H */
71 # if HAVE_LAN_SOCKET_H
72 # include <lan/socket.h>
74 # include <lan/netdb.h>
75 # else /* not HAVE_LAN_SOCKET_H */
76 # define OMIT_SOCKETS 1
77 # endif /* not HAVE_LAN_SOCKET_H */
78 # endif /* not HAVE_SYS_SOCKET_H */
79 #endif /* !OMIT_SOCKETS */
84 #else /* not STDC_HEADERS */
85 extern char *getenv();
88 # else /* not HAVE_STRING_H */
90 # endif /* not HAVE_STRING_H */
91 #endif /* not STDC_HEADERS */
94 # include <sys/fcntl.h>
95 #else /* not HAVE_SYS_FCNTL_H */
98 # endif /* HAVE_FCNTL_H */
99 #endif /* not HAVE_SYS_FCNTL_H */
101 #if HAVE_SYS_SYSTEMINFO_H
102 # include <sys/systeminfo.h>
103 #endif /* HAVE_SYS_SYSTEMINFO_H */
105 #if TIME_WITH_SYS_TIME
106 # include <sys/time.h>
110 # include <sys/time.h>
121 # include <sys/wait.h>
126 # define NAMLEN(dirent) strlen((dirent)->d_name)
127 # define HAVE_DIR_STRUCT
129 # define dirent direct
130 # define NAMLEN(dirent) (dirent)->d_namlen
132 # include <sys/ndir.h>
133 # define HAVE_DIR_STRUCT
136 # include <sys/dir.h>
137 # define HAVE_DIR_STRUCT
141 # define HAVE_DIR_STRUCT
145 #include <X11/Intrinsic.h>
146 #include <X11/StringDefs.h>
147 #include <X11/Shell.h>
148 #include <X11/cursorfont.h>
149 #include <X11/Xatom.h>
150 #include <X11/Xmu/Atoms.h>
152 #include <X11/Xaw3d/Dialog.h>
153 #include <X11/Xaw3d/Form.h>
154 #include <X11/Xaw3d/List.h>
155 #include <X11/Xaw3d/Label.h>
156 #include <X11/Xaw3d/SimpleMenu.h>
157 #include <X11/Xaw3d/SmeBSB.h>
158 #include <X11/Xaw3d/SmeLine.h>
159 #include <X11/Xaw3d/Box.h>
160 #include <X11/Xaw3d/MenuButton.h>
161 #include <X11/Xaw3d/Text.h>
162 #include <X11/Xaw3d/AsciiText.h>
164 #include <X11/Xaw/Dialog.h>
165 #include <X11/Xaw/Form.h>
166 #include <X11/Xaw/List.h>
167 #include <X11/Xaw/Label.h>
168 #include <X11/Xaw/SimpleMenu.h>
169 #include <X11/Xaw/SmeBSB.h>
170 #include <X11/Xaw/SmeLine.h>
171 #include <X11/Xaw/Box.h>
172 #include <X11/Xaw/MenuButton.h>
173 #include <X11/Xaw/Text.h>
174 #include <X11/Xaw/AsciiText.h>
177 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
182 #include "pixmaps/pixmaps.h"
183 #define IMAGE_EXT "xpm"
185 #define IMAGE_EXT "xim"
186 #include "bitmaps/bitmaps.h"
189 #include "bitmaps/icon_white.bm"
190 #include "bitmaps/icon_black.bm"
191 #include "bitmaps/checkmark.bm"
193 #include "frontend.h"
195 #include "backendz.h"
199 #include "xgamelist.h"
200 #include "xhistory.h"
201 #include "xedittags.h"
204 // must be moved to xengineoutput.h
206 void EngineOutputProc P((Widget w, XEvent *event,
207 String *prms, Cardinal *nprms));
208 void EvalGraphProc P((Widget w, XEvent *event,
209 String *prms, Cardinal *nprms));
216 #define usleep(t) _sleep2(((t)+500)/1000)
220 # define _(s) gettext (s)
221 # define N_(s) gettext_noop (s)
239 int main P((int argc, char **argv));
240 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
241 char *init_path, char *mode, int (*show_entry)(), char **name_return));
242 RETSIGTYPE CmailSigHandler P((int sig));
243 RETSIGTYPE IntSigHandler P((int sig));
244 RETSIGTYPE TermSizeSigHandler P((int sig));
245 void CreateGCs P((int redo));
246 void CreateXIMPieces P((void));
247 void CreateXPMPieces P((void));
248 void CreateXPMBoard P((char *s, int n));
249 void CreatePieces P((void));
250 void CreatePieceMenus P((void));
251 Widget CreateMenuBar P((Menu *mb));
252 Widget CreateButtonBar P ((MenuItem *mi));
253 char *FindFont P((char *pattern, int targetPxlSize));
254 void PieceMenuPopup P((Widget w, XEvent *event,
255 String *params, Cardinal *num_params));
256 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
257 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
258 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
259 u_int wreq, u_int hreq));
260 void CreateGrid P((void));
261 int EventToSquare P((int x, int limit));
262 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
263 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
264 void HandleUserMove P((Widget w, XEvent *event,
265 String *prms, Cardinal *nprms));
266 void AnimateUserMove P((Widget w, XEvent * event,
267 String * params, Cardinal * nParams));
268 void HandlePV P((Widget w, XEvent * event,
269 String * params, Cardinal * nParams));
270 void SelectPV P((Widget w, XEvent * event,
271 String * params, Cardinal * nParams));
272 void StopPV P((Widget w, XEvent * event,
273 String * params, Cardinal * nParams));
274 void WhiteClock P((Widget w, XEvent *event,
275 String *prms, Cardinal *nprms));
276 void BlackClock P((Widget w, XEvent *event,
277 String *prms, Cardinal *nprms));
278 void DrawPositionProc P((Widget w, XEvent *event,
279 String *prms, Cardinal *nprms));
280 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
282 void CommentClick P((Widget w, XEvent * event,
283 String * params, Cardinal * nParams));
284 void CommentPopUp P((char *title, char *label));
285 void CommentPopDown P((void));
286 void CommentCallback P((Widget w, XtPointer client_data,
287 XtPointer call_data));
288 void ICSInputBoxPopUp P((void));
289 void ICSInputBoxPopDown P((void));
290 void FileNamePopUp P((char *label, char *def,
291 FileProc proc, char *openMode));
292 void FileNamePopDown P((void));
293 void FileNameCallback P((Widget w, XtPointer client_data,
294 XtPointer call_data));
295 void FileNameAction P((Widget w, XEvent *event,
296 String *prms, Cardinal *nprms));
297 void AskQuestionReplyAction P((Widget w, XEvent *event,
298 String *prms, Cardinal *nprms));
299 void AskQuestionProc P((Widget w, XEvent *event,
300 String *prms, Cardinal *nprms));
301 void AskQuestionPopDown P((void));
302 void PromotionPopDown P((void));
303 void PromotionCallback P((Widget w, XtPointer client_data,
304 XtPointer call_data));
305 void EditCommentPopDown P((void));
306 void EditCommentCallback P((Widget w, XtPointer client_data,
307 XtPointer call_data));
308 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
309 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
310 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
311 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
313 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
315 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
317 void LoadPositionProc P((Widget w, XEvent *event,
318 String *prms, Cardinal *nprms));
319 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
321 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
323 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
325 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
327 void PastePositionProc P((Widget w, XEvent *event, String *prms,
329 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
330 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
331 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
332 void SavePositionProc P((Widget w, XEvent *event,
333 String *prms, Cardinal *nprms));
334 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
335 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
337 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
338 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
339 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
341 void MachineWhiteProc P((Widget w, XEvent *event,
342 String *prms, Cardinal *nprms));
343 void AnalyzeModeProc P((Widget w, XEvent *event,
344 String *prms, Cardinal *nprms));
345 void AnalyzeFileProc P((Widget w, XEvent *event,
346 String *prms, Cardinal *nprms));
347 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
349 void IcsClientProc P((Widget w, XEvent *event, String *prms,
351 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
352 void EditPositionProc P((Widget w, XEvent *event,
353 String *prms, Cardinal *nprms));
354 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
355 void EditCommentProc P((Widget w, XEvent *event,
356 String *prms, Cardinal *nprms));
357 void IcsInputBoxProc P((Widget w, XEvent *event,
358 String *prms, Cardinal *nprms));
359 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
365 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
370 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
371 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
372 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
373 void StopObservingProc P((Widget w, XEvent *event, String *prms,
375 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
377 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
379 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
380 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
384 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
386 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
388 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
389 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
391 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
393 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
395 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
396 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
397 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
398 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
400 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
401 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
403 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
405 void HighlightArrowProc P((Widget w, XEvent *event, String *prms,
407 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
408 //void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
409 void OneClickProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
410 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
412 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
414 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
416 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
418 //void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
419 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
421 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
423 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
425 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
427 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
428 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
429 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
430 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
431 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
432 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
433 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
434 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
435 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
436 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void DisplayMove P((int moveNumber));
439 void DisplayTitle P((char *title));
440 void ICSInitScript P((void));
441 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
442 void ErrorPopUp P((char *title, char *text, int modal));
443 void ErrorPopDown P((void));
444 static char *ExpandPathName P((char *path));
445 static void CreateAnimVars P((void));
446 static void DragPieceMove P((int x, int y));
447 static void DrawDragPiece P((void));
448 char *ModeToWidgetName P((GameMode mode));
449 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
450 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
451 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
452 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
453 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
454 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
455 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
456 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
457 void IcsOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
458 void SoundOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
459 void BoardOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
460 void LoadOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
461 void SaveOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
462 void GameListOptionsPopDown P(());
463 void ShufflePopDown P(());
464 void 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 {N_("Sounds ..."), "Sounds", SoundOptionsProc},
716 {"----", NULL, NothingProc},
717 {N_("Always Queen Ctrl+Shift+Q"), "Always Queen", AlwaysQueenProc},
718 {N_("Animate Dragging"), "Animate Dragging", AnimateDraggingProc},
719 {N_("Animate Moving Ctrl+Shift+A"), "Animate Moving", AnimateMovingProc},
720 {N_("Auto Flag Ctrl+Shift+F"), "Auto Flag", AutoflagProc},
721 {N_("Auto Flip View"), "Auto Flip View", AutoflipProc},
722 {N_("Blindfold"), "Blindfold", BlindfoldProc},
723 {N_("Flash Moves"), "Flash Moves", FlashMovesProc},
725 {N_("Highlight Dragging"), "Highlight Dragging", HighlightDraggingProc},
727 {N_("Highlight Last Move"), "Highlight Last Move", HighlightLastMoveProc},
728 {N_("Highlight With Arrow"), "Arrow", HighlightArrowProc},
729 {N_("Move Sound"), "Move Sound", MoveSoundProc},
730 // {N_("ICS Alarm"), "ICS Alarm", IcsAlarmProc},
731 {N_("One-Click Moving"), "OneClick", OneClickProc},
732 {N_("Periodic Updates"), "Periodic Updates", PeriodicUpdatesProc},
733 {N_("Ponder Next Move Ctrl+Shift+P"), "Ponder Next Move", PonderNextMoveProc},
734 {N_("Popup Exit Message"), "Popup Exit Message", PopupExitMessageProc},
735 {N_("Popup Move Errors"), "Popup Move Errors", PopupMoveErrorsProc},
736 // {N_("Premove"), "Premove", PremoveProc},
737 {N_("Show Coords"), "Show Coords", ShowCoordsProc},
738 {N_("Hide Thinking Ctrl+Shift+H"), "Hide Thinking", HideThinkingProc},
739 {N_("Test Legality Ctrl+Shift+L"), "Test Legality", TestLegalityProc},
740 {"----", NULL, NothingProc},
741 {N_("Save Settings Now"), "Save Settings Now", SaveSettingsProc},
742 {N_("Save Settings on Exit"), "Save Settings on Exit", SaveOnExitProc},
746 MenuItem helpMenu[] = {
747 {N_("Info XBoard"), "Info XBoard", InfoProc},
748 {N_("Man XBoard F1"), "Man XBoard", ManProc},
749 {"----", NULL, NothingProc},
750 {N_("About XBoard"), "About XBoard", AboutProc},
755 {N_("File"), "File", fileMenu},
756 {N_("Edit"), "Edit", editMenu},
757 {N_("View"), "View", viewMenu},
758 {N_("Mode"), "Mode", modeMenu},
759 {N_("Action"), "Action", actionMenu},
760 {N_("Engine"), "Engine", engineMenu},
761 {N_("Options"), "Options", optionsMenu},
762 {N_("Help"), "Help", helpMenu},
766 #define PAUSE_BUTTON "P"
767 MenuItem buttonBar[] = {
768 {"<<", "<<", ToStartProc},
769 {"<", "<", BackwardProc},
770 {PAUSE_BUTTON, PAUSE_BUTTON, PauseProc},
771 {">", ">", ForwardProc},
772 {">>", ">>", ToEndProc},
776 #define PIECE_MENU_SIZE 18
777 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
778 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
779 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
780 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
781 N_("Empty square"), N_("Clear board") },
782 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
783 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
784 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
785 N_("Empty square"), N_("Clear board") }
787 /* must be in same order as PieceMenuStrings! */
788 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
789 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
790 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
791 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
792 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
793 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
794 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
795 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
796 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
799 #define DROP_MENU_SIZE 6
800 String dropMenuStrings[DROP_MENU_SIZE] = {
801 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
803 /* must be in same order as PieceMenuStrings! */
804 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
805 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
806 WhiteRook, WhiteQueen
814 DropMenuEnables dmEnables[] = {
832 { XtNborderWidth, 0 },
833 { XtNdefaultDistance, 0 },
837 { XtNborderWidth, 0 },
838 { XtNresizable, (XtArgVal) True },
842 { XtNborderWidth, 0 },
848 { XtNjustify, (XtArgVal) XtJustifyRight },
849 { XtNlabel, (XtArgVal) "..." },
850 { XtNresizable, (XtArgVal) True },
851 { XtNresize, (XtArgVal) False }
854 Arg messageArgs[] = {
855 { XtNjustify, (XtArgVal) XtJustifyLeft },
856 { XtNlabel, (XtArgVal) "..." },
857 { XtNresizable, (XtArgVal) True },
858 { XtNresize, (XtArgVal) False }
862 { XtNborderWidth, 0 },
863 { XtNjustify, (XtArgVal) XtJustifyLeft }
866 XtResource clientResources[] = {
867 { "flashCount", "flashCount", XtRInt, sizeof(int),
868 XtOffset(AppDataPtr, flashCount), XtRImmediate,
869 (XtPointer) FLASH_COUNT },
872 XrmOptionDescRec shellOptions[] = {
873 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
874 { "-flash", "flashCount", XrmoptionNoArg, "3" },
875 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
878 XtActionsRec boardActions[] = {
879 { "DrawPosition", DrawPositionProc },
880 { "HandleUserMove", HandleUserMove },
881 { "AnimateUserMove", AnimateUserMove },
882 { "HandlePV", HandlePV },
883 { "SelectPV", SelectPV },
884 { "StopPV", StopPV },
885 { "FileNameAction", FileNameAction },
886 { "AskQuestionProc", AskQuestionProc },
887 { "AskQuestionReplyAction", AskQuestionReplyAction },
888 { "PieceMenuPopup", PieceMenuPopup },
889 { "WhiteClock", WhiteClock },
890 { "BlackClock", BlackClock },
891 { "Iconify", Iconify },
892 { "ResetProc", ResetProc },
893 { "NewVariantProc", NewVariantProc },
894 { "LoadGameProc", LoadGameProc },
895 { "LoadNextGameProc", LoadNextGameProc },
896 { "LoadPrevGameProc", LoadPrevGameProc },
897 { "LoadSelectedProc", LoadSelectedProc },
898 { "SetFilterProc", SetFilterProc },
899 { "ReloadGameProc", ReloadGameProc },
900 { "LoadPositionProc", LoadPositionProc },
901 { "LoadNextPositionProc", LoadNextPositionProc },
902 { "LoadPrevPositionProc", LoadPrevPositionProc },
903 { "ReloadPositionProc", ReloadPositionProc },
904 { "CopyPositionProc", CopyPositionProc },
905 { "PastePositionProc", PastePositionProc },
906 { "CopyGameProc", CopyGameProc },
907 { "PasteGameProc", PasteGameProc },
908 { "SaveGameProc", SaveGameProc },
909 { "SavePositionProc", SavePositionProc },
910 { "MailMoveProc", MailMoveProc },
911 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
912 { "QuitProc", QuitProc },
913 { "MachineWhiteProc", MachineWhiteProc },
914 { "MachineBlackProc", MachineBlackProc },
915 { "AnalysisModeProc", AnalyzeModeProc },
916 { "AnalyzeFileProc", AnalyzeFileProc },
917 { "TwoMachinesProc", TwoMachinesProc },
918 { "IcsClientProc", IcsClientProc },
919 { "EditGameProc", EditGameProc },
920 { "EditPositionProc", EditPositionProc },
921 { "TrainingProc", EditPositionProc },
922 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
923 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
924 { "ShowGameListProc", ShowGameListProc },
925 { "ShowMoveListProc", HistoryShowProc},
926 { "EditTagsProc", EditCommentProc },
927 { "EditCommentProc", EditCommentProc },
928 { "IcsInputBoxProc", IcsInputBoxProc },
929 { "PauseProc", PauseProc },
930 { "AcceptProc", AcceptProc },
931 { "DeclineProc", DeclineProc },
932 { "RematchProc", RematchProc },
933 { "CallFlagProc", CallFlagProc },
934 { "DrawProc", DrawProc },
935 { "AdjournProc", AdjournProc },
936 { "AbortProc", AbortProc },
937 { "ResignProc", ResignProc },
938 { "AdjuWhiteProc", AdjuWhiteProc },
939 { "AdjuBlackProc", AdjuBlackProc },
940 { "AdjuDrawProc", AdjuDrawProc },
941 { "EnterKeyProc", EnterKeyProc },
942 { "UpKeyProc", UpKeyProc },
943 { "DownKeyProc", DownKeyProc },
944 { "StopObservingProc", StopObservingProc },
945 { "StopExaminingProc", StopExaminingProc },
946 { "UploadProc", UploadProc },
947 { "BackwardProc", BackwardProc },
948 { "ForwardProc", ForwardProc },
949 { "ToStartProc", ToStartProc },
950 { "ToEndProc", ToEndProc },
951 { "RevertProc", RevertProc },
952 { "AnnotateProc", AnnotateProc },
953 { "TruncateGameProc", TruncateGameProc },
954 { "MoveNowProc", MoveNowProc },
955 { "RetractMoveProc", RetractMoveProc },
956 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
957 { "UciMenuProc", (XtActionProc) UciMenuProc },
958 { "TimeControlProc", (XtActionProc) TimeControlProc },
959 { "AlwaysQueenProc", AlwaysQueenProc },
960 { "AnimateDraggingProc", AnimateDraggingProc },
961 { "AnimateMovingProc", AnimateMovingProc },
962 { "AutoflagProc", AutoflagProc },
963 { "AutoflipProc", AutoflipProc },
964 { "BlindfoldProc", BlindfoldProc },
965 { "FlashMovesProc", FlashMovesProc },
966 { "FlipViewProc", FlipViewProc },
968 { "HighlightDraggingProc", HighlightDraggingProc },
970 { "HighlightLastMoveProc", HighlightLastMoveProc },
971 // { "IcsAlarmProc", IcsAlarmProc },
972 { "MoveSoundProc", MoveSoundProc },
973 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
974 { "PonderNextMoveProc", PonderNextMoveProc },
975 { "PopupExitMessageProc", PopupExitMessageProc },
976 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
977 // { "PremoveProc", PremoveProc },
978 { "ShowCoordsProc", ShowCoordsProc },
979 { "ShowThinkingProc", ShowThinkingProc },
980 { "HideThinkingProc", HideThinkingProc },
981 { "TestLegalityProc", TestLegalityProc },
982 { "SaveSettingsProc", SaveSettingsProc },
983 { "SaveOnExitProc", SaveOnExitProc },
984 { "InfoProc", InfoProc },
985 { "ManProc", ManProc },
986 { "HintProc", HintProc },
987 { "BookProc", BookProc },
988 { "AboutGameProc", AboutGameProc },
989 { "AboutProc", AboutProc },
990 { "DebugProc", DebugProc },
991 { "NothingProc", NothingProc },
992 { "CommentClick", (XtActionProc) CommentClick },
993 { "CommentPopDown", (XtActionProc) CommentPopDown },
994 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
995 { "TagsPopDown", (XtActionProc) TagsPopDown },
996 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
997 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
998 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
999 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
1000 { "GameListPopDown", (XtActionProc) GameListPopDown },
1001 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
1002 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1003 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
1004 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1005 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1006 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
1007 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
1008 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
1009 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
1010 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1013 char globalTranslations[] =
1014 ":<Key>F9: ResignProc() \n \
1015 :Ctrl<Key>n: ResetProc() \n \
1016 :Meta<Key>V: NewVariantProc() \n \
1017 :Ctrl<Key>o: LoadGameProc() \n \
1018 :Meta<Key>Next: LoadNextGameProc() \n \
1019 :Meta<Key>Prior: LoadPrevGameProc() \n \
1020 :Ctrl<Key>s: SaveGameProc() \n \
1021 :Ctrl<Key>c: CopyGameProc() \n \
1022 :Ctrl<Key>v: PasteGameProc() \n \
1023 :Ctrl<Key>O: LoadPositionProc() \n \
1024 :Shift<Key>Next: LoadNextPositionProc() \n \
1025 :Shift<Key>Prior: LoadPrevPositionProc() \n \
1026 :Ctrl<Key>S: SavePositionProc() \n \
1027 :Ctrl<Key>C: CopyPositionProc() \n \
1028 :Ctrl<Key>V: PastePositionProc() \n \
1029 :Ctrl<Key>q: QuitProc() \n \
1030 :Ctrl<Key>w: MachineWhiteProc() \n \
1031 :Ctrl<Key>b: MachineBlackProc() \n \
1032 :Ctrl<Key>t: TwoMachinesProc() \n \
1033 :Ctrl<Key>a: AnalysisModeProc() \n \
1034 :Ctrl<Key>f: AnalyzeFileProc() \n \
1035 :Ctrl<Key>e: EditGameProc() \n \
1036 :Ctrl<Key>E: EditPositionProc() \n \
1037 :Meta<Key>O: EngineOutputProc() \n \
1038 :Meta<Key>E: EvalGraphProc() \n \
1039 :Meta<Key>G: ShowGameListProc() \n \
1040 :Meta<Key>H: ShowMoveListProc() \n \
1041 :<Key>Pause: PauseProc() \n \
1042 :<Key>F3: AcceptProc() \n \
1043 :<Key>F4: DeclineProc() \n \
1044 :<Key>F12: RematchProc() \n \
1045 :<Key>F5: CallFlagProc() \n \
1046 :<Key>F6: DrawProc() \n \
1047 :<Key>F7: AdjournProc() \n \
1048 :<Key>F8: AbortProc() \n \
1049 :<Key>F10: StopObservingProc() \n \
1050 :<Key>F11: StopExaminingProc() \n \
1051 :Meta Ctrl<Key>F12: DebugProc() \n \
1052 :Meta<Key>End: ToEndProc() \n \
1053 :Meta<Key>Right: ForwardProc() \n \
1054 :Meta<Key>Home: ToStartProc() \n \
1055 :Meta<Key>Left: BackwardProc() \n \
1056 :<Key>Home: RevertProc() \n \
1057 :<Key>End: TruncateGameProc() \n \
1058 :Ctrl<Key>m: MoveNowProc() \n \
1059 :Ctrl<Key>x: RetractMoveProc() \n \
1060 :Meta<Key>J: EngineMenuProc() \n \
1061 :Meta<Key>U: UciMenuProc() \n \
1062 :Meta<Key>T: TimeControlProc() \n \
1063 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1064 :Ctrl<Key>F: AutoflagProc() \n \
1065 :Ctrl<Key>A: AnimateMovingProc() \n \
1066 :Ctrl<Key>P: PonderNextMoveProc() \n \
1067 :Ctrl<Key>L: TestLegalityProc() \n \
1068 :Ctrl<Key>H: HideThinkingProc() \n \
1069 :<Key>-: Iconify() \n \
1070 :<Key>F1: ManProc() \n \
1071 :<Key>F2: FlipViewProc() \n \
1072 <KeyDown>.: BackwardProc() \n \
1073 <KeyUp>.: ForwardProc() \n \
1074 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1075 \"Send to chess program:\",,1) \n \
1076 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1077 \"Send to second chess program:\",,2) \n";
1079 char boardTranslations[] =
1080 "<Btn1Down>: HandleUserMove(0) \n \
1081 Shift<Btn1Up>: HandleUserMove(1) \n \
1082 <Btn1Up>: HandleUserMove(0) \n \
1083 <Btn1Motion>: AnimateUserMove() \n \
1084 <Btn3Motion>: HandlePV() \n \
1085 <Btn3Up>: PieceMenuPopup(menuB) \n \
1086 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1087 PieceMenuPopup(menuB) \n \
1088 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1089 PieceMenuPopup(menuW) \n \
1090 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1091 PieceMenuPopup(menuW) \n \
1092 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1093 PieceMenuPopup(menuB) \n";
1095 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1096 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1098 char ICSInputTranslations[] =
1099 "<Key>Up: UpKeyProc() \n "
1100 "<Key>Down: DownKeyProc() \n "
1101 "<Key>Return: EnterKeyProc() \n";
1103 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1104 // as the widget is destroyed before the up-click can call extend-end
1105 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1107 String xboardResources[] = {
1108 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1109 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1110 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1115 /* Max possible square size */
1116 #define MAXSQSIZE 256
1118 static int xpm_avail[MAXSQSIZE];
1120 #ifdef HAVE_DIR_STRUCT
1122 /* Extract piece size from filename */
1124 xpm_getsize(name, len, ext)
1135 if ((p=strchr(name, '.')) == NULL ||
1136 StrCaseCmp(p+1, ext) != 0)
1142 while (*p && isdigit(*p))
1149 /* Setup xpm_avail */
1151 xpm_getavail(dirname, ext)
1159 for (i=0; i<MAXSQSIZE; ++i)
1162 if (appData.debugMode)
1163 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1165 dir = opendir(dirname);
1168 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1169 programName, dirname);
1173 while ((ent=readdir(dir)) != NULL) {
1174 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1175 if (i > 0 && i < MAXSQSIZE)
1185 xpm_print_avail(fp, ext)
1191 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1192 for (i=1; i<MAXSQSIZE; ++i) {
1198 /* Return XPM piecesize closest to size */
1200 xpm_closest_to(dirname, size, ext)
1206 int sm_diff = MAXSQSIZE;
1210 xpm_getavail(dirname, ext);
1212 if (appData.debugMode)
1213 xpm_print_avail(stderr, ext);
1215 for (i=1; i<MAXSQSIZE; ++i) {
1218 diff = (diff<0) ? -diff : diff;
1219 if (diff < sm_diff) {
1227 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1233 #else /* !HAVE_DIR_STRUCT */
1234 /* If we are on a system without a DIR struct, we can't
1235 read the directory, so we can't collect a list of
1236 filenames, etc., so we can't do any size-fitting. */
1238 xpm_closest_to(dirname, size, ext)
1243 fprintf(stderr, _("\
1244 Warning: No DIR structure found on this system --\n\
1245 Unable to autosize for XPM/XIM pieces.\n\
1246 Please report this error to frankm@hiwaay.net.\n\
1247 Include system type & operating system in message.\n"));
1250 #endif /* HAVE_DIR_STRUCT */
1252 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1253 "magenta", "cyan", "white" };
1257 TextColors textColors[(int)NColorClasses];
1259 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1261 parse_color(str, which)
1265 char *p, buf[100], *d;
1268 if (strlen(str) > 99) /* watch bounds on buf */
1273 for (i=0; i<which; ++i) {
1280 /* Could be looking at something like:
1282 .. in which case we want to stop on a comma also */
1283 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1287 return -1; /* Use default for empty field */
1290 if (which == 2 || isdigit(*p))
1293 while (*p && isalpha(*p))
1298 for (i=0; i<8; ++i) {
1299 if (!StrCaseCmp(buf, cnames[i]))
1300 return which? (i+40) : (i+30);
1302 if (!StrCaseCmp(buf, "default")) return -1;
1304 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1309 parse_cpair(cc, str)
1313 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1314 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1319 /* bg and attr are optional */
1320 textColors[(int)cc].bg = parse_color(str, 1);
1321 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1322 textColors[(int)cc].attr = 0;
1328 /* Arrange to catch delete-window events */
1329 Atom wm_delete_window;
1331 CatchDeleteWindow(Widget w, String procname)
1334 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1335 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1336 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1343 XtSetArg(args[0], XtNiconic, False);
1344 XtSetValues(shellWidget, args, 1);
1346 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1349 //---------------------------------------------------------------------------------------------------------
1350 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1353 #define CW_USEDEFAULT (1<<31)
1354 #define ICS_TEXT_MENU_SIZE 90
1355 #define DEBUG_FILE "xboard.debug"
1356 #define SetCurrentDirectory chdir
1357 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1361 // these two must some day move to frontend.h, when they are implemented
1362 Boolean GameListIsUp();
1364 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1367 // front-end part of option handling
1369 // [HGM] This platform-dependent table provides the location for storing the color info
1370 extern char *crWhite, * crBlack;
1374 &appData.whitePieceColor,
1375 &appData.blackPieceColor,
1376 &appData.lightSquareColor,
1377 &appData.darkSquareColor,
1378 &appData.highlightSquareColor,
1379 &appData.premoveHighlightColor,
1380 &appData.lowTimeWarningColor,
1391 // [HGM] font: keep a font for each square size, even non-stndard ones
1392 #define NUM_SIZES 18
1393 #define MAX_SIZE 130
1394 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1395 char *fontTable[NUM_FONTS][MAX_SIZE];
1398 ParseFont(char *name, int number)
1399 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1401 if(sscanf(name, "size%d:", &size)) {
1402 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1403 // defer processing it until we know if it matches our board size
1404 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1405 fontTable[number][size] = strdup(strchr(name, ':')+1);
1406 fontValid[number][size] = True;
1411 case 0: // CLOCK_FONT
1412 appData.clockFont = strdup(name);
1414 case 1: // MESSAGE_FONT
1415 appData.font = strdup(name);
1417 case 2: // COORD_FONT
1418 appData.coordFont = strdup(name);
1423 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1428 { // only 2 fonts currently
1429 appData.clockFont = CLOCK_FONT_NAME;
1430 appData.coordFont = COORD_FONT_NAME;
1431 appData.font = DEFAULT_FONT_NAME;
1436 { // no-op, until we identify the code for this already in XBoard and move it here
1440 ParseColor(int n, char *name)
1441 { // in XBoard, just copy the color-name string
1442 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1446 ParseTextAttribs(ColorClass cc, char *s)
1448 (&appData.colorShout)[cc] = strdup(s);
1452 ParseBoardSize(void *addr, char *name)
1454 appData.boardSize = strdup(name);
1459 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1463 SetCommPortDefaults()
1464 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1467 // [HGM] args: these three cases taken out to stay in front-end
1469 SaveFontArg(FILE *f, ArgDescriptor *ad)
1472 int i, n = (int)(intptr_t)ad->argLoc;
1474 case 0: // CLOCK_FONT
1475 name = appData.clockFont;
1477 case 1: // MESSAGE_FONT
1478 name = appData.font;
1480 case 2: // COORD_FONT
1481 name = appData.coordFont;
1486 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1487 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1488 fontTable[n][squareSize] = strdup(name);
1489 fontValid[n][squareSize] = True;
1492 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1493 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1498 { // nothing to do, as the sounds are at all times represented by their text-string names already
1502 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1503 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1504 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
1508 SaveColor(FILE *f, ArgDescriptor *ad)
1509 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1510 if(colorVariable[(int)(intptr_t)ad->argLoc])
1511 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
1515 SaveBoardSize(FILE *f, char *name, void *addr)
1516 { // wrapper to shield back-end from BoardSize & sizeInfo
1517 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1521 ParseCommPortSettings(char *s)
1522 { // no such option in XBoard (yet)
1525 extern Widget engineOutputShell;
1526 extern Widget tagsShell, editTagsShell;
1528 GetActualPlacement(Widget wg, WindowPlacement *wp)
1538 XtSetArg(args[i], XtNx, &x); i++;
1539 XtSetArg(args[i], XtNy, &y); i++;
1540 XtSetArg(args[i], XtNwidth, &w); i++;
1541 XtSetArg(args[i], XtNheight, &h); i++;
1542 XtGetValues(wg, args, i);
1551 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1552 // In XBoard this will have to wait until awareness of window parameters is implemented
1553 GetActualPlacement(shellWidget, &wpMain);
1554 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1555 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1556 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1557 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1558 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1559 else GetActualPlacement(editShell, &wpComment);
1560 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1561 else GetActualPlacement(editTagsShell, &wpTags);
1565 PrintCommPortSettings(FILE *f, char *name)
1566 { // This option does not exist in XBoard
1570 MySearchPath(char *installDir, char *name, char *fullname)
1571 { // just append installDir and name. Perhaps ExpandPath should be used here?
1572 name = ExpandPathName(name);
1573 if(name && name[0] == '/')
1574 safeStrCpy(fullname, name, MSG_SIZ );
1576 sprintf(fullname, "%s%c%s", installDir, '/', name);
1582 MyGetFullPathName(char *name, char *fullname)
1583 { // should use ExpandPath?
1584 name = ExpandPathName(name);
1585 safeStrCpy(fullname, name, MSG_SIZ );
1590 EnsureOnScreen(int *x, int *y, int minX, int minY)
1597 { // [HGM] args: allows testing if main window is realized from back-end
1598 return xBoardWindow != 0;
1602 PopUpStartupDialog()
1603 { // start menu not implemented in XBoard
1607 ConvertToLine(int argc, char **argv)
1609 static char line[128*1024], buf[1024];
1613 for(i=1; i<argc; i++)
1615 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1616 && argv[i][0] != '{' )
1617 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1619 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1620 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1623 line[strlen(line)-1] = NULLCHAR;
1627 //--------------------------------------------------------------------------------------------
1629 extern Boolean twoBoards, partnerUp;
1632 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1634 #define BoardSize int
1635 void InitDrawingSizes(BoardSize boardSize, int flags)
1636 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1637 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1639 XtGeometryResult gres;
1642 if(!formWidget) return;
1645 * Enable shell resizing.
1647 shellArgs[0].value = (XtArgVal) &w;
1648 shellArgs[1].value = (XtArgVal) &h;
1649 XtGetValues(shellWidget, shellArgs, 2);
1651 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1652 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1653 XtSetValues(shellWidget, &shellArgs[2], 4);
1655 XtSetArg(args[0], XtNdefaultDistance, &sep);
1656 XtGetValues(formWidget, args, 1);
1658 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1659 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1660 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1662 hOffset = boardWidth + 10;
1663 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1664 secondSegments[i] = gridSegments[i];
1665 secondSegments[i].x1 += hOffset;
1666 secondSegments[i].x2 += hOffset;
1669 XtSetArg(args[0], XtNwidth, boardWidth);
1670 XtSetArg(args[1], XtNheight, boardHeight);
1671 XtSetValues(boardWidget, args, 2);
1673 timerWidth = (boardWidth - sep) / 2;
1674 XtSetArg(args[0], XtNwidth, timerWidth);
1675 XtSetValues(whiteTimerWidget, args, 1);
1676 XtSetValues(blackTimerWidget, args, 1);
1678 XawFormDoLayout(formWidget, False);
1680 if (appData.titleInWindow) {
1682 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1683 XtSetArg(args[i], XtNheight, &h); i++;
1684 XtGetValues(titleWidget, args, i);
1686 w = boardWidth - 2*bor;
1688 XtSetArg(args[0], XtNwidth, &w);
1689 XtGetValues(menuBarWidget, args, 1);
1690 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1693 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1694 if (gres != XtGeometryYes && appData.debugMode) {
1696 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1697 programName, gres, w, h, wr, hr);
1701 XawFormDoLayout(formWidget, True);
1704 * Inhibit shell resizing.
1706 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1707 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1708 shellArgs[4].value = shellArgs[2].value = w;
1709 shellArgs[5].value = shellArgs[3].value = h;
1710 XtSetValues(shellWidget, &shellArgs[0], 6);
1712 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1715 for(i=0; i<4; i++) {
1717 for(p=0; p<=(int)WhiteKing; p++)
1718 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1719 if(gameInfo.variant == VariantShogi) {
1720 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1721 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1722 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1723 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1724 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1727 if(gameInfo.variant == VariantGothic) {
1728 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1731 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1732 xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
1733 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1736 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1737 for(p=0; p<=(int)WhiteKing; p++)
1738 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1739 if(gameInfo.variant == VariantShogi) {
1740 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1741 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1742 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1743 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1744 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1747 if(gameInfo.variant == VariantGothic) {
1748 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1751 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1752 ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
1753 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1758 for(i=0; i<2; i++) {
1760 for(p=0; p<=(int)WhiteKing; p++)
1761 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1762 if(gameInfo.variant == VariantShogi) {
1763 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1764 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1765 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1766 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1767 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1770 if(gameInfo.variant == VariantGothic) {
1771 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1774 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1775 pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
1776 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1786 void ParseIcsTextColors()
1787 { // [HGM] tken out of main(), so it can be called from ICS-Options dialog
1788 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1789 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1790 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1791 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1792 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1793 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1794 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1795 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1796 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1797 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1799 if (appData.colorize) {
1801 _("%s: can't parse color names; disabling colorization\n"),
1804 appData.colorize = FALSE;
1809 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
1810 XrmValue vFrom, vTo;
1811 int forceMono = False;
1813 if (!appData.monoMode) {
1814 vFrom.addr = (caddr_t) appData.lightSquareColor;
1815 vFrom.size = strlen(appData.lightSquareColor);
1816 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1817 if (vTo.addr == NULL) {
1818 appData.monoMode = True;
1821 lightSquareColor = *(Pixel *) vTo.addr;
1824 if (!appData.monoMode) {
1825 vFrom.addr = (caddr_t) appData.darkSquareColor;
1826 vFrom.size = strlen(appData.darkSquareColor);
1827 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1828 if (vTo.addr == NULL) {
1829 appData.monoMode = True;
1832 darkSquareColor = *(Pixel *) vTo.addr;
1835 if (!appData.monoMode) {
1836 vFrom.addr = (caddr_t) appData.whitePieceColor;
1837 vFrom.size = strlen(appData.whitePieceColor);
1838 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1839 if (vTo.addr == NULL) {
1840 appData.monoMode = True;
1843 whitePieceColor = *(Pixel *) vTo.addr;
1846 if (!appData.monoMode) {
1847 vFrom.addr = (caddr_t) appData.blackPieceColor;
1848 vFrom.size = strlen(appData.blackPieceColor);
1849 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1850 if (vTo.addr == NULL) {
1851 appData.monoMode = True;
1854 blackPieceColor = *(Pixel *) vTo.addr;
1858 if (!appData.monoMode) {
1859 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1860 vFrom.size = strlen(appData.highlightSquareColor);
1861 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1862 if (vTo.addr == NULL) {
1863 appData.monoMode = True;
1866 highlightSquareColor = *(Pixel *) vTo.addr;
1870 if (!appData.monoMode) {
1871 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1872 vFrom.size = strlen(appData.premoveHighlightColor);
1873 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1874 if (vTo.addr == NULL) {
1875 appData.monoMode = True;
1878 premoveHighlightColor = *(Pixel *) vTo.addr;
1889 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1890 XSetWindowAttributes window_attributes;
1892 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1893 XrmValue vFrom, vTo;
1894 XtGeometryResult gres;
1897 int forceMono = False;
1899 srandom(time(0)); // [HGM] book: make random truly random
1901 setbuf(stdout, NULL);
1902 setbuf(stderr, NULL);
1905 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1906 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1910 programName = strrchr(argv[0], '/');
1911 if (programName == NULL)
1912 programName = argv[0];
1917 XtSetLanguageProc(NULL, NULL, NULL);
1918 bindtextdomain(PACKAGE, LOCALEDIR);
1919 textdomain(PACKAGE);
1923 XtAppInitialize(&appContext, "XBoard", shellOptions,
1924 XtNumber(shellOptions),
1925 &argc, argv, xboardResources, NULL, 0);
1926 appData.boardSize = "";
1927 InitAppData(ConvertToLine(argc, argv));
1929 if (p == NULL) p = "/tmp";
1930 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1931 gameCopyFilename = (char*) malloc(i);
1932 gamePasteFilename = (char*) malloc(i);
1933 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1934 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1936 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1937 clientResources, XtNumber(clientResources),
1940 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1941 static char buf[MSG_SIZ];
1942 EscapeExpand(buf, appData.initString);
1943 appData.initString = strdup(buf);
1944 EscapeExpand(buf, appData.secondInitString);
1945 appData.secondInitString = strdup(buf);
1946 EscapeExpand(buf, appData.firstComputerString);
1947 appData.firstComputerString = strdup(buf);
1948 EscapeExpand(buf, appData.secondComputerString);
1949 appData.secondComputerString = strdup(buf);
1952 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1955 if (chdir(chessDir) != 0) {
1956 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1962 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1963 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1964 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1965 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1968 setbuf(debugFP, NULL);
1971 /* [HGM,HR] make sure board size is acceptable */
1972 if(appData.NrFiles > BOARD_FILES ||
1973 appData.NrRanks > BOARD_RANKS )
1974 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1977 /* This feature does not work; animation needs a rewrite */
1978 appData.highlightDragging = FALSE;
1982 xDisplay = XtDisplay(shellWidget);
1983 xScreen = DefaultScreen(xDisplay);
1984 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1986 gameInfo.variant = StringToVariant(appData.variant);
1987 InitPosition(FALSE);
1990 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1992 if (isdigit(appData.boardSize[0])) {
1993 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1994 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1995 &fontPxlSize, &smallLayout, &tinyLayout);
1997 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1998 programName, appData.boardSize);
2002 /* Find some defaults; use the nearest known size */
2003 SizeDefaults *szd, *nearest;
2004 int distance = 99999;
2005 nearest = szd = sizeDefaults;
2006 while (szd->name != NULL) {
2007 if (abs(szd->squareSize - squareSize) < distance) {
2009 distance = abs(szd->squareSize - squareSize);
2010 if (distance == 0) break;
2014 if (i < 2) lineGap = nearest->lineGap;
2015 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
2016 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
2017 if (i < 5) fontPxlSize = nearest->fontPxlSize;
2018 if (i < 6) smallLayout = nearest->smallLayout;
2019 if (i < 7) tinyLayout = nearest->tinyLayout;
2022 SizeDefaults *szd = sizeDefaults;
2023 if (*appData.boardSize == NULLCHAR) {
2024 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
2025 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
2028 if (szd->name == NULL) szd--;
2029 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
2031 while (szd->name != NULL &&
2032 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
2033 if (szd->name == NULL) {
2034 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
2035 programName, appData.boardSize);
2039 squareSize = szd->squareSize;
2040 lineGap = szd->lineGap;
2041 clockFontPxlSize = szd->clockFontPxlSize;
2042 coordFontPxlSize = szd->coordFontPxlSize;
2043 fontPxlSize = szd->fontPxlSize;
2044 smallLayout = szd->smallLayout;
2045 tinyLayout = szd->tinyLayout;
2046 // [HGM] font: use defaults from settings file if available and not overruled
2048 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
2049 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
2050 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
2051 appData.font = fontTable[MESSAGE_FONT][squareSize];
2052 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
2053 appData.coordFont = fontTable[COORD_FONT][squareSize];
2055 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
2056 if (strlen(appData.pixmapDirectory) > 0) {
2057 p = ExpandPathName(appData.pixmapDirectory);
2059 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
2060 appData.pixmapDirectory);
2063 if (appData.debugMode) {
2064 fprintf(stderr, _("\
2065 XBoard square size (hint): %d\n\
2066 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
2068 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
2069 if (appData.debugMode) {
2070 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
2073 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
2075 /* [HR] height treated separately (hacked) */
2076 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
2077 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
2078 if (appData.showJail == 1) {
2079 /* Jail on top and bottom */
2080 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2081 XtSetArg(boardArgs[2], XtNheight,
2082 boardHeight + 2*(lineGap + squareSize));
2083 } else if (appData.showJail == 2) {
2085 XtSetArg(boardArgs[1], XtNwidth,
2086 boardWidth + 2*(lineGap + squareSize));
2087 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2090 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2091 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2095 * Determine what fonts to use.
2097 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2098 clockFontID = XLoadFont(xDisplay, appData.clockFont);
2099 clockFontStruct = XQueryFont(xDisplay, clockFontID);
2100 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2101 coordFontID = XLoadFont(xDisplay, appData.coordFont);
2102 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2103 appData.font = FindFont(appData.font, fontPxlSize);
2104 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
2105 countFontStruct = XQueryFont(xDisplay, countFontID);
2106 // appData.font = FindFont(appData.font, fontPxlSize);
2108 xdb = XtDatabase(xDisplay);
2109 XrmPutStringResource(&xdb, "*font", appData.font);
2112 * Detect if there are not enough colors available and adapt.
2114 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2115 appData.monoMode = True;
2118 forceMono = MakeColors();
2121 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2124 if (appData.bitmapDirectory == NULL ||
2125 appData.bitmapDirectory[0] == NULLCHAR)
2126 appData.bitmapDirectory = DEF_BITMAP_DIR;
2129 if (appData.lowTimeWarning && !appData.monoMode) {
2130 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2131 vFrom.size = strlen(appData.lowTimeWarningColor);
2132 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2133 if (vTo.addr == NULL)
2134 appData.monoMode = True;
2136 lowTimeWarningColor = *(Pixel *) vTo.addr;
2139 if (appData.monoMode && appData.debugMode) {
2140 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2141 (unsigned long) XWhitePixel(xDisplay, xScreen),
2142 (unsigned long) XBlackPixel(xDisplay, xScreen));
2145 ParseIcsTextColors();
2146 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2147 textColors[ColorNone].attr = 0;
2149 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2155 layoutName = "tinyLayout";
2156 } else if (smallLayout) {
2157 layoutName = "smallLayout";
2159 layoutName = "normalLayout";
2161 /* Outer layoutWidget is there only to provide a name for use in
2162 resources that depend on the layout style */
2164 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2165 layoutArgs, XtNumber(layoutArgs));
2167 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2168 formArgs, XtNumber(formArgs));
2169 XtSetArg(args[0], XtNdefaultDistance, &sep);
2170 XtGetValues(formWidget, args, 1);
2173 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2174 XtSetArg(args[0], XtNtop, XtChainTop);
2175 XtSetArg(args[1], XtNbottom, XtChainTop);
2176 XtSetArg(args[2], XtNright, XtChainLeft);
2177 XtSetValues(menuBarWidget, args, 3);
2179 widgetList[j++] = whiteTimerWidget =
2180 XtCreateWidget("whiteTime", labelWidgetClass,
2181 formWidget, timerArgs, XtNumber(timerArgs));
2182 XtSetArg(args[0], XtNfont, clockFontStruct);
2183 XtSetArg(args[1], XtNtop, XtChainTop);
2184 XtSetArg(args[2], XtNbottom, XtChainTop);
2185 XtSetValues(whiteTimerWidget, args, 3);
2187 widgetList[j++] = blackTimerWidget =
2188 XtCreateWidget("blackTime", labelWidgetClass,
2189 formWidget, timerArgs, XtNumber(timerArgs));
2190 XtSetArg(args[0], XtNfont, clockFontStruct);
2191 XtSetArg(args[1], XtNtop, XtChainTop);
2192 XtSetArg(args[2], XtNbottom, XtChainTop);
2193 XtSetValues(blackTimerWidget, args, 3);
2195 if (appData.titleInWindow) {
2196 widgetList[j++] = titleWidget =
2197 XtCreateWidget("title", labelWidgetClass, formWidget,
2198 titleArgs, XtNumber(titleArgs));
2199 XtSetArg(args[0], XtNtop, XtChainTop);
2200 XtSetArg(args[1], XtNbottom, XtChainTop);
2201 XtSetValues(titleWidget, args, 2);
2204 if (appData.showButtonBar) {
2205 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2206 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2207 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2208 XtSetArg(args[2], XtNtop, XtChainTop);
2209 XtSetArg(args[3], XtNbottom, XtChainTop);
2210 XtSetValues(buttonBarWidget, args, 4);
2213 widgetList[j++] = messageWidget =
2214 XtCreateWidget("message", labelWidgetClass, formWidget,
2215 messageArgs, XtNumber(messageArgs));
2216 XtSetArg(args[0], XtNtop, XtChainTop);
2217 XtSetArg(args[1], XtNbottom, XtChainTop);
2218 XtSetValues(messageWidget, args, 2);
2220 widgetList[j++] = boardWidget =
2221 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2222 XtNumber(boardArgs));
2224 XtManageChildren(widgetList, j);
2226 timerWidth = (boardWidth - sep) / 2;
2227 XtSetArg(args[0], XtNwidth, timerWidth);
2228 XtSetValues(whiteTimerWidget, args, 1);
2229 XtSetValues(blackTimerWidget, args, 1);
2231 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2232 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2233 XtGetValues(whiteTimerWidget, args, 2);
2235 if (appData.showButtonBar) {
2236 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2237 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2238 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2242 * formWidget uses these constraints but they are stored
2246 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2247 XtSetValues(menuBarWidget, args, i);
2248 if (appData.titleInWindow) {
2251 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2252 XtSetValues(whiteTimerWidget, args, i);
2254 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2255 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2256 XtSetValues(blackTimerWidget, args, i);
2258 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2259 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2260 XtSetValues(titleWidget, args, i);
2262 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2263 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2264 XtSetValues(messageWidget, args, i);
2265 if (appData.showButtonBar) {
2267 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2268 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2269 XtSetValues(buttonBarWidget, args, i);
2273 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2274 XtSetValues(whiteTimerWidget, args, i);
2276 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2277 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2278 XtSetValues(blackTimerWidget, args, i);
2280 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2281 XtSetValues(titleWidget, args, i);
2283 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2284 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2285 XtSetValues(messageWidget, args, i);
2286 if (appData.showButtonBar) {
2288 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2289 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2290 XtSetValues(buttonBarWidget, args, i);
2295 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2296 XtSetValues(whiteTimerWidget, args, i);
2298 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2299 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2300 XtSetValues(blackTimerWidget, args, i);
2302 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2303 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2304 XtSetValues(messageWidget, args, i);
2305 if (appData.showButtonBar) {
2307 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2308 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2309 XtSetValues(buttonBarWidget, args, i);
2313 XtSetArg(args[0], XtNfromVert, messageWidget);
2314 XtSetArg(args[1], XtNtop, XtChainTop);
2315 XtSetArg(args[2], XtNbottom, XtChainBottom);
2316 XtSetArg(args[3], XtNleft, XtChainLeft);
2317 XtSetArg(args[4], XtNright, XtChainRight);
2318 XtSetValues(boardWidget, args, 5);
2320 XtRealizeWidget(shellWidget);
2323 XtSetArg(args[0], XtNx, wpMain.x);
2324 XtSetArg(args[1], XtNy, wpMain.y);
2325 XtSetValues(shellWidget, args, 2);
2329 * Correct the width of the message and title widgets.
2330 * It is not known why some systems need the extra fudge term.
2331 * The value "2" is probably larger than needed.
2333 XawFormDoLayout(formWidget, False);
2335 #define WIDTH_FUDGE 2
2337 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2338 XtSetArg(args[i], XtNheight, &h); i++;
2339 XtGetValues(messageWidget, args, i);
2340 if (appData.showButtonBar) {
2342 XtSetArg(args[i], XtNwidth, &w); i++;
2343 XtGetValues(buttonBarWidget, args, i);
2344 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2346 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2349 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2350 if (gres != XtGeometryYes && appData.debugMode) {
2351 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2352 programName, gres, w, h, wr, hr);
2355 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2356 /* The size used for the child widget in layout lags one resize behind
2357 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2359 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2360 if (gres != XtGeometryYes && appData.debugMode) {
2361 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2362 programName, gres, w, h, wr, hr);
2365 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2366 XtSetArg(args[1], XtNright, XtChainRight);
2367 XtSetValues(messageWidget, args, 2);
2369 if (appData.titleInWindow) {
2371 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2372 XtSetArg(args[i], XtNheight, &h); i++;
2373 XtGetValues(titleWidget, args, i);
2375 w = boardWidth - 2*bor;
2377 XtSetArg(args[0], XtNwidth, &w);
2378 XtGetValues(menuBarWidget, args, 1);
2379 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2382 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2383 if (gres != XtGeometryYes && appData.debugMode) {
2385 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2386 programName, gres, w, h, wr, hr);
2389 XawFormDoLayout(formWidget, True);
2391 xBoardWindow = XtWindow(boardWidget);
2393 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2394 // not need to go into InitDrawingSizes().
2398 * Create X checkmark bitmap and initialize option menu checks.
2400 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2401 checkmark_bits, checkmark_width, checkmark_height);
2402 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2403 if (appData.alwaysPromoteToQueen) {
2404 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2407 if (appData.animateDragging) {
2408 XtSetValues(XtNameToWidget(menuBarWidget,
2409 "menuOptions.Animate Dragging"),
2412 if (appData.animate) {
2413 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2416 if (appData.autoCallFlag) {
2417 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2420 if (appData.autoFlipView) {
2421 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2424 if (appData.blindfold) {
2425 XtSetValues(XtNameToWidget(menuBarWidget,
2426 "menuOptions.Blindfold"), args, 1);
2428 if (appData.flashCount > 0) {
2429 XtSetValues(XtNameToWidget(menuBarWidget,
2430 "menuOptions.Flash Moves"),
2434 if (appData.highlightDragging) {
2435 XtSetValues(XtNameToWidget(menuBarWidget,
2436 "menuOptions.Highlight Dragging"),
2440 if (appData.highlightLastMove) {
2441 XtSetValues(XtNameToWidget(menuBarWidget,
2442 "menuOptions.Highlight Last Move"),
2445 if (appData.highlightMoveWithArrow) {
2446 XtSetValues(XtNameToWidget(menuBarWidget,
2447 "menuOptions.Arrow"),
2450 // if (appData.icsAlarm) {
2451 // XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2454 if (appData.ringBellAfterMoves) {
2455 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2458 if (appData.oneClick) {
2459 XtSetValues(XtNameToWidget(menuBarWidget,
2460 "menuOptions.OneClick"), args, 1);
2462 if (appData.periodicUpdates) {
2463 XtSetValues(XtNameToWidget(menuBarWidget,
2464 "menuOptions.Periodic Updates"), args, 1);
2466 if (appData.ponderNextMove) {
2467 XtSetValues(XtNameToWidget(menuBarWidget,
2468 "menuOptions.Ponder Next Move"), args, 1);
2470 if (appData.popupExitMessage) {
2471 XtSetValues(XtNameToWidget(menuBarWidget,
2472 "menuOptions.Popup Exit Message"), args, 1);
2474 if (appData.popupMoveErrors) {
2475 XtSetValues(XtNameToWidget(menuBarWidget,
2476 "menuOptions.Popup Move Errors"), args, 1);
2478 // if (appData.premove) {
2479 // XtSetValues(XtNameToWidget(menuBarWidget,
2480 // "menuOptions.Premove"), args, 1);
2482 if (appData.showCoords) {
2483 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2486 if (appData.hideThinkingFromHuman) {
2487 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2490 if (appData.testLegality) {
2491 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2494 if (saveSettingsOnExit) {
2495 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2502 ReadBitmap(&wIconPixmap, "icon_white.bm",
2503 icon_white_bits, icon_white_width, icon_white_height);
2504 ReadBitmap(&bIconPixmap, "icon_black.bm",
2505 icon_black_bits, icon_black_width, icon_black_height);
2506 iconPixmap = wIconPixmap;
2508 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2509 XtSetValues(shellWidget, args, i);
2512 * Create a cursor for the board widget.
2514 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2515 XChangeWindowAttributes(xDisplay, xBoardWindow,
2516 CWCursor, &window_attributes);
2519 * Inhibit shell resizing.
2521 shellArgs[0].value = (XtArgVal) &w;
2522 shellArgs[1].value = (XtArgVal) &h;
2523 XtGetValues(shellWidget, shellArgs, 2);
2524 shellArgs[4].value = shellArgs[2].value = w;
2525 shellArgs[5].value = shellArgs[3].value = h;
2526 XtSetValues(shellWidget, &shellArgs[2], 4);
2527 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2528 marginH = h - boardHeight;
2530 CatchDeleteWindow(shellWidget, "QuitProc");
2535 if (appData.bitmapDirectory[0] != NULLCHAR) {
2539 CreateXPMBoard(appData.liteBackTextureFile, 1);
2540 CreateXPMBoard(appData.darkBackTextureFile, 0);
2544 /* Create regular pieces */
2545 if (!useImages) CreatePieces();
2550 if (appData.animate || appData.animateDragging)
2553 XtAugmentTranslations(formWidget,
2554 XtParseTranslationTable(globalTranslations));
2555 XtAugmentTranslations(boardWidget,
2556 XtParseTranslationTable(boardTranslations));
2557 XtAugmentTranslations(whiteTimerWidget,
2558 XtParseTranslationTable(whiteTranslations));
2559 XtAugmentTranslations(blackTimerWidget,
2560 XtParseTranslationTable(blackTranslations));
2562 /* Why is the following needed on some versions of X instead
2563 * of a translation? */
2564 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2565 (XtEventHandler) EventProc, NULL);
2568 /* [AS] Restore layout */
2569 if( wpMoveHistory.visible ) {
2573 if( wpEvalGraph.visible )
2578 if( wpEngineOutput.visible ) {
2579 EngineOutputPopUp();
2584 if (errorExitStatus == -1) {
2585 if (appData.icsActive) {
2586 /* We now wait until we see "login:" from the ICS before
2587 sending the logon script (problems with timestamp otherwise) */
2588 /*ICSInitScript();*/
2589 if (appData.icsInputBox) ICSInputBoxPopUp();
2593 signal(SIGWINCH, TermSizeSigHandler);
2595 signal(SIGINT, IntSigHandler);
2596 signal(SIGTERM, IntSigHandler);
2597 if (*appData.cmailGameName != NULLCHAR) {
2598 signal(SIGUSR1, CmailSigHandler);
2601 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2603 XtSetKeyboardFocus(shellWidget, formWidget);
2605 XtAppMainLoop(appContext);
2606 if (appData.debugMode) fclose(debugFP); // [DM] debug
2613 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2614 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2616 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2617 unlink(gameCopyFilename);
2618 unlink(gamePasteFilename);
2621 RETSIGTYPE TermSizeSigHandler(int sig)
2634 CmailSigHandler(sig)
2640 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2642 /* Activate call-back function CmailSigHandlerCallBack() */
2643 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2645 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2649 CmailSigHandlerCallBack(isr, closure, message, count, error)
2657 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2659 /**** end signal code ****/
2665 /* try to open the icsLogon script, either in the location given
2666 * or in the users HOME directory
2673 f = fopen(appData.icsLogon, "r");
2676 homedir = getenv("HOME");
2677 if (homedir != NULL)
2679 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2680 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2681 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2682 f = fopen(buf, "r");
2687 ProcessICSInitScript(f);
2689 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2698 EditCommentPopDown();
2713 if (!menuBarWidget) return;
2714 w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2716 DisplayError("menuEdit.Revert", 0);
2718 XtSetSensitive(w, !grey);
2720 w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2722 DisplayError("menuEdit.Annotate", 0);
2724 XtSetSensitive(w, !grey);
2729 SetMenuEnables(enab)
2733 if (!menuBarWidget) return;
2734 while (enab->name != NULL) {
2735 w = XtNameToWidget(menuBarWidget, enab->name);
2737 DisplayError(enab->name, 0);
2739 XtSetSensitive(w, enab->value);
2745 Enables icsEnables[] = {
2746 { "menuFile.Mail Move", False },
2747 { "menuFile.Reload CMail Message", False },
2748 { "menuMode.Machine Black", False },
2749 { "menuMode.Machine White", False },
2750 { "menuMode.Analysis Mode", False },
2751 { "menuMode.Analyze File", False },
2752 { "menuMode.Two Machines", False },
2754 { "menuEngine.Hint", False },
2755 { "menuEngine.Book", False },
2756 { "menuEngine.Move Now", False },
2757 { "menuOptions.Periodic Updates", False },
2758 { "menuOptions.Hide Thinking", False },
2759 { "menuOptions.Ponder Next Move", False },
2760 { "menuEngine.Engine #1 Settings", False },
2762 { "menuEngine.Engine #2 Settings", False },
2763 { "menuEdit.Annotate", False },
2767 Enables ncpEnables[] = {
2768 { "menuFile.Mail Move", False },
2769 { "menuFile.Reload CMail Message", False },
2770 { "menuMode.Machine White", False },
2771 { "menuMode.Machine Black", False },
2772 { "menuMode.Analysis Mode", False },
2773 { "menuMode.Analyze File", False },
2774 { "menuMode.Two Machines", False },
2775 { "menuMode.ICS Client", False },
2776 { "menuView.ICS Input Box", False },
2777 { "Action", False },
2778 { "menuEdit.Revert", False },
2779 { "menuEdit.Annotate", False },
2780 { "menuEngine.Engine #1 Settings", False },
2781 { "menuEngine.Engine #2 Settings", False },
2782 { "menuEngine.Move Now", False },
2783 { "menuEngine.Retract Move", False },
2784 { "menuOptions.Auto Flag", False },
2785 { "menuOptions.Auto Flip View", False },
2786 { "menuOptions.ICS", False },
2787 // { "menuOptions.ICS Alarm", False },
2788 { "menuOptions.Move Sound", False },
2789 { "menuOptions.Hide Thinking", False },
2790 { "menuOptions.Periodic Updates", False },
2791 { "menuOptions.Ponder Next Move", False },
2792 { "menuEngine.Hint", False },
2793 { "menuEngine.Book", False },
2797 Enables gnuEnables[] = {
2798 { "menuMode.ICS Client", False },
2799 { "menuView.ICS Input Box", False },
2800 { "menuAction.Accept", False },
2801 { "menuAction.Decline", False },
2802 { "menuAction.Rematch", False },
2803 { "menuAction.Adjourn", False },
2804 { "menuAction.Stop Examining", False },
2805 { "menuAction.Stop Observing", False },
2806 { "menuAction.Upload to Examine", False },
2807 { "menuEdit.Revert", False },
2808 { "menuEdit.Annotate", False },
2809 { "menuOptions.ICS", False },
2811 /* The next two options rely on SetCmailMode being called *after* */
2812 /* SetGNUMode so that when GNU is being used to give hints these */
2813 /* menu options are still available */
2815 { "menuFile.Mail Move", False },
2816 { "menuFile.Reload CMail Message", False },
2820 Enables cmailEnables[] = {
2822 { "menuAction.Call Flag", False },
2823 { "menuAction.Draw", True },
2824 { "menuAction.Adjourn", False },
2825 { "menuAction.Abort", False },
2826 { "menuAction.Stop Observing", False },
2827 { "menuAction.Stop Examining", False },
2828 { "menuFile.Mail Move", True },
2829 { "menuFile.Reload CMail Message", True },
2833 Enables trainingOnEnables[] = {
2834 { "menuMode.Edit Comment", False },
2835 { "menuMode.Pause", False },
2836 { "menuEdit.Forward", False },
2837 { "menuEdit.Backward", False },
2838 { "menuEdit.Forward to End", False },
2839 { "menuEdit.Back to Start", False },
2840 { "menuEngine.Move Now", False },
2841 { "menuEdit.Truncate Game", False },
2845 Enables trainingOffEnables[] = {
2846 { "menuMode.Edit Comment", True },
2847 { "menuMode.Pause", True },
2848 { "menuEdit.Forward", True },
2849 { "menuEdit.Backward", True },
2850 { "menuEdit.Forward to End", True },
2851 { "menuEdit.Back to Start", True },
2852 { "menuEngine.Move Now", True },
2853 { "menuEdit.Truncate Game", True },
2857 Enables machineThinkingEnables[] = {
2858 { "menuFile.Load Game", False },
2859 // { "menuFile.Load Next Game", False },
2860 // { "menuFile.Load Previous Game", False },
2861 // { "menuFile.Reload Same Game", False },
2862 { "menuEdit.Paste Game", False },
2863 { "menuFile.Load Position", False },
2864 // { "menuFile.Load Next Position", False },
2865 // { "menuFile.Load Previous Position", False },
2866 // { "menuFile.Reload Same Position", False },
2867 { "menuEdit.Paste Position", False },
2868 { "menuMode.Machine White", False },
2869 { "menuMode.Machine Black", False },
2870 { "menuMode.Two Machines", False },
2871 { "menuEngine.Retract Move", False },
2875 Enables userThinkingEnables[] = {
2876 { "menuFile.Load Game", True },
2877 // { "menuFile.Load Next Game", True },
2878 // { "menuFile.Load Previous Game", True },
2879 // { "menuFile.Reload Same Game", True },
2880 { "menuEdit.Paste Game", True },
2881 { "menuFile.Load Position", True },
2882 // { "menuFile.Load Next Position", True },
2883 // { "menuFile.Load Previous Position", True },
2884 // { "menuFile.Reload Same Position", True },
2885 { "menuEdit.Paste Position", True },
2886 { "menuMode.Machine White", True },
2887 { "menuMode.Machine Black", True },
2888 { "menuMode.Two Machines", True },
2889 { "menuEngine.Retract Move", True },
2895 SetMenuEnables(icsEnables);
2898 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2899 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2906 SetMenuEnables(ncpEnables);
2912 SetMenuEnables(gnuEnables);
2918 SetMenuEnables(cmailEnables);
2924 SetMenuEnables(trainingOnEnables);
2925 if (appData.showButtonBar) {
2926 XtSetSensitive(buttonBarWidget, False);
2932 SetTrainingModeOff()
2934 SetMenuEnables(trainingOffEnables);
2935 if (appData.showButtonBar) {
2936 XtSetSensitive(buttonBarWidget, True);
2941 SetUserThinkingEnables()
2943 if (appData.noChessProgram) return;
2944 SetMenuEnables(userThinkingEnables);
2948 SetMachineThinkingEnables()
2950 if (appData.noChessProgram) return;
2951 SetMenuEnables(machineThinkingEnables);
2953 case MachinePlaysBlack:
2954 case MachinePlaysWhite:
2955 case TwoMachinesPlay:
2956 XtSetSensitive(XtNameToWidget(menuBarWidget,
2957 ModeToWidgetName(gameMode)), True);
2964 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2965 #define HISTORY_SIZE 64
2966 static char *history[HISTORY_SIZE];
2967 int histIn = 0, histP = 0;
2970 SaveInHistory(char *cmd)
2972 if (history[histIn] != NULL) {
2973 free(history[histIn]);
2974 history[histIn] = NULL;
2976 if (*cmd == NULLCHAR) return;
2977 history[histIn] = StrSave(cmd);
2978 histIn = (histIn + 1) % HISTORY_SIZE;
2979 if (history[histIn] != NULL) {
2980 free(history[histIn]);
2981 history[histIn] = NULL;
2987 PrevInHistory(char *cmd)
2990 if (histP == histIn) {
2991 if (history[histIn] != NULL) free(history[histIn]);
2992 history[histIn] = StrSave(cmd);
2994 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
2995 if (newhp == histIn || history[newhp] == NULL) return NULL;
2997 return history[histP];
3003 if (histP == histIn) return NULL;
3004 histP = (histP + 1) % HISTORY_SIZE;
3005 return history[histP];
3007 // end of borrowed code
3009 #define Abs(n) ((n)<0 ? -(n) : (n))
3012 * Find a font that matches "pattern" that is as close as
3013 * possible to the targetPxlSize. Prefer fonts that are k
3014 * pixels smaller to fonts that are k pixels larger. The
3015 * pattern must be in the X Consortium standard format,
3016 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3017 * The return value should be freed with XtFree when no
3021 FindFont(pattern, targetPxlSize)
3025 char **fonts, *p, *best, *scalable, *scalableTail;
3026 int i, j, nfonts, minerr, err, pxlSize;
3029 char **missing_list;
3031 char *def_string, *base_fnt_lst, strInt[3];
3033 XFontStruct **fnt_list;
3035 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3036 snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
3037 p = strstr(pattern, "--");
3038 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3039 strcat(base_fnt_lst, strInt);
3040 strcat(base_fnt_lst, strchr(p + 2, '-'));
3042 if ((fntSet = XCreateFontSet(xDisplay,
3046 &def_string)) == NULL) {
3048 fprintf(stderr, _("Unable to create font set.\n"));
3052 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3054 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3056 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3057 programName, pattern);
3065 for (i=0; i<nfonts; i++) {
3068 if (*p != '-') continue;
3070 if (*p == NULLCHAR) break;
3071 if (*p++ == '-') j++;
3073 if (j < 7) continue;
3076 scalable = fonts[i];
3079 err = pxlSize - targetPxlSize;
3080 if (Abs(err) < Abs(minerr) ||
3081 (minerr > 0 && err < 0 && -err == minerr)) {
3087 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3088 /* If the error is too big and there is a scalable font,
3089 use the scalable font. */
3090 int headlen = scalableTail - scalable;
3091 p = (char *) XtMalloc(strlen(scalable) + 10);
3092 while (isdigit(*scalableTail)) scalableTail++;
3093 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3095 p = (char *) XtMalloc(strlen(best) + 2);
3096 safeStrCpy(p, best, strlen(best)+1 );
3098 if (appData.debugMode) {
3099 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3100 pattern, targetPxlSize, p);
3103 if (missing_count > 0)
3104 XFreeStringList(missing_list);
3105 XFreeFontSet(xDisplay, fntSet);
3107 XFreeFontNames(fonts);
3113 { // [HGM] deletes GCs that are to be remade, to prevent resource leak;
3114 // must be called before all non-first callse to CreateGCs()
3115 XtReleaseGC(shellWidget, highlineGC);
3116 XtReleaseGC(shellWidget, lightSquareGC);
3117 XtReleaseGC(shellWidget, darkSquareGC);
3118 if (appData.monoMode) {
3119 if (DefaultDepth(xDisplay, xScreen) == 1) {
3120 XtReleaseGC(shellWidget, wbPieceGC);
3122 XtReleaseGC(shellWidget, bwPieceGC);
3125 XtReleaseGC(shellWidget, prelineGC);
3126 XtReleaseGC(shellWidget, jailSquareGC);
3127 XtReleaseGC(shellWidget, wdPieceGC);
3128 XtReleaseGC(shellWidget, wlPieceGC);
3129 XtReleaseGC(shellWidget, wjPieceGC);
3130 XtReleaseGC(shellWidget, bdPieceGC);
3131 XtReleaseGC(shellWidget, blPieceGC);
3132 XtReleaseGC(shellWidget, bjPieceGC);
3136 void CreateGCs(int redo)
3138 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3139 | GCBackground | GCFunction | GCPlaneMask;
3140 XGCValues gc_values;
3143 gc_values.plane_mask = AllPlanes;
3144 gc_values.line_width = lineGap;
3145 gc_values.line_style = LineSolid;
3146 gc_values.function = GXcopy;
3149 DeleteGCs(); // called a second time; clean up old GCs first
3150 } else { // [HGM] grid and font GCs created on first call only
3151 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3152 gc_values.background = XBlackPixel(xDisplay, xScreen);
3153 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3155 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3156 gc_values.background = XWhitePixel(xDisplay, xScreen);
3157 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3158 XSetFont(xDisplay, coordGC, coordFontID);
3160 // [HGM] make font for holdings counts (white on black)
3161 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3162 gc_values.background = XBlackPixel(xDisplay, xScreen);
3163 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3164 XSetFont(xDisplay, countGC, countFontID);
3166 if (appData.monoMode) {
3167 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3168 gc_values.background = XWhitePixel(xDisplay, xScreen);
3169 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3171 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3172 gc_values.background = XBlackPixel(xDisplay, xScreen);
3173 lightSquareGC = wbPieceGC
3174 = XtGetGC(shellWidget, value_mask, &gc_values);
3176 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3177 gc_values.background = XWhitePixel(xDisplay, xScreen);
3178 darkSquareGC = bwPieceGC
3179 = XtGetGC(shellWidget, value_mask, &gc_values);
3181 if (DefaultDepth(xDisplay, xScreen) == 1) {
3182 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3183 gc_values.function = GXcopyInverted;
3184 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3185 gc_values.function = GXcopy;
3186 if (XBlackPixel(xDisplay, xScreen) == 1) {
3187 bwPieceGC = darkSquareGC;
3188 wbPieceGC = copyInvertedGC;
3190 bwPieceGC = copyInvertedGC;
3191 wbPieceGC = lightSquareGC;
3195 gc_values.foreground = highlightSquareColor;
3196 gc_values.background = highlightSquareColor;
3197 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3199 gc_values.foreground = premoveHighlightColor;
3200 gc_values.background = premoveHighlightColor;
3201 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3203 gc_values.foreground = lightSquareColor;
3204 gc_values.background = darkSquareColor;
3205 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3207 gc_values.foreground = darkSquareColor;
3208 gc_values.background = lightSquareColor;
3209 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3211 gc_values.foreground = jailSquareColor;
3212 gc_values.background = jailSquareColor;
3213 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3215 gc_values.foreground = whitePieceColor;
3216 gc_values.background = darkSquareColor;
3217 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3219 gc_values.foreground = whitePieceColor;
3220 gc_values.background = lightSquareColor;
3221 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3223 gc_values.foreground = whitePieceColor;
3224 gc_values.background = jailSquareColor;
3225 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3227 gc_values.foreground = blackPieceColor;
3228 gc_values.background = darkSquareColor;
3229 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3231 gc_values.foreground = blackPieceColor;
3232 gc_values.background = lightSquareColor;
3233 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3235 gc_values.foreground = blackPieceColor;
3236 gc_values.background = jailSquareColor;
3237 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3241 void loadXIM(xim, xmask, filename, dest, mask)
3254 fp = fopen(filename, "rb");
3256 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3263 for (y=0; y<h; ++y) {
3264 for (x=0; x<h; ++x) {
3269 XPutPixel(xim, x, y, blackPieceColor);
3271 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3274 XPutPixel(xim, x, y, darkSquareColor);
3276 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3279 XPutPixel(xim, x, y, whitePieceColor);
3281 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3284 XPutPixel(xim, x, y, lightSquareColor);
3286 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3294 /* create Pixmap of piece */
3295 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3297 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3300 /* create Pixmap of clipmask
3301 Note: We assume the white/black pieces have the same
3302 outline, so we make only 6 masks. This is okay
3303 since the XPM clipmask routines do the same. */
3305 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3307 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3310 /* now create the 1-bit version */
3311 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3314 values.foreground = 1;
3315 values.background = 0;
3317 /* Don't use XtGetGC, not read only */
3318 maskGC = XCreateGC(xDisplay, *mask,
3319 GCForeground | GCBackground, &values);
3320 XCopyPlane(xDisplay, temp, *mask, maskGC,
3321 0, 0, squareSize, squareSize, 0, 0, 1);
3322 XFreePixmap(xDisplay, temp);
3327 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3329 void CreateXIMPieces()
3334 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3339 /* The XSynchronize calls were copied from CreatePieces.
3340 Not sure if needed, but can't hurt */
3341 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3344 /* temp needed by loadXIM() */
3345 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3346 0, 0, ss, ss, AllPlanes, XYPixmap);
3348 if (strlen(appData.pixmapDirectory) == 0) {
3352 if (appData.monoMode) {
3353 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3357 fprintf(stderr, _("\nLoading XIMs...\n"));
3359 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3360 fprintf(stderr, "%d", piece+1);
3361 for (kind=0; kind<4; kind++) {
3362 fprintf(stderr, ".");
3363 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3364 ExpandPathName(appData.pixmapDirectory),
3365 piece <= (int) WhiteKing ? "" : "w",
3366 pieceBitmapNames[piece],
3368 ximPieceBitmap[kind][piece] =
3369 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3370 0, 0, ss, ss, AllPlanes, XYPixmap);
3371 if (appData.debugMode)
3372 fprintf(stderr, _("(File:%s:) "), buf);
3373 loadXIM(ximPieceBitmap[kind][piece],
3375 &(xpmPieceBitmap2[kind][piece]),
3376 &(ximMaskPm2[piece]));
3377 if(piece <= (int)WhiteKing)
3378 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3380 fprintf(stderr," ");
3382 /* Load light and dark squares */
3383 /* If the LSQ and DSQ pieces don't exist, we will
3384 draw them with solid squares. */
3385 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3386 if (access(buf, 0) != 0) {
3390 fprintf(stderr, _("light square "));
3392 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3393 0, 0, ss, ss, AllPlanes, XYPixmap);
3394 if (appData.debugMode)
3395 fprintf(stderr, _("(File:%s:) "), buf);
3397 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3398 fprintf(stderr, _("dark square "));
3399 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3400 ExpandPathName(appData.pixmapDirectory), ss);
3401 if (appData.debugMode)
3402 fprintf(stderr, _("(File:%s:) "), buf);
3404 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3405 0, 0, ss, ss, AllPlanes, XYPixmap);
3406 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3407 xpmJailSquare = xpmLightSquare;
3409 fprintf(stderr, _("Done.\n"));
3411 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3415 void CreateXPMBoard(char *s, int kind)
3419 if(s == NULL || *s == 0 || *s == '*') { useTexture &= ~(kind+1); return; }
3420 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3421 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3425 void FreeXPMPieces()
3426 { // [HGM] to prevent resoucre leak on calling CreaeXPMPieces() a second time,
3427 // thisroutine has to be called t free the old piece pixmaps
3429 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++)
3430 for (kind=0; kind<4; kind++) XFreePixmap(xDisplay, xpmPieceBitmap2[kind][piece]);
3432 XFreePixmap(xDisplay, xpmLightSquare);
3433 XFreePixmap(xDisplay, xpmDarkSquare);
3437 void CreateXPMPieces()
3441 u_int ss = squareSize;
3443 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3444 XpmColorSymbol symbols[4];
3445 static int redo = False;
3447 if(redo) FreeXPMPieces(); else redo = 1;
3449 /* The XSynchronize calls were copied from CreatePieces.
3450 Not sure if needed, but can't hurt */
3451 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3453 /* Setup translations so piece colors match square colors */
3454 symbols[0].name = "light_piece";
3455 symbols[0].value = appData.whitePieceColor;
3456 symbols[1].name = "dark_piece";
3457 symbols[1].value = appData.blackPieceColor;
3458 symbols[2].name = "light_square";
3459 symbols[2].value = appData.lightSquareColor;
3460 symbols[3].name = "dark_square";
3461 symbols[3].value = appData.darkSquareColor;
3463 attr.valuemask = XpmColorSymbols;
3464 attr.colorsymbols = symbols;
3465 attr.numsymbols = 4;
3467 if (appData.monoMode) {
3468 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3472 if (strlen(appData.pixmapDirectory) == 0) {
3473 XpmPieces* pieces = builtInXpms;
3476 while (pieces->size != squareSize && pieces->size) pieces++;
3477 if (!pieces->size) {
3478 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3481 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3482 for (kind=0; kind<4; kind++) {
3484 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3485 pieces->xpm[piece][kind],
3486 &(xpmPieceBitmap2[kind][piece]),
3487 NULL, &attr)) != 0) {
3488 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3492 if(piece <= (int) WhiteKing)
3493 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3497 xpmJailSquare = xpmLightSquare;
3501 fprintf(stderr, _("\nLoading XPMs...\n"));
3504 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3505 fprintf(stderr, "%d ", piece+1);
3506 for (kind=0; kind<4; kind++) {
3507 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3508 ExpandPathName(appData.pixmapDirectory),
3509 piece > (int) WhiteKing ? "w" : "",
3510 pieceBitmapNames[piece],
3512 if (appData.debugMode) {
3513 fprintf(stderr, _("(File:%s:) "), buf);
3515 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3516 &(xpmPieceBitmap2[kind][piece]),
3517 NULL, &attr)) != 0) {
3518 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3519 // [HGM] missing: read of unorthodox piece failed; substitute King.
3520 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3521 ExpandPathName(appData.pixmapDirectory),
3523 if (appData.debugMode) {
3524 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3526 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3527 &(xpmPieceBitmap2[kind][piece]),
3531 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3536 if(piece <= (int) WhiteKing)
3537 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3540 /* Load light and dark squares */
3541 /* If the LSQ and DSQ pieces don't exist, we will
3542 draw them with solid squares. */
3543 fprintf(stderr, _("light square "));
3544 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3545 if (access(buf, 0) != 0) {
3549 if (appData.debugMode)
3550 fprintf(stderr, _("(File:%s:) "), buf);
3552 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3553 &xpmLightSquare, NULL, &attr)) != 0) {
3554 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3557 fprintf(stderr, _("dark square "));
3558 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3559 ExpandPathName(appData.pixmapDirectory), ss);
3560 if (appData.debugMode) {
3561 fprintf(stderr, _("(File:%s:) "), buf);
3563 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3564 &xpmDarkSquare, NULL, &attr)) != 0) {
3565 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3569 xpmJailSquare = xpmLightSquare;
3570 fprintf(stderr, _("Done.\n"));
3572 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3575 #endif /* HAVE_LIBXPM */
3578 /* No built-in bitmaps */
3583 u_int ss = squareSize;
3585 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3588 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3589 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3590 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3591 pieceBitmapNames[piece],
3592 ss, kind == SOLID ? 's' : 'o');
3593 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3594 if(piece <= (int)WhiteKing)
3595 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3599 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3603 /* With built-in bitmaps */
3606 BuiltInBits* bib = builtInBits;
3609 u_int ss = squareSize;
3611 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3614 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3616 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3617 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3618 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3619 pieceBitmapNames[piece],
3620 ss, kind == SOLID ? 's' : 'o');
3621 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3622 bib->bits[kind][piece], ss, ss);
3623 if(piece <= (int)WhiteKing)
3624 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3628 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3633 void ReadBitmap(pm, name, bits, wreq, hreq)
3636 unsigned char bits[];
3642 char msg[MSG_SIZ], fullname[MSG_SIZ];
3644 if (*appData.bitmapDirectory != NULLCHAR) {
3645 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3646 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3647 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3648 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3649 &w, &h, pm, &x_hot, &y_hot);
3650 fprintf(stderr, "load %s\n", name);
3651 if (errcode != BitmapSuccess) {
3653 case BitmapOpenFailed:
3654 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3656 case BitmapFileInvalid:
3657 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3659 case BitmapNoMemory:
3660 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3664 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3668 fprintf(stderr, _("%s: %s...using built-in\n"),
3670 } else if (w != wreq || h != hreq) {
3672 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3673 programName, fullname, w, h, wreq, hreq);
3679 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3688 if (lineGap == 0) return;
3690 /* [HR] Split this into 2 loops for non-square boards. */
3692 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3693 gridSegments[i].x1 = 0;
3694 gridSegments[i].x2 =
3695 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3696 gridSegments[i].y1 = gridSegments[i].y2
3697 = lineGap / 2 + (i * (squareSize + lineGap));
3700 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3701 gridSegments[j + i].y1 = 0;
3702 gridSegments[j + i].y2 =
3703 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3704 gridSegments[j + i].x1 = gridSegments[j + i].x2
3705 = lineGap / 2 + (j * (squareSize + lineGap));
3709 static void MenuBarSelect(w, addr, index)
3714 XtActionProc proc = (XtActionProc) addr;
3716 (proc)(NULL, NULL, NULL, NULL);
3719 void CreateMenuBarPopup(parent, name, mb)
3729 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3732 XtSetArg(args[j], XtNleftMargin, 20); j++;
3733 XtSetArg(args[j], XtNrightMargin, 20); j++;
3735 while (mi->string != NULL) {
3736 if (strcmp(mi->string, "----") == 0) {
3737 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3740 XtSetArg(args[j], XtNlabel, XtNewString(mi->string));
3741 entry = XtCreateManagedWidget(mi->ref, smeBSBObjectClass,
3743 XtAddCallback(entry, XtNcallback,
3744 (XtCallbackProc) MenuBarSelect,
3745 (caddr_t) mi->proc);
3751 Widget CreateMenuBar(mb)
3755 Widget anchor, menuBar;
3757 char menuName[MSG_SIZ];
3760 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3761 XtSetArg(args[j], XtNvSpace, 0); j++;
3762 XtSetArg(args[j], XtNborderWidth, 0); j++;
3763 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3764 formWidget, args, j);
3766 while (mb->name != NULL) {
3767 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3768 strncat(menuName, mb->ref, MSG_SIZ - strlen(menuName) - 1);
3770 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3773 shortName[0] = mb->name[0];
3774 shortName[1] = NULLCHAR;
3775 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3778 XtSetArg(args[j], XtNlabel, XtNewString(mb->name)); j++;
3781 XtSetArg(args[j], XtNborderWidth, 0); j++;
3782 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3784 CreateMenuBarPopup(menuBar, menuName, mb);
3790 Widget CreateButtonBar(mi)
3794 Widget button, buttonBar;
3798 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3800 XtSetArg(args[j], XtNhSpace, 0); j++;
3802 XtSetArg(args[j], XtNborderWidth, 0); j++;
3803 XtSetArg(args[j], XtNvSpace, 0); j++;
3804 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3805 formWidget, args, j);
3807 while (mi->string != NULL) {
3810 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3811 XtSetArg(args[j], XtNborderWidth, 0); j++;
3813 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3814 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3815 buttonBar, args, j);
3816 XtAddCallback(button, XtNcallback,
3817 (XtCallbackProc) MenuBarSelect,
3818 (caddr_t) mi->proc);
3825 CreatePieceMenu(name, color)
3832 ChessSquare selection;
3834 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3835 boardWidget, args, 0);
3837 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3838 String item = pieceMenuStrings[color][i];
3840 if (strcmp(item, "----") == 0) {
3841 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3844 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3845 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3847 selection = pieceMenuTranslation[color][i];
3848 XtAddCallback(entry, XtNcallback,
3849 (XtCallbackProc) PieceMenuSelect,
3850 (caddr_t) selection);
3851 if (selection == WhitePawn || selection == BlackPawn) {
3852 XtSetArg(args[0], XtNpopupOnEntry, entry);
3853 XtSetValues(menu, args, 1);
3866 ChessSquare selection;
3868 whitePieceMenu = CreatePieceMenu("menuW", 0);
3869 blackPieceMenu = CreatePieceMenu("menuB", 1);
3871 XtRegisterGrabAction(PieceMenuPopup, True,
3872 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3873 GrabModeAsync, GrabModeAsync);
3875 XtSetArg(args[0], XtNlabel, _("Drop"));
3876 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3877 boardWidget, args, 1);
3878 for (i = 0; i < DROP_MENU_SIZE; i++) {
3879 String item = dropMenuStrings[i];
3881 if (strcmp(item, "----") == 0) {
3882 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3885 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3886 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3888 selection = dropMenuTranslation[i];
3889 XtAddCallback(entry, XtNcallback,
3890 (XtCallbackProc) DropMenuSelect,
3891 (caddr_t) selection);
3896 void SetupDropMenu()
3904 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3905 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3906 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3907 dmEnables[i].piece);
3908 XtSetSensitive(entry, p != NULL || !appData.testLegality
3909 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3910 && !appData.icsActive));
3912 while (p && *p++ == dmEnables[i].piece) count++;
3913 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3915 XtSetArg(args[j], XtNlabel, label); j++;
3916 XtSetValues(entry, args, j);
3920 void PieceMenuPopup(w, event, params, num_params)
3924 Cardinal *num_params;
3926 String whichMenu; int menuNr;
3927 if (event->type == ButtonRelease)
3928 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3929 else if (event->type == ButtonPress)
3930 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3932 case 0: whichMenu = params[0]; break;
3933 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3935 case -1: if (errorUp) ErrorPopDown();
3938 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3941 static void PieceMenuSelect(w, piece, junk)
3946 if (pmFromX < 0 || pmFromY < 0) return;
3947 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3950 static void DropMenuSelect(w, piece, junk)
3955 if (pmFromX < 0 || pmFromY < 0) return;
3956 DropMenuEvent(piece, pmFromX, pmFromY);
3959 void WhiteClock(w, event, prms, nprms)
3968 void BlackClock(w, event, prms, nprms)
3979 * If the user selects on a border boundary, return -1; if off the board,
3980 * return -2. Otherwise map the event coordinate to the square.
3982 int EventToSquare(x, limit)
3990 if ((x % (squareSize + lineGap)) >= squareSize)
3992 x /= (squareSize + lineGap);
3998 static void do_flash_delay(msec)
4004 static void drawHighlight(file, rank, gc)
4010 if (lineGap == 0) return;
4013 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
4014 (squareSize + lineGap);
4015 y = lineGap/2 + rank * (squareSize + lineGap);
4017 x = lineGap/2 + file * (squareSize + lineGap);
4018 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
4019 (squareSize + lineGap);
4022 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
4023 squareSize+lineGap, squareSize+lineGap);
4026 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
4027 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4030 SetHighlights(fromX, fromY, toX, toY)
4031 int fromX, fromY, toX, toY;
4033 if (hi1X != fromX || hi1Y != fromY) {
4034 if (hi1X >= 0 && hi1Y >= 0) {
4035 drawHighlight(hi1X, hi1Y, lineGC);
4037 } // [HGM] first erase both, then draw new!
4038 if (hi2X != toX || hi2Y != toY) {
4039 if (hi2X >= 0 && hi2Y >= 0) {
4040 drawHighlight(hi2X, hi2Y, lineGC);
4043 if (hi1X != fromX || hi1Y != fromY) {
4044 if (fromX >= 0 && fromY >= 0) {
4045 drawHighlight(fromX, fromY, highlineGC);
4048 if (hi2X != toX || hi2Y != toY) {
4049 if (toX >= 0 && toY >= 0) {
4050 drawHighlight(toX, toY, highlineGC);
4062 SetHighlights(-1, -1, -1, -1);
4067 SetPremoveHighlights(fromX, fromY, toX, toY)
4068 int fromX, fromY, toX, toY;
4070 if (pm1X != fromX || pm1Y != fromY) {
4071 if (pm1X >= 0 && pm1Y >= 0) {
4072 drawHighlight(pm1X, pm1Y, lineGC);
4074 if (fromX >= 0 && fromY >= 0) {
4075 drawHighlight(fromX, fromY, prelineGC);
4078 if (pm2X != toX || pm2Y != toY) {
4079 if (pm2X >= 0 && pm2Y >= 0) {
4080 drawHighlight(pm2X, pm2Y, lineGC);
4082 if (toX >= 0 && toY >= 0) {
4083 drawHighlight(toX, toY, prelineGC);
4093 ClearPremoveHighlights()
4095 SetPremoveHighlights(-1, -1, -1, -1);
4098 static int CutOutSquare(x, y, x0, y0, kind)
4099 int x, y, *x0, *y0, kind;
4101 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
4102 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
4104 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
4105 if(textureW[kind] < W*squareSize)
4106 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
4108 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
4109 if(textureH[kind] < H*squareSize)
4110 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
4112 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
4116 static void BlankSquare(x, y, color, piece, dest, fac)
4117 int x, y, color, fac;
4120 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
4122 if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
4123 XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
4124 squareSize, squareSize, x*fac, y*fac);
4126 if (useImages && useImageSqs) {
4130 pm = xpmLightSquare;
4135 case 2: /* neutral */
4140 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4141 squareSize, squareSize, x*fac, y*fac);
4151 case 2: /* neutral */
4156 XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
4161 I split out the routines to draw a piece so that I could
4162 make a generic flash routine.
4164 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4166 int square_color, x, y;
4169 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4170 switch (square_color) {
4172 case 2: /* neutral */
4174 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4175 ? *pieceToOutline(piece)
4176 : *pieceToSolid(piece),
4177 dest, bwPieceGC, 0, 0,
4178 squareSize, squareSize, x, y);
4181 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4182 ? *pieceToSolid(piece)
4183 : *pieceToOutline(piece),
4184 dest, wbPieceGC, 0, 0,
4185 squareSize, squareSize, x, y);
4190 static void monoDrawPiece(piece, square_color, x, y, dest)
4192 int square_color, x, y;
4195 switch (square_color) {
4197 case 2: /* neutral */
4199 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4200 ? *pieceToOutline(piece)
4201 : *pieceToSolid(piece),
4202 dest, bwPieceGC, 0, 0,
4203 squareSize, squareSize, x, y, 1);
4206 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4207 ? *pieceToSolid(piece)
4208 : *pieceToOutline(piece),
4209 dest, wbPieceGC, 0, 0,
4210 squareSize, squareSize, x, y, 1);
4215 static void colorDrawPiece(piece, square_color, x, y, dest)
4217 int square_color, x, y;
4220 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4221 switch (square_color) {
4223 XCopyPlane(xDisplay, *pieceToSolid(piece),
4224 dest, (int) piece < (int) BlackPawn
4225 ? wlPieceGC : blPieceGC, 0, 0,
4226 squareSize, squareSize, x, y, 1);
4229 XCopyPlane(xDisplay, *pieceToSolid(piece),
4230 dest, (int) piece < (int) BlackPawn
4231 ? wdPieceGC : bdPieceGC, 0, 0,
4232 squareSize, squareSize, x, y, 1);
4234 case 2: /* neutral */
4236 XCopyPlane(xDisplay, *pieceToSolid(piece),
4237 dest, (int) piece < (int) BlackPawn
4238 ? wjPieceGC : bjPieceGC, 0, 0,
4239 squareSize, squareSize, x, y, 1);
4244 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4246 int square_color, x, y;
4249 int kind, p = piece;
4251 switch (square_color) {
4253 case 2: /* neutral */
4255 if ((int)piece < (int) BlackPawn) {
4263 if ((int)piece < (int) BlackPawn) {
4271 if(appData.upsideDown && flipView) { kind ^= 2; p += p < BlackPawn ? BlackPawn : -BlackPawn; }// swap white and black pieces
4272 if(useTexture & square_color+1) {
4273 BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
4274 XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
4275 XSetClipOrigin(xDisplay, wlPieceGC, x, y);
4276 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);
4277 XSetClipMask(xDisplay, wlPieceGC, None);
4278 XSetClipOrigin(xDisplay, wlPieceGC, 0, 0);
4280 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4281 dest, wlPieceGC, 0, 0,
4282 squareSize, squareSize, x, y);
4285 typedef void (*DrawFunc)();
4287 DrawFunc ChooseDrawFunc()
4289 if (appData.monoMode) {
4290 if (DefaultDepth(xDisplay, xScreen) == 1) {
4291 return monoDrawPiece_1bit;
4293 return monoDrawPiece;
4297 return colorDrawPieceImage;
4299 return colorDrawPiece;
4303 /* [HR] determine square color depending on chess variant. */
4304 static int SquareColor(row, column)
4309 if (gameInfo.variant == VariantXiangqi) {
4310 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4312 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4314 } else if (row <= 4) {
4320 square_color = ((column + row) % 2) == 1;
4323 /* [hgm] holdings: next line makes all holdings squares light */
4324 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4326 return square_color;
4329 void DrawSquare(row, column, piece, do_flash)
4330 int row, column, do_flash;
4333 int square_color, x, y, direction, font_ascent, font_descent;
4336 XCharStruct overall;
4340 /* Calculate delay in milliseconds (2-delays per complete flash) */
4341 flash_delay = 500 / appData.flashRate;
4344 x = lineGap + ((BOARD_WIDTH-1)-column) *
4345 (squareSize + lineGap);
4346 y = lineGap + row * (squareSize + lineGap);
4348 x = lineGap + column * (squareSize + lineGap);
4349 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4350 (squareSize + lineGap);
4353 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4355 square_color = SquareColor(row, column);
4357 if ( // [HGM] holdings: blank out area between board and holdings
4358 column == BOARD_LEFT-1 || column == BOARD_RGHT
4359 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4360 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4361 BlankSquare(x, y, 2, EmptySquare, xBoardWindow, 1);
4363 // [HGM] print piece counts next to holdings
4364 string[1] = NULLCHAR;
4365 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4366 string[0] = '0' + piece;
4367 XTextExtents(countFontStruct, string, 1, &direction,
4368 &font_ascent, &font_descent, &overall);
4369 if (appData.monoMode) {
4370 XDrawImageString(xDisplay, xBoardWindow, countGC,
4371 x + squareSize - overall.width - 2,
4372 y + font_ascent + 1, string, 1);
4374 XDrawString(xDisplay, xBoardWindow, countGC,
4375 x + squareSize - overall.width - 2,
4376 y + font_ascent + 1, string, 1);
4379 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4380 string[0] = '0' + piece;
4381 XTextExtents(countFontStruct, string, 1, &direction,
4382 &font_ascent, &font_descent, &overall);
4383 if (appData.monoMode) {
4384 XDrawImageString(xDisplay, xBoardWindow, countGC,
4385 x + 2, y + font_ascent + 1, string, 1);
4387 XDrawString(xDisplay, xBoardWindow, countGC,
4388 x + 2, y + font_ascent + 1, string, 1);
4392 if (piece == EmptySquare || appData.blindfold) {
4393 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4395 drawfunc = ChooseDrawFunc();
4396 if (do_flash && appData.flashCount > 0) {
4397 for (i=0; i<appData.flashCount; ++i) {
4399 drawfunc(piece, square_color, x, y, xBoardWindow);
4400 XSync(xDisplay, False);
4401 do_flash_delay(flash_delay);
4403 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4404 XSync(xDisplay, False);
4405 do_flash_delay(flash_delay);
4408 drawfunc(piece, square_color, x, y, xBoardWindow);
4412 string[1] = NULLCHAR;
4413 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4414 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4415 string[0] = 'a' + column - BOARD_LEFT;
4416 XTextExtents(coordFontStruct, string, 1, &direction,
4417 &font_ascent, &font_descent, &overall);
4418 if (appData.monoMode) {
4419 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4420 x + squareSize - overall.width - 2,
4421 y + squareSize - font_descent - 1, string, 1);
4423 XDrawString(xDisplay, xBoardWindow, coordGC,
4424 x + squareSize - overall.width - 2,
4425 y + squareSize - font_descent - 1, string, 1);
4428 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4429 string[0] = ONE + row;
4430 XTextExtents(coordFontStruct, string, 1, &direction,
4431 &font_ascent, &font_descent, &overall);
4432 if (appData.monoMode) {
4433 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4434 x + 2, y + font_ascent + 1, string, 1);
4436 XDrawString(xDisplay, xBoardWindow, coordGC,
4437 x + 2, y + font_ascent + 1, string, 1);
4440 if(!partnerUp && marker[row][column]) {
4441 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4442 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4447 /* Why is this needed on some versions of X? */
4448 void EventProc(widget, unused, event)
4453 if (!XtIsRealized(widget))
4456 switch (event->type) {
4458 if (event->xexpose.count > 0) return; /* no clipping is done */
4459 XDrawPosition(widget, True, NULL);
4460 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4461 flipView = !flipView; partnerUp = !partnerUp;
4462 XDrawPosition(widget, True, NULL);
4463 flipView = !flipView; partnerUp = !partnerUp;
4467 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
4474 void DrawPosition(fullRedraw, board)
4475 /*Boolean*/int fullRedraw;
4478 XDrawPosition(boardWidget, fullRedraw, board);
4481 /* Returns 1 if there are "too many" differences between b1 and b2
4482 (i.e. more than 1 move was made) */
4483 static int too_many_diffs(b1, b2)
4489 for (i=0; i<BOARD_HEIGHT; ++i) {
4490 for (j=0; j<BOARD_WIDTH; ++j) {
4491 if (b1[i][j] != b2[i][j]) {
4492 if (++c > 4) /* Castling causes 4 diffs */
4501 /* Matrix describing castling maneuvers */
4502 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4503 static int castling_matrix[4][5] = {
4504 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4505 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4506 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4507 { 7, 7, 4, 5, 6 } /* 0-0, black */
4510 /* Checks whether castling occurred. If it did, *rrow and *rcol
4511 are set to the destination (row,col) of the rook that moved.
4513 Returns 1 if castling occurred, 0 if not.
4515 Note: Only handles a max of 1 castling move, so be sure
4516 to call too_many_diffs() first.
4518 static int check_castle_draw(newb, oldb, rrow, rcol)
4525 /* For each type of castling... */
4526 for (i=0; i<4; ++i) {
4527 r = castling_matrix[i];
4529 /* Check the 4 squares involved in the castling move */
4531 for (j=1; j<=4; ++j) {
4532 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4539 /* All 4 changed, so it must be a castling move */
4548 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4549 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4551 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4554 void DrawSeekBackground( int left, int top, int right, int bottom )
4556 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4559 void DrawSeekText(char *buf, int x, int y)
4561 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4564 void DrawSeekDot(int x, int y, int colorNr)
4566 int square = colorNr & 0x80;
4569 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4571 XFillRectangle(xDisplay, xBoardWindow, color,
4572 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4574 XFillArc(xDisplay, xBoardWindow, color,
4575 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4578 static int damage[2][BOARD_RANKS][BOARD_FILES];
4581 * event handler for redrawing the board
4583 void XDrawPosition(w, repaint, board)
4585 /*Boolean*/int repaint;
4589 static int lastFlipView = 0;
4590 static int lastBoardValid[2] = {0, 0};
4591 static Board lastBoard[2];
4594 int nr = twoBoards*partnerUp;
4596 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4598 if (board == NULL) {
4599 if (!lastBoardValid[nr]) return;
4600 board = lastBoard[nr];
4602 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4603 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4604 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Flip View"),
4609 * It would be simpler to clear the window with XClearWindow()
4610 * but this causes a very distracting flicker.
4613 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4615 if ( lineGap && IsDrawArrowEnabled())
4616 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4617 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4619 /* If too much changes (begin observing new game, etc.), don't
4621 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4623 /* Special check for castling so we don't flash both the king
4624 and the rook (just flash the king). */
4626 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4627 /* Draw rook with NO flashing. King will be drawn flashing later */
4628 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4629 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4633 /* First pass -- Draw (newly) empty squares and repair damage.
4634 This prevents you from having a piece show up twice while it
4635 is flashing on its new square */
4636 for (i = 0; i < BOARD_HEIGHT; i++)
4637 for (j = 0; j < BOARD_WIDTH; j++)
4638 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4639 || damage[nr][i][j]) {
4640 DrawSquare(i, j, board[i][j], 0);
4641 damage[nr][i][j] = False;
4644 /* Second pass -- Draw piece(s) in new position and flash them */
4645 for (i = 0; i < BOARD_HEIGHT; i++)
4646 for (j = 0; j < BOARD_WIDTH; j++)
4647 if (board[i][j] != lastBoard[nr][i][j]) {
4648 DrawSquare(i, j, board[i][j], do_flash);
4652 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4653 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4654 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4656 for (i = 0; i < BOARD_HEIGHT; i++)
4657 for (j = 0; j < BOARD_WIDTH; j++) {
4658 DrawSquare(i, j, board[i][j], 0);
4659 damage[nr][i][j] = False;
4663 CopyBoard(lastBoard[nr], board);
4664 lastBoardValid[nr] = 1;
4665 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4666 lastFlipView = flipView;
4668 /* Draw highlights */
4669 if (pm1X >= 0 && pm1Y >= 0) {
4670 drawHighlight(pm1X, pm1Y, prelineGC);
4672 if (pm2X >= 0 && pm2Y >= 0) {
4673 drawHighlight(pm2X, pm2Y, prelineGC);
4675 if (hi1X >= 0 && hi1Y >= 0) {
4676 drawHighlight(hi1X, hi1Y, highlineGC);
4678 if (hi2X >= 0 && hi2Y >= 0) {
4679 drawHighlight(hi2X, hi2Y, highlineGC);
4681 DrawArrowHighlight(hi1X, hi1Y, hi2X, hi2Y);
4683 /* If piece being dragged around board, must redraw that too */
4686 XSync(xDisplay, False);
4691 * event handler for redrawing the board
4693 void DrawPositionProc(w, event, prms, nprms)
4699 XDrawPosition(w, True, NULL);
4704 * event handler for parsing user moves
4706 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4707 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4708 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4709 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4710 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4711 // and at the end FinishMove() to perform the move after optional promotion popups.
4712 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4713 void HandleUserMove(w, event, prms, nprms)
4719 if (w != boardWidget || errorExitStatus != -1) return;
4720 if(nprms) shiftKey = !strcmp(prms[0], "1");
4723 if (event->type == ButtonPress) {
4724 XtPopdown(promotionShell);
4725 XtDestroyWidget(promotionShell);
4726 promotionUp = False;
4734 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4735 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4736 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4739 void AnimateUserMove (Widget w, XEvent * event,
4740 String * params, Cardinal * nParams)
4742 DragPieceMove(event->xmotion.x, event->xmotion.y);
4745 void HandlePV (Widget w, XEvent * event,
4746 String * params, Cardinal * nParams)
4747 { // [HGM] pv: walk PV
4748 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4751 Widget CommentCreate(name, text, mutable, callback, lines)
4753 int /*Boolean*/ mutable;
4754 XtCallbackProc callback;
4758 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4763 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4764 XtGetValues(boardWidget, args, j);
4767 XtSetArg(args[j], XtNresizable, True); j++;
4770 XtCreatePopupShell(name, topLevelShellWidgetClass,
4771 shellWidget, args, j);
4774 XtCreatePopupShell(name, transientShellWidgetClass,
4775 shellWidget, args, j);
4778 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4779 layoutArgs, XtNumber(layoutArgs));
4781 XtCreateManagedWidget("form", formWidgetClass, layout,
4782 formArgs, XtNumber(formArgs));
4786 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4787 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4789 XtSetArg(args[j], XtNstring, text); j++;
4790 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4791 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4792 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4793 XtSetArg(args[j], XtNright, XtChainRight); j++;
4794 XtSetArg(args[j], XtNresizable, True); j++;
4795 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4796 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4797 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4798 XtSetArg(args[j], XtNautoFill, True); j++;
4799 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4801 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4802 XtOverrideTranslations(edit, XtParseTranslationTable(commentTranslations));
4806 XtSetArg(args[j], XtNfromVert, edit); j++;
4807 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4808 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4809 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4810 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4812 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4813 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4816 XtSetArg(args[j], XtNfromVert, edit); j++;
4817 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4818 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4819 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4820 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4821 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4823 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4824 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4827 XtSetArg(args[j], XtNfromVert, edit); j++;
4828 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4829 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4830 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4831 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4832 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4834 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4835 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4838 XtSetArg(args[j], XtNfromVert, edit); j++;
4839 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4840 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4841 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4842 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4844 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4845 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4848 XtSetArg(args[j], XtNfromVert, edit); j++;
4849 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4850 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4851 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4852 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4853 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4855 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4856 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4859 XtRealizeWidget(shell);
4861 if (commentX == -1) {
4864 Dimension pw_height;
4865 Dimension ew_height;
4868 XtSetArg(args[j], XtNheight, &ew_height); j++;
4869 XtGetValues(edit, args, j);
4872 XtSetArg(args[j], XtNheight, &pw_height); j++;
4873 XtGetValues(shell, args, j);
4874 commentH = pw_height + (lines - 1) * ew_height;
4875 commentW = bw_width - 16;
4877 XSync(xDisplay, False);
4879 /* This code seems to tickle an X bug if it is executed too soon
4880 after xboard starts up. The coordinates get transformed as if
4881 the main window was positioned at (0, 0).
4883 XtTranslateCoords(shellWidget,
4884 (bw_width - commentW) / 2, 0 - commentH / 2,
4885 &commentX, &commentY);
4887 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4888 RootWindowOfScreen(XtScreen(shellWidget)),
4889 (bw_width - commentW) / 2, 0 - commentH / 2,
4894 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4897 if(wpComment.width > 0) {
4898 commentX = wpComment.x;
4899 commentY = wpComment.y;
4900 commentW = wpComment.width;
4901 commentH = wpComment.height;
4905 XtSetArg(args[j], XtNheight, commentH); j++;
4906 XtSetArg(args[j], XtNwidth, commentW); j++;
4907 XtSetArg(args[j], XtNx, commentX); j++;
4908 XtSetArg(args[j], XtNy, commentY); j++;
4909 XtSetValues(shell, args, j);
4910 XtSetKeyboardFocus(shell, edit);
4915 /* Used for analysis window and ICS input window */
4916 Widget MiscCreate(name, text, mutable, callback, lines)
4918 int /*Boolean*/ mutable;
4919 XtCallbackProc callback;
4923 Widget shell, layout, form, edit;
4925 Dimension bw_width, pw_height, ew_height, w, h;
4931 XtSetArg(args[j], XtNresizable, True); j++;
4934 XtCreatePopupShell(name, topLevelShellWidgetClass,
4935 shellWidget, args, j);
4938 XtCreatePopupShell(name, transientShellWidgetClass,
4939 shellWidget, args, j);
4942 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4943 layoutArgs, XtNumber(layoutArgs));
4945 XtCreateManagedWidget("form", formWidgetClass, layout,
4946 formArgs, XtNumber(formArgs));
4950 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4951 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4953 XtSetArg(args[j], XtNstring, text); j++;
4954 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4955 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4956 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4957 XtSetArg(args[j], XtNright, XtChainRight); j++;
4958 XtSetArg(args[j], XtNresizable, True); j++;
4959 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4960 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4961 XtSetArg(args[j], XtNautoFill, True); j++;
4962 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4964 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4966 XtRealizeWidget(shell);
4969 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4970 XtGetValues(boardWidget, args, j);
4973 XtSetArg(args[j], XtNheight, &ew_height); j++;
4974 XtGetValues(edit, args, j);
4977 XtSetArg(args[j], XtNheight, &pw_height); j++;
4978 XtGetValues(shell, args, j);
4979 h = pw_height + (lines - 1) * ew_height;
4982 XSync(xDisplay, False);
4984 /* This code seems to tickle an X bug if it is executed too soon
4985 after xboard starts up. The coordinates get transformed as if
4986 the main window was positioned at (0, 0).
4988 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4990 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4991 RootWindowOfScreen(XtScreen(shellWidget)),
4992 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4996 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4999 XtSetArg(args[j], XtNheight, h); j++;
5000 XtSetArg(args[j], XtNwidth, w); j++;
5001 XtSetArg(args[j], XtNx, x); j++;
5002 XtSetArg(args[j], XtNy, y); j++;
5003 XtSetValues(shell, args, j);
5009 static int savedIndex; /* gross that this is global */
5011 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
5014 XawTextPosition index, dummy;
5017 XawTextGetSelectionPos(w, &index, &dummy);
5018 XtSetArg(arg, XtNstring, &val);
5019 XtGetValues(w, &arg, 1);
5020 ReplaceComment(savedIndex, val);
5021 if(savedIndex != currentMove) ToNrEvent(savedIndex);
5022 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
5025 void EditCommentPopUp(index, title, text)
5034 if (text == NULL) text = "";
5036 if (editShell == NULL) {
5038 CommentCreate(title, text, True, EditCommentCallback, 4);
5039 XtRealizeWidget(editShell);
5040 CatchDeleteWindow(editShell, "EditCommentPopDown");
5042 edit = XtNameToWidget(editShell, "*form.text");
5044 XtSetArg(args[j], XtNstring, text); j++;
5045 XtSetValues(edit, args, j);
5047 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5048 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5049 XtSetValues(editShell, args, j);
5052 XtPopup(editShell, XtGrabNone);
5056 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5057 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"),
5059 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"),
5063 void EditCommentCallback(w, client_data, call_data)
5065 XtPointer client_data, call_data;
5073 XtSetArg(args[j], XtNlabel, &name); j++;
5074 XtGetValues(w, args, j);
5076 if (strcmp(name, _("ok")) == 0) {
5077 edit = XtNameToWidget(editShell, "*form.text");
5079 XtSetArg(args[j], XtNstring, &val); j++;
5080 XtGetValues(edit, args, j);
5081 ReplaceComment(savedIndex, val);
5082 EditCommentPopDown();
5083 } else if (strcmp(name, _("cancel")) == 0) {
5084 EditCommentPopDown();
5085 } else if (strcmp(name, _("clear")) == 0) {
5086 edit = XtNameToWidget(editShell, "*form.text");
5087 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5088 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5092 void EditCommentPopDown()
5097 if (!editUp) return;
5099 XtSetArg(args[j], XtNx, &commentX); j++;
5100 XtSetArg(args[j], XtNy, &commentY); j++;
5101 XtSetArg(args[j], XtNheight, &commentH); j++;
5102 XtSetArg(args[j], XtNwidth, &commentW); j++;
5103 XtGetValues(editShell, args, j);
5104 XtPopdown(editShell);
5107 XtSetArg(args[j], XtNleftBitmap, None); j++;
5108 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"),
5110 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"),
5114 void ICSInputBoxPopUp()
5119 char *title = _("ICS Input");
5122 if (ICSInputShell == NULL) {
5123 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
5124 tr = XtParseTranslationTable(ICSInputTranslations);
5125 edit = XtNameToWidget(ICSInputShell, "*form.text");
5126 XtOverrideTranslations(edit, tr);
5127 XtRealizeWidget(ICSInputShell);
5128 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
5131 edit = XtNameToWidget(ICSInputShell, "*form.text");
5133 XtSetArg(args[j], XtNstring, ""); j++;
5134 XtSetValues(edit, args, j);
5136 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5137 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5138 XtSetValues(ICSInputShell, args, j);
5141 XtPopup(ICSInputShell, XtGrabNone);
5142 XtSetKeyboardFocus(ICSInputShell, edit);
5144 ICSInputBoxUp = True;
5146 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5147 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.ICS Input Box"),
5151 void ICSInputSendText()
5158 edit = XtNameToWidget(ICSInputShell, "*form.text");
5160 XtSetArg(args[j], XtNstring, &val); j++;
5161 XtGetValues(edit, args, j);
5163 SendMultiLineToICS(val);
5164 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5165 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5168 void ICSInputBoxPopDown()
5173 if (!ICSInputBoxUp) return;
5175 XtPopdown(ICSInputShell);
5176 ICSInputBoxUp = False;
5178 XtSetArg(args[j], XtNleftBitmap, None); j++;
5179 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.ICS Input Box"),
5183 void CommentPopUp(title, text)
5190 savedIndex = currentMove; // [HGM] vari
5191 if (commentShell == NULL) {
5193 CommentCreate(title, text, False, CommentCallback, 4);
5194 XtRealizeWidget(commentShell);
5195 CatchDeleteWindow(commentShell, "CommentPopDown");
5197 edit = XtNameToWidget(commentShell, "*form.text");
5199 XtSetArg(args[j], XtNstring, text); j++;
5200 XtSetValues(edit, args, j);
5202 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5203 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5204 XtSetValues(commentShell, args, j);
5207 XtPopup(commentShell, XtGrabNone);
5208 XSync(xDisplay, False);
5213 void CommentCallback(w, client_data, call_data)
5215 XtPointer client_data, call_data;
5222 XtSetArg(args[j], XtNlabel, &name); j++;
5223 XtGetValues(w, args, j);
5225 if (strcmp(name, _("close")) == 0) {
5227 } else if (strcmp(name, _("edit")) == 0) {
5234 void CommentPopDown()
5239 if (!commentUp) return;
5241 XtSetArg(args[j], XtNx, &commentX); j++;
5242 XtSetArg(args[j], XtNy, &commentY); j++;
5243 XtSetArg(args[j], XtNwidth, &commentW); j++;
5244 XtSetArg(args[j], XtNheight, &commentH); j++;
5245 XtGetValues(commentShell, args, j);
5246 XtPopdown(commentShell);
5247 XSync(xDisplay, False);
5251 void FileNamePopUp(label, def, proc, openMode)
5257 fileProc = proc; /* I can't see a way not */
5258 fileOpenMode = openMode; /* to use globals here */
5259 { // [HGM] use file-selector dialog stolen from Ghostview
5261 int index; // this is not supported yet
5263 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5264 def, openMode, NULL, &name))
5265 (void) (*fileProc)(f, index=0, name);
5269 void FileNamePopDown()
5271 if (!filenameUp) return;
5272 XtPopdown(fileNameShell);
5273 XtDestroyWidget(fileNameShell);
5278 void FileNameCallback(w, client_data, call_data)
5280 XtPointer client_data, call_data;
5285 XtSetArg(args[0], XtNlabel, &name);
5286 XtGetValues(w, args, 1);
5288 if (strcmp(name, _("cancel")) == 0) {
5293 FileNameAction(w, NULL, NULL, NULL);
5296 void FileNameAction(w, event, prms, nprms)
5308 name = XawDialogGetValueString(w = XtParent(w));
5310 if ((name != NULL) && (*name != NULLCHAR)) {
5311 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
5312 XtPopdown(w = XtParent(XtParent(w)));
5316 p = strrchr(buf, ' ');
5323 fullname = ExpandPathName(buf);
5325 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5328 f = fopen(fullname, fileOpenMode);
5330 DisplayError(_("Failed to open file"), errno);
5332 (void) (*fileProc)(f, index, buf);
5339 XtPopdown(w = XtParent(XtParent(w)));
5345 void PromotionPopUp()
5348 Widget dialog, layout;
5350 Dimension bw_width, pw_width;
5354 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5355 XtGetValues(boardWidget, args, j);
5358 XtSetArg(args[j], XtNresizable, True); j++;
5359 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5361 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5362 shellWidget, args, j);
5364 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5365 layoutArgs, XtNumber(layoutArgs));
5368 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5369 XtSetArg(args[j], XtNborderWidth, 0); j++;
5370 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5373 if(gameInfo.variant != VariantShogi) {
5374 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) {
5375 XawDialogAddButton(dialog, _("Warlord"), PromotionCallback,
5376 (XtPointer) dialog);
5377 XawDialogAddButton(dialog, _("General"), PromotionCallback,
5378 (XtPointer) dialog);
5379 XawDialogAddButton(dialog, _("Lieutenant"), PromotionCallback,
5380 (XtPointer) dialog);
5381 XawDialogAddButton(dialog, _("Captain"), PromotionCallback,
5382 (XtPointer) dialog);
5384 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5385 (XtPointer) dialog);
5386 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5387 (XtPointer) dialog);
5388 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5389 (XtPointer) dialog);
5390 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5391 (XtPointer) dialog);
5393 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5394 gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
\r
5395 gameInfo.variant == VariantGiveaway) {
5396 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5397 (XtPointer) dialog);
5399 if(gameInfo.variant == VariantCapablanca ||
5400 gameInfo.variant == VariantGothic ||
5401 gameInfo.variant == VariantCapaRandom) {
5402 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5403 (XtPointer) dialog);
5404 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5405 (XtPointer) dialog);
5407 } else // [HGM] shogi
5409 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5410 (XtPointer) dialog);
5411 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5412 (XtPointer) dialog);
5414 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5415 (XtPointer) dialog);
5417 XtRealizeWidget(promotionShell);
5418 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5421 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5422 XtGetValues(promotionShell, args, j);
5424 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5425 lineGap + squareSize/3 +
5426 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5427 0 : 6*(squareSize + lineGap)), &x, &y);
5430 XtSetArg(args[j], XtNx, x); j++;
5431 XtSetArg(args[j], XtNy, y); j++;
5432 XtSetValues(promotionShell, args, j);
5434 XtPopup(promotionShell, XtGrabNone);
5439 void PromotionPopDown()
5441 if (!promotionUp) return;
5442 XtPopdown(promotionShell);
5443 XtDestroyWidget(promotionShell);
5444 promotionUp = False;
5447 void PromotionCallback(w, client_data, call_data)
5449 XtPointer client_data, call_data;
5455 XtSetArg(args[0], XtNlabel, &name);
5456 XtGetValues(w, args, 1);
5460 if (fromX == -1) return;
5462 if (strcmp(name, _("cancel")) == 0) {
5466 } else if (strcmp(name, _("Knight")) == 0) {
5468 } else if (strcmp(name, _("Promote")) == 0) {
5470 } else if (strcmp(name, _("Defer")) == 0) {
5473 promoChar = ToLower(name[0]);
5476 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5478 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5479 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5484 void ErrorCallback(w, client_data, call_data)
5486 XtPointer client_data, call_data;
5489 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5491 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5497 if (!errorUp) return;
5499 XtPopdown(errorShell);
5500 XtDestroyWidget(errorShell);
5501 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5504 void ErrorPopUp(title, label, modal)
5505 char *title, *label;
5509 Widget dialog, layout;
5513 Dimension bw_width, pw_width;
5514 Dimension pw_height;
5518 XtSetArg(args[i], XtNresizable, True); i++;
5519 XtSetArg(args[i], XtNtitle, title); i++;
5521 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5522 shellWidget, args, i);
5524 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5525 layoutArgs, XtNumber(layoutArgs));
5528 XtSetArg(args[i], XtNlabel, label); i++;
5529 XtSetArg(args[i], XtNborderWidth, 0); i++;
5530 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5533 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5535 XtRealizeWidget(errorShell);
5536 CatchDeleteWindow(errorShell, "ErrorPopDown");
5539 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5540 XtGetValues(boardWidget, args, i);
5542 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5543 XtSetArg(args[i], XtNheight, &pw_height); i++;
5544 XtGetValues(errorShell, args, i);
5547 /* This code seems to tickle an X bug if it is executed too soon
5548 after xboard starts up. The coordinates get transformed as if
5549 the main window was positioned at (0, 0).
5551 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5552 0 - pw_height + squareSize / 3, &x, &y);
5554 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5555 RootWindowOfScreen(XtScreen(boardWidget)),
5556 (bw_width - pw_width) / 2,
5557 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5561 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5564 XtSetArg(args[i], XtNx, x); i++;
5565 XtSetArg(args[i], XtNy, y); i++;
5566 XtSetValues(errorShell, args, i);
5569 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5572 /* Disable all user input other than deleting the window */
5573 static int frozen = 0;
5577 /* Grab by a widget that doesn't accept input */
5578 XtAddGrab(messageWidget, TRUE, FALSE);
5582 /* Undo a FreezeUI */
5585 if (!frozen) return;
5586 XtRemoveGrab(messageWidget);
5590 char *ModeToWidgetName(mode)
5594 case BeginningOfGame:
5595 if (appData.icsActive)
5596 return "menuMode.ICS Client";
5597 else if (appData.noChessProgram ||
5598 *appData.cmailGameName != NULLCHAR)
5599 return "menuMode.Edit Game";
5601 return "menuMode.Machine Black";
5602 case MachinePlaysBlack:
5603 return "menuMode.Machine Black";
5604 case MachinePlaysWhite:
5605 return "menuMode.Machine White";
5607 return "menuMode.Analysis Mode";
5609 return "menuMode.Analyze File";
5610 case TwoMachinesPlay:
5611 return "menuMode.Two Machines";
5613 return "menuMode.Edit Game";
5614 case PlayFromGameFile:
5615 return "menuFile.Load Game";
5617 return "menuMode.Edit Position";
5619 return "menuMode.Training";
5620 case IcsPlayingWhite:
5621 case IcsPlayingBlack:
5625 return "menuMode.ICS Client";
5632 void ModeHighlight()
5635 static int oldPausing = FALSE;
5636 static GameMode oldmode = (GameMode) -1;
5639 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5641 if (pausing != oldPausing) {
5642 oldPausing = pausing;
5644 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5646 XtSetArg(args[0], XtNleftBitmap, None);
5648 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5651 if (appData.showButtonBar) {
5652 /* Always toggle, don't set. Previous code messes up when
5653 invoked while the button is pressed, as releasing it
5654 toggles the state again. */
5657 XtSetArg(args[0], XtNbackground, &oldbg);
5658 XtSetArg(args[1], XtNforeground, &oldfg);
5659 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5661 XtSetArg(args[0], XtNbackground, oldfg);
5662 XtSetArg(args[1], XtNforeground, oldbg);
5664 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5668 wname = ModeToWidgetName(oldmode);
5669 if (wname != NULL) {
5670 XtSetArg(args[0], XtNleftBitmap, None);
5671 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5673 wname = ModeToWidgetName(gameMode);
5674 if (wname != NULL) {
5675 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5676 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5680 /* Maybe all the enables should be handled here, not just this one */
5681 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5682 gameMode == Training || gameMode == PlayFromGameFile);
5687 * Button/menu procedures
5689 void ResetProc(w, event, prms, nprms)
5698 int LoadGamePopUp(f, gameNumber, title)
5703 cmailMsgLoaded = FALSE;
5704 if (gameNumber == 0) {
5705 int error = GameListBuild(f);
5707 DisplayError(_("Cannot build game list"), error);
5708 } else if (!ListEmpty(&gameList) &&
5709 ((ListGame *) gameList.tailPred)->number > 1) {
5710 GameListPopUp(f, title);
5716 return LoadGame(f, gameNumber, title, FALSE);
5719 void LoadGameProc(w, event, prms, nprms)
5725 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5728 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5731 void LoadNextGameProc(w, event, prms, nprms)
5740 void LoadPrevGameProc(w, event, prms, nprms)
5749 void ReloadGameProc(w, event, prms, nprms)
5758 void LoadNextPositionProc(w, event, prms, nprms)
5767 void LoadPrevPositionProc(w, event, prms, nprms)
5776 void ReloadPositionProc(w, event, prms, nprms)
5785 void LoadPositionProc(w, event, prms, nprms)
5791 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5794 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5797 void SaveGameProc(w, event, prms, nprms)
5803 FileNamePopUp(_("Save game file name?"),
5804 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5808 void SavePositionProc(w, event, prms, nprms)
5814 FileNamePopUp(_("Save position file name?"),
5815 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5819 void ReloadCmailMsgProc(w, event, prms, nprms)
5825 ReloadCmailMsgEvent(FALSE);
5828 void MailMoveProc(w, event, prms, nprms)
5837 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5838 char *selected_fen_position=NULL;
5841 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5842 Atom *type_return, XtPointer *value_return,
5843 unsigned long *length_return, int *format_return)
5845 char *selection_tmp;
5847 if (!selected_fen_position) return False; /* should never happen */
5848 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5849 /* note: since no XtSelectionDoneProc was registered, Xt will
5850 * automatically call XtFree on the value returned. So have to
5851 * make a copy of it allocated with XtMalloc */
5852 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5853 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
5855 *value_return=selection_tmp;
5856 *length_return=strlen(selection_tmp);
5857 *type_return=*target;
5858 *format_return = 8; /* bits per byte */
5860 } else if (*target == XA_TARGETS(xDisplay)) {
5861 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5862 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5863 targets_tmp[1] = XA_STRING;
5864 *value_return = targets_tmp;
5865 *type_return = XA_ATOM;
5867 *format_return = 8 * sizeof(Atom);
5868 if (*format_return > 32) {
5869 *length_return *= *format_return / 32;
5870 *format_return = 32;
5878 /* note: when called from menu all parameters are NULL, so no clue what the
5879 * Widget which was clicked on was, or what the click event was
5881 void CopyPositionProc(w, event, prms, nprms)
5888 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5889 * have a notion of a position that is selected but not copied.
5890 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5892 if(gameMode == EditPosition) EditPositionDone(TRUE);
5893 if (selected_fen_position) free(selected_fen_position);
5894 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5895 if (!selected_fen_position) return;
5896 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5898 SendPositionSelection,
5899 NULL/* lose_ownership_proc */ ,
5900 NULL/* transfer_done_proc */);
5901 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5903 SendPositionSelection,
5904 NULL/* lose_ownership_proc */ ,
5905 NULL/* transfer_done_proc */);
5908 /* function called when the data to Paste is ready */
5910 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5911 Atom *type, XtPointer value, unsigned long *len, int *format)
5914 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5915 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5916 EditPositionPasteFEN(fenstr);
5920 /* called when Paste Position button is pressed,
5921 * all parameters will be NULL */
5922 void PastePositionProc(w, event, prms, nprms)
5928 XtGetSelectionValue(menuBarWidget,
5929 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5930 /* (XtSelectionCallbackProc) */ PastePositionCB,
5931 NULL, /* client_data passed to PastePositionCB */
5933 /* better to use the time field from the event that triggered the
5934 * call to this function, but that isn't trivial to get
5942 SendGameSelection(Widget w, Atom *selection, Atom *target,
5943 Atom *type_return, XtPointer *value_return,
5944 unsigned long *length_return, int *format_return)
5946 char *selection_tmp;
5948 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5949 FILE* f = fopen(gameCopyFilename, "r");
5952 if (f == NULL) return False;
5956 selection_tmp = XtMalloc(len + 1);
5957 count = fread(selection_tmp, 1, len, f);
5960 XtFree(selection_tmp);
5963 selection_tmp[len] = NULLCHAR;
5964 *value_return = selection_tmp;
5965 *length_return = len;
5966 *type_return = *target;
5967 *format_return = 8; /* bits per byte */
5969 } else if (*target == XA_TARGETS(xDisplay)) {
5970 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5971 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5972 targets_tmp[1] = XA_STRING;
5973 *value_return = targets_tmp;
5974 *type_return = XA_ATOM;
5976 *format_return = 8 * sizeof(Atom);
5977 if (*format_return > 32) {
5978 *length_return *= *format_return / 32;
5979 *format_return = 32;
5987 /* note: when called from menu all parameters are NULL, so no clue what the
5988 * Widget which was clicked on was, or what the click event was
5990 void CopyGameProc(w, event, prms, nprms)
5998 ret = SaveGameToFile(gameCopyFilename, FALSE);
6002 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
6003 * have a notion of a game that is selected but not copied.
6004 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
6006 XtOwnSelection(menuBarWidget, XA_PRIMARY,
6009 NULL/* lose_ownership_proc */ ,
6010 NULL/* transfer_done_proc */);
6011 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
6014 NULL/* lose_ownership_proc */ ,
6015 NULL/* transfer_done_proc */);
6018 /* function called when the data to Paste is ready */
6020 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
6021 Atom *type, XtPointer value, unsigned long *len, int *format)
6024 if (value == NULL || *len == 0) {
6025 return; /* nothing had been selected to copy */
6027 f = fopen(gamePasteFilename, "w");
6029 DisplayError(_("Can't open temp file"), errno);
6032 fwrite(value, 1, *len, f);
6035 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
6038 /* called when Paste Game button is pressed,
6039 * all parameters will be NULL */
6040 void PasteGameProc(w, event, prms, nprms)
6046 XtGetSelectionValue(menuBarWidget,
6047 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
6048 /* (XtSelectionCallbackProc) */ PasteGameCB,
6049 NULL, /* client_data passed to PasteGameCB */
6051 /* better to use the time field from the event that triggered the
6052 * call to this function, but that isn't trivial to get
6062 SaveGameProc(NULL, NULL, NULL, NULL);
6066 void QuitProc(w, event, prms, nprms)
6075 void PauseProc(w, event, prms, nprms)
6085 void MachineBlackProc(w, event, prms, nprms)
6091 MachineBlackEvent();
6094 void MachineWhiteProc(w, event, prms, nprms)
6100 MachineWhiteEvent();
6103 void AnalyzeModeProc(w, event, prms, nprms)
6111 if (!first.analysisSupport) {
6112 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6113 DisplayError(buf, 0);
6116 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
6117 if (appData.icsActive) {
6118 if (gameMode != IcsObserving) {
6119 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
6120 DisplayError(buf, 0);
6122 if (appData.icsEngineAnalyze) {
6123 if (appData.debugMode)
6124 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
6130 /* if enable, use want disable icsEngineAnalyze */
6131 if (appData.icsEngineAnalyze) {
6136 appData.icsEngineAnalyze = TRUE;
6137 if (appData.debugMode)
6138 fprintf(debugFP, _("ICS engine analyze starting... \n"));
6140 if (!appData.showThinking)
6141 ShowThinkingProc(w,event,prms,nprms);
6146 void AnalyzeFileProc(w, event, prms, nprms)
6152 if (!first.analysisSupport) {
6154 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6155 DisplayError(buf, 0);
6160 if (!appData.showThinking)
6161 ShowThinkingProc(w,event,prms,nprms);
6164 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
6165 AnalysisPeriodicEvent(1);
6168 void TwoMachinesProc(w, event, prms, nprms)
6177 void IcsClientProc(w, event, prms, nprms)
6186 void EditGameProc(w, event, prms, nprms)
6195 void EditPositionProc(w, event, prms, nprms)
6201 EditPositionEvent();
6204 void TrainingProc(w, event, prms, nprms)
6213 void EditCommentProc(w, event, prms, nprms)
6220 EditCommentPopDown();
6226 void IcsInputBoxProc(w, event, prms, nprms)
6232 if (ICSInputBoxUp) {
6233 ICSInputBoxPopDown();
6239 void AcceptProc(w, event, prms, nprms)
6248 void DeclineProc(w, event, prms, nprms)
6257 void RematchProc(w, event, prms, nprms)
6266 void CallFlagProc(w, event, prms, nprms)
6275 void DrawProc(w, event, prms, nprms)
6284 void AbortProc(w, event, prms, nprms)
6293 void AdjournProc(w, event, prms, nprms)
6302 void ResignProc(w, event, prms, nprms)
6311 void AdjuWhiteProc(w, event, prms, nprms)
6317 UserAdjudicationEvent(+1);
6320 void AdjuBlackProc(w, event, prms, nprms)
6326 UserAdjudicationEvent(-1);
6329 void AdjuDrawProc(w, event, prms, nprms)
6335 UserAdjudicationEvent(0);
6338 void EnterKeyProc(w, event, prms, nprms)
6344 if (ICSInputBoxUp == True)
6348 void UpKeyProc(w, event, prms, nprms)
6353 { // [HGM] input: let up-arrow recall previous line from history
6360 if (!ICSInputBoxUp) return;
6361 edit = XtNameToWidget(ICSInputShell, "*form.text");
6363 XtSetArg(args[j], XtNstring, &val); j++;
6364 XtGetValues(edit, args, j);
6365 val = PrevInHistory(val);
6366 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6367 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6369 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6370 XawTextReplace(edit, 0, 0, &t);
6371 XawTextSetInsertionPoint(edit, 9999);
6375 void DownKeyProc(w, event, prms, nprms)
6380 { // [HGM] input: let down-arrow recall next line from history
6385 if (!ICSInputBoxUp) return;
6386 edit = XtNameToWidget(ICSInputShell, "*form.text");
6387 val = NextInHistory();
6388 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6389 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6391 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6392 XawTextReplace(edit, 0, 0, &t);
6393 XawTextSetInsertionPoint(edit, 9999);
6397 void StopObservingProc(w, event, prms, nprms)
6403 StopObservingEvent();
6406 void StopExaminingProc(w, event, prms, nprms)
6412 StopExaminingEvent();
6415 void UploadProc(w, event, prms, nprms)
6425 void ForwardProc(w, event, prms, nprms)
6435 void BackwardProc(w, event, prms, nprms)
6444 void ToStartProc(w, event, prms, nprms)
6453 void ToEndProc(w, event, prms, nprms)
6462 void RevertProc(w, event, prms, nprms)
6471 void AnnotateProc(w, event, prms, nprms)
6480 void TruncateGameProc(w, event, prms, nprms)
6486 TruncateGameEvent();
6488 void RetractMoveProc(w, event, prms, nprms)
6497 void MoveNowProc(w, event, prms, nprms)
6507 void AlwaysQueenProc(w, event, prms, nprms)
6515 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6517 if (appData.alwaysPromoteToQueen) {
6518 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6520 XtSetArg(args[0], XtNleftBitmap, None);
6522 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6526 void AnimateDraggingProc(w, event, prms, nprms)
6534 appData.animateDragging = !appData.animateDragging;
6536 if (appData.animateDragging) {
6537 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6540 XtSetArg(args[0], XtNleftBitmap, None);
6542 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6546 void AnimateMovingProc(w, event, prms, nprms)
6554 appData.animate = !appData.animate;
6556 if (appData.animate) {
6557 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6560 XtSetArg(args[0], XtNleftBitmap, None);
6562 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6566 void AutoflagProc(w, event, prms, nprms)
6574 appData.autoCallFlag = !appData.autoCallFlag;
6576 if (appData.autoCallFlag) {
6577 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6579 XtSetArg(args[0], XtNleftBitmap, None);
6581 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6585 void AutoflipProc(w, event, prms, nprms)
6593 appData.autoFlipView = !appData.autoFlipView;
6595 if (appData.autoFlipView) {
6596 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6598 XtSetArg(args[0], XtNleftBitmap, None);
6600 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6604 void BlindfoldProc(w, event, prms, nprms)
6612 appData.blindfold = !appData.blindfold;
6614 if (appData.blindfold) {
6615 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6617 XtSetArg(args[0], XtNleftBitmap, None);
6619 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6622 DrawPosition(True, NULL);
6625 void TestLegalityProc(w, event, prms, nprms)
6633 appData.testLegality = !appData.testLegality;
6635 if (appData.testLegality) {
6636 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6638 XtSetArg(args[0], XtNleftBitmap, None);
6640 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6645 void FlashMovesProc(w, event, prms, nprms)
6653 if (appData.flashCount == 0) {
6654 appData.flashCount = 3;
6656 appData.flashCount = -appData.flashCount;
6659 if (appData.flashCount > 0) {
6660 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6662 XtSetArg(args[0], XtNleftBitmap, None);
6664 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6668 void FlipViewProc(w, event, prms, nprms)
6674 flipView = !flipView;
6675 DrawPosition(True, NULL);
6679 void HighlightDraggingProc(w, event, prms, nprms)
6687 appData.highlightDragging = !appData.highlightDragging;
6689 if (appData.highlightDragging) {
6690 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6692 XtSetArg(args[0], XtNleftBitmap, None);
6694 XtSetValues(XtNameToWidget(menuBarWidget,
6695 "menuOptions.Highlight Dragging"), args, 1);
6699 void HighlightLastMoveProc(w, event, prms, nprms)
6707 appData.highlightLastMove = !appData.highlightLastMove;
6709 if (appData.highlightLastMove) {
6710 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6712 XtSetArg(args[0], XtNleftBitmap, None);
6714 XtSetValues(XtNameToWidget(menuBarWidget,
6715 "menuOptions.Highlight Last Move"), args, 1);
6718 void HighlightArrowProc(w, event, prms, nprms)
6726 appData.highlightMoveWithArrow = !appData.highlightMoveWithArrow;
6728 if (appData.highlightMoveWithArrow) {
6729 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6731 XtSetArg(args[0], XtNleftBitmap, None);
6733 XtSetValues(XtNameToWidget(menuBarWidget,
6734 "menuOptions.Arrow"), args, 1);
6738 void IcsAlarmProc(w, event, prms, nprms)
6746 appData.icsAlarm = !appData.icsAlarm;
6748 if (appData.icsAlarm) {
6749 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6751 XtSetArg(args[0], XtNleftBitmap, None);
6753 XtSetValues(XtNameToWidget(menuBarWidget,
6754 "menuOptions.ICS Alarm"), args, 1);
6758 void MoveSoundProc(w, event, prms, nprms)
6766 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6768 if (appData.ringBellAfterMoves) {
6769 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6771 XtSetArg(args[0], XtNleftBitmap, None);
6773 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6777 void OneClickProc(w, event, prms, nprms)
6785 appData.oneClick = !appData.oneClick;
6787 if (appData.oneClick) {
6788 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6790 XtSetArg(args[0], XtNleftBitmap, None);
6792 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.OneClick"),
6796 void PeriodicUpdatesProc(w, event, prms, nprms)
6804 PeriodicUpdatesEvent(!appData.periodicUpdates);
6806 if (appData.periodicUpdates) {
6807 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6809 XtSetArg(args[0], XtNleftBitmap, None);
6811 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6815 void PonderNextMoveProc(w, event, prms, nprms)
6823 PonderNextMoveEvent(!appData.ponderNextMove);
6825 if (appData.ponderNextMove) {
6826 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6828 XtSetArg(args[0], XtNleftBitmap, None);
6830 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6834 void PopupExitMessageProc(w, event, prms, nprms)
6842 appData.popupExitMessage = !appData.popupExitMessage;
6844 if (appData.popupExitMessage) {
6845 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6847 XtSetArg(args[0], XtNleftBitmap, None);
6849 XtSetValues(XtNameToWidget(menuBarWidget,
6850 "menuOptions.Popup Exit Message"), args, 1);
6853 void PopupMoveErrorsProc(w, event, prms, nprms)
6861 appData.popupMoveErrors = !appData.popupMoveErrors;
6863 if (appData.popupMoveErrors) {
6864 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6866 XtSetArg(args[0], XtNleftBitmap, None);
6868 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6873 void PremoveProc(w, event, prms, nprms)
6881 appData.premove = !appData.premove;
6883 if (appData.premove) {
6884 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6886 XtSetArg(args[0], XtNleftBitmap, None);
6888 XtSetValues(XtNameToWidget(menuBarWidget,
6889 "menuOptions.Premove"), args, 1);
6893 void ShowCoordsProc(w, event, prms, nprms)
6901 appData.showCoords = !appData.showCoords;
6903 if (appData.showCoords) {
6904 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6906 XtSetArg(args[0], XtNleftBitmap, None);
6908 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6911 DrawPosition(True, NULL);
6914 void ShowThinkingProc(w, event, prms, nprms)
6920 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6921 ShowThinkingEvent();
6924 void HideThinkingProc(w, event, prms, nprms)
6932 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6933 ShowThinkingEvent();
6935 if (appData.hideThinkingFromHuman) {
6936 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6938 XtSetArg(args[0], XtNleftBitmap, None);
6940 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6944 void SaveOnExitProc(w, event, prms, nprms)
6952 saveSettingsOnExit = !saveSettingsOnExit;
6954 if (saveSettingsOnExit) {
6955 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6957 XtSetArg(args[0], XtNleftBitmap, None);
6959 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6963 void SaveSettingsProc(w, event, prms, nprms)
6969 SaveSettings(settingsFileName);
6972 void InfoProc(w, event, prms, nprms)
6979 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6984 void ManProc(w, event, prms, nprms)
6992 if (nprms && *nprms > 0)
6996 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
7000 void HintProc(w, event, prms, nprms)
7009 void BookProc(w, event, prms, nprms)
7018 void AboutProc(w, event, prms, nprms)
7026 char *zippy = " (with Zippy code)";
7030 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
7031 programVersion, zippy,
7032 "Copyright 1991 Digital Equipment Corporation",
7033 "Enhancements Copyright 1992-2009 Free Software Foundation",
7034 "Enhancements Copyright 2005 Alessandro Scotti",
7035 PACKAGE, " is free software and carries NO WARRANTY;",
7036 "see the file COPYING for more information.");
7037 ErrorPopUp(_("About XBoard"), buf, FALSE);
7040 void DebugProc(w, event, prms, nprms)
7046 appData.debugMode = !appData.debugMode;
7049 void AboutGameProc(w, event, prms, nprms)
7058 void NothingProc(w, event, prms, nprms)
7067 void Iconify(w, event, prms, nprms)
7076 XtSetArg(args[0], XtNiconic, True);
7077 XtSetValues(shellWidget, args, 1);
7080 void DisplayMessage(message, extMessage)
7081 char *message, *extMessage;
7083 /* display a message in the message widget */
7092 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
7097 message = extMessage;
7101 /* need to test if messageWidget already exists, since this function
7102 can also be called during the startup, if for example a Xresource
7103 is not set up correctly */
7106 XtSetArg(arg, XtNlabel, message);
7107 XtSetValues(messageWidget, &arg, 1);
7113 void DisplayTitle(text)
7118 char title[MSG_SIZ];
7121 if (text == NULL) text = "";
7123 if (appData.titleInWindow) {
7125 XtSetArg(args[i], XtNlabel, text); i++;
7126 XtSetValues(titleWidget, args, i);
7129 if (*text != NULLCHAR) {
7130 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
7131 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
7132 } else if (appData.icsActive) {
7133 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7134 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7135 } else if (appData.cmailGameName[0] != NULLCHAR) {
7136 snprintf(icon, sizeof(icon), "%s", "CMail");
7137 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7139 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7140 } else if (gameInfo.variant == VariantGothic) {
7141 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7142 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
7145 } else if (gameInfo.variant == VariantFalcon) {
7146 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7147 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
7149 } else if (appData.noChessProgram) {
7150 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7151 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
7153 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
7154 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7157 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7158 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7159 XtSetValues(shellWidget, args, i);
7164 DisplayError(message, error)
7171 if (appData.debugMode || appData.matchMode) {
7172 fprintf(stderr, "%s: %s\n", programName, message);
7175 if (appData.debugMode || appData.matchMode) {
7176 fprintf(stderr, "%s: %s: %s\n",
7177 programName, message, strerror(error));
7179 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7182 ErrorPopUp(_("Error"), message, FALSE);
7186 void DisplayMoveError(message)
7191 DrawPosition(FALSE, NULL);
7192 if (appData.debugMode || appData.matchMode) {
7193 fprintf(stderr, "%s: %s\n", programName, message);
7195 if (appData.popupMoveErrors) {
7196 ErrorPopUp(_("Error"), message, FALSE);
7198 DisplayMessage(message, "");
7203 void DisplayFatalError(message, error, status)
7209 errorExitStatus = status;
7211 fprintf(stderr, "%s: %s\n", programName, message);
7213 fprintf(stderr, "%s: %s: %s\n",
7214 programName, message, strerror(error));
7215 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7218 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7219 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7225 void DisplayInformation(message)
7229 ErrorPopUp(_("Information"), message, TRUE);
7232 void DisplayNote(message)
7236 ErrorPopUp(_("Note"), message, FALSE);
7240 NullXErrorCheck(dpy, error_event)
7242 XErrorEvent *error_event;
7247 void DisplayIcsInteractionTitle(message)
7250 if (oldICSInteractionTitle == NULL) {
7251 /* Magic to find the old window title, adapted from vim */
7252 char *wina = getenv("WINDOWID");
7254 Window win = (Window) atoi(wina);
7255 Window root, parent, *children;
7256 unsigned int nchildren;
7257 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7259 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7260 if (!XQueryTree(xDisplay, win, &root, &parent,
7261 &children, &nchildren)) break;
7262 if (children) XFree((void *)children);
7263 if (parent == root || parent == 0) break;
7266 XSetErrorHandler(oldHandler);
7268 if (oldICSInteractionTitle == NULL) {
7269 oldICSInteractionTitle = "xterm";
7272 printf("\033]0;%s\007", message);
7276 char pendingReplyPrefix[MSG_SIZ];
7277 ProcRef pendingReplyPR;
7279 void AskQuestionProc(w, event, prms, nprms)
7286 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7290 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7293 void AskQuestionPopDown()
7295 if (!askQuestionUp) return;
7296 XtPopdown(askQuestionShell);
7297 XtDestroyWidget(askQuestionShell);
7298 askQuestionUp = False;
7301 void AskQuestionReplyAction(w, event, prms, nprms)
7311 reply = XawDialogGetValueString(w = XtParent(w));
7312 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
7313 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
7314 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
7315 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
7316 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7317 AskQuestionPopDown();
7319 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7322 void AskQuestionCallback(w, client_data, call_data)
7324 XtPointer client_data, call_data;
7329 XtSetArg(args[0], XtNlabel, &name);
7330 XtGetValues(w, args, 1);
7332 if (strcmp(name, _("cancel")) == 0) {
7333 AskQuestionPopDown();
7335 AskQuestionReplyAction(w, NULL, NULL, NULL);
7339 void AskQuestion(title, question, replyPrefix, pr)
7340 char *title, *question, *replyPrefix;
7344 Widget popup, layout, dialog, edit;
7350 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
7351 pendingReplyPR = pr;
7354 XtSetArg(args[i], XtNresizable, True); i++;
7355 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7356 askQuestionShell = popup =
7357 XtCreatePopupShell(title, transientShellWidgetClass,
7358 shellWidget, args, i);
7361 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7362 layoutArgs, XtNumber(layoutArgs));
7365 XtSetArg(args[i], XtNlabel, question); i++;
7366 XtSetArg(args[i], XtNvalue, ""); i++;
7367 XtSetArg(args[i], XtNborderWidth, 0); i++;
7368 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7371 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7372 (XtPointer) dialog);
7373 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7374 (XtPointer) dialog);
7376 XtRealizeWidget(popup);
7377 CatchDeleteWindow(popup, "AskQuestionPopDown");
7379 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7380 &x, &y, &win_x, &win_y, &mask);
7382 XtSetArg(args[0], XtNx, x - 10);
7383 XtSetArg(args[1], XtNy, y - 30);
7384 XtSetValues(popup, args, 2);
7386 XtPopup(popup, XtGrabExclusive);
7387 askQuestionUp = True;
7389 edit = XtNameToWidget(dialog, "*value");
7390 XtSetKeyboardFocus(popup, edit);
7398 if (*name == NULLCHAR) {
7400 } else if (strcmp(name, "$") == 0) {
7401 putc(BELLCHAR, stderr);
7404 char *prefix = "", *sep = "";
7405 if(!strchr(name, '/')) { prefix = appData.soundDirectory; sep = "/"; }
7406 snprintf(buf, sizeof(buf), "%s '%s%s%s' &", appData.soundProgram, prefix, sep, name);
7414 PlaySound(appData.soundMove);
7420 PlaySound(appData.soundIcsWin);
7426 PlaySound(appData.soundIcsLoss);
7432 PlaySound(appData.soundIcsDraw);
7436 PlayIcsUnfinishedSound()
7438 PlaySound(appData.soundIcsUnfinished);
7444 PlaySound(appData.soundIcsAlarm);
7450 system("stty echo");
7456 system("stty -echo");
7460 Colorize(cc, continuation)
7465 int count, outCount, error;
7467 if (textColors[(int)cc].bg > 0) {
7468 if (textColors[(int)cc].fg > 0) {
7469 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7470 textColors[(int)cc].fg, textColors[(int)cc].bg);
7472 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7473 textColors[(int)cc].bg);
7476 if (textColors[(int)cc].fg > 0) {
7477 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7478 textColors[(int)cc].fg);
7480 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7483 count = strlen(buf);
7484 outCount = OutputToProcess(NoProc, buf, count, &error);
7485 if (outCount < count) {
7486 DisplayFatalError(_("Error writing to display"), error, 1);
7489 if (continuation) return;
7492 PlaySound(appData.soundShout);
7495 PlaySound(appData.soundSShout);
7498 PlaySound(appData.soundChannel1);
7501 PlaySound(appData.soundChannel);
7504 PlaySound(appData.soundKibitz);
7507 PlaySound(appData.soundTell);
7509 case ColorChallenge:
7510 PlaySound(appData.soundChallenge);
7513 PlaySound(appData.soundRequest);
7516 PlaySound(appData.soundSeek);
7527 return getpwuid(getuid())->pw_name;
7531 ExpandPathName(path)
7534 static char static_buf[4*MSG_SIZ];
7535 char *d, *s, buf[4*MSG_SIZ];
7541 while (*s && isspace(*s))
7550 if (*(s+1) == '/') {
7551 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7555 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7556 { char *p; if(p = strchr(buf, '/')) *p = 0; }
7557 pwd = getpwnam(buf);
7560 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7564 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7565 strcat(d, strchr(s+1, '/'));
7569 safeStrCpy(d, s, 4*MSG_SIZ );
7576 static char host_name[MSG_SIZ];
7578 #if HAVE_GETHOSTNAME
7579 gethostname(host_name, MSG_SIZ);
7581 #else /* not HAVE_GETHOSTNAME */
7582 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7583 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7585 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7587 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7588 #endif /* not HAVE_GETHOSTNAME */
7591 XtIntervalId delayedEventTimerXID = 0;
7592 DelayedEventCallback delayedEventCallback = 0;
7597 delayedEventTimerXID = 0;
7598 delayedEventCallback();
7602 ScheduleDelayedEvent(cb, millisec)
7603 DelayedEventCallback cb; long millisec;
7605 if(delayedEventTimerXID && delayedEventCallback == cb)
7606 // [HGM] alive: replace, rather than add or flush identical event
7607 XtRemoveTimeOut(delayedEventTimerXID);
7608 delayedEventCallback = cb;
7609 delayedEventTimerXID =
7610 XtAppAddTimeOut(appContext, millisec,
7611 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7614 DelayedEventCallback
7617 if (delayedEventTimerXID) {
7618 return delayedEventCallback;
7625 CancelDelayedEvent()
7627 if (delayedEventTimerXID) {
7628 XtRemoveTimeOut(delayedEventTimerXID);
7629 delayedEventTimerXID = 0;
7633 XtIntervalId loadGameTimerXID = 0;
7635 int LoadGameTimerRunning()
7637 return loadGameTimerXID != 0;
7640 int StopLoadGameTimer()
7642 if (loadGameTimerXID != 0) {
7643 XtRemoveTimeOut(loadGameTimerXID);
7644 loadGameTimerXID = 0;
7652 LoadGameTimerCallback(arg, id)
7656 loadGameTimerXID = 0;
7661 StartLoadGameTimer(millisec)
7665 XtAppAddTimeOut(appContext, millisec,
7666 (XtTimerCallbackProc) LoadGameTimerCallback,
7670 XtIntervalId analysisClockXID = 0;
7673 AnalysisClockCallback(arg, id)
7677 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7678 || appData.icsEngineAnalyze) { // [DM]
7679 AnalysisPeriodicEvent(0);
7680 StartAnalysisClock();
7685 StartAnalysisClock()
7688 XtAppAddTimeOut(appContext, 2000,
7689 (XtTimerCallbackProc) AnalysisClockCallback,
7693 XtIntervalId clockTimerXID = 0;
7695 int ClockTimerRunning()
7697 return clockTimerXID != 0;
7700 int StopClockTimer()
7702 if (clockTimerXID != 0) {
7703 XtRemoveTimeOut(clockTimerXID);
7712 ClockTimerCallback(arg, id)
7721 StartClockTimer(millisec)
7725 XtAppAddTimeOut(appContext, millisec,
7726 (XtTimerCallbackProc) ClockTimerCallback,
7731 DisplayTimerLabel(w, color, timer, highlight)
7740 /* check for low time warning */
7741 Pixel foregroundOrWarningColor = timerForegroundPixel;
7744 appData.lowTimeWarning &&
7745 (timer / 1000) < appData.icsAlarmTime)
7746 foregroundOrWarningColor = lowTimeWarningColor;
7748 if (appData.clockMode) {
7749 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7750 XtSetArg(args[0], XtNlabel, buf);
7752 snprintf(buf, MSG_SIZ, "%s ", color);
7753 XtSetArg(args[0], XtNlabel, buf);
7758 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7759 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7761 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7762 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7765 XtSetValues(w, args, 3);
7769 DisplayWhiteClock(timeRemaining, highlight)
7775 if(appData.noGUI) return;
7776 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7777 if (highlight && iconPixmap == bIconPixmap) {
7778 iconPixmap = wIconPixmap;
7779 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7780 XtSetValues(shellWidget, args, 1);
7785 DisplayBlackClock(timeRemaining, highlight)
7791 if(appData.noGUI) return;
7792 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7793 if (highlight && iconPixmap == wIconPixmap) {
7794 iconPixmap = bIconPixmap;
7795 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7796 XtSetValues(shellWidget, args, 1);
7814 int StartChildProcess(cmdLine, dir, pr)
7821 int to_prog[2], from_prog[2];
7825 if (appData.debugMode) {
7826 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7829 /* We do NOT feed the cmdLine to the shell; we just
7830 parse it into blank-separated arguments in the
7831 most simple-minded way possible.
7834 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7837 while(*p == ' ') p++;
7839 if(*p == '"' || *p == '\'')
7840 p = strchr(++argv[i-1], *p);
7841 else p = strchr(p, ' ');
7842 if (p == NULL) break;
7847 SetUpChildIO(to_prog, from_prog);
7849 if ((pid = fork()) == 0) {
7851 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7852 close(to_prog[1]); // first close the unused pipe ends
7853 close(from_prog[0]);
7854 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7855 dup2(from_prog[1], 1);
7856 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7857 close(from_prog[1]); // and closing again loses one of the pipes!
7858 if(fileno(stderr) >= 2) // better safe than sorry...
7859 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7861 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7866 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7868 execvp(argv[0], argv);
7870 /* If we get here, exec failed */
7875 /* Parent process */
7877 close(from_prog[1]);
7879 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7882 cp->fdFrom = from_prog[0];
7883 cp->fdTo = to_prog[1];
7888 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7889 static RETSIGTYPE AlarmCallBack(int n)
7895 DestroyChildProcess(pr, signalType)
7899 ChildProc *cp = (ChildProc *) pr;
7901 if (cp->kind != CPReal) return;
7903 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7904 signal(SIGALRM, AlarmCallBack);
7906 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7907 kill(cp->pid, SIGKILL); // kill it forcefully
7908 wait((int *) 0); // and wait again
7912 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7914 /* Process is exiting either because of the kill or because of
7915 a quit command sent by the backend; either way, wait for it to die.
7924 InterruptChildProcess(pr)
7927 ChildProc *cp = (ChildProc *) pr;
7929 if (cp->kind != CPReal) return;
7930 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7933 int OpenTelnet(host, port, pr)
7938 char cmdLine[MSG_SIZ];
7940 if (port[0] == NULLCHAR) {
7941 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7943 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7945 return StartChildProcess(cmdLine, "", pr);
7948 int OpenTCP(host, port, pr)
7954 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7955 #else /* !OMIT_SOCKETS */
7957 struct sockaddr_in sa;
7959 unsigned short uport;
7962 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7966 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7967 sa.sin_family = AF_INET;
7968 sa.sin_addr.s_addr = INADDR_ANY;
7969 uport = (unsigned short) 0;
7970 sa.sin_port = htons(uport);
7971 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7975 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7976 if (!(hp = gethostbyname(host))) {
7978 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7979 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7980 hp->h_addrtype = AF_INET;
7982 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7983 hp->h_addr_list[0] = (char *) malloc(4);
7984 hp->h_addr_list[0][0] = b0;
7985 hp->h_addr_list[0][1] = b1;
7986 hp->h_addr_list[0][2] = b2;
7987 hp->h_addr_list[0][3] = b3;
7992 sa.sin_family = hp->h_addrtype;
7993 uport = (unsigned short) atoi(port);
7994 sa.sin_port = htons(uport);
7995 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7997 if (connect(s, (struct sockaddr *) &sa,
7998 sizeof(struct sockaddr_in)) < 0) {
8002 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8009 #endif /* !OMIT_SOCKETS */
8014 int OpenCommPort(name, pr)
8021 fd = open(name, 2, 0);
8022 if (fd < 0) return errno;
8024 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8034 int OpenLoopback(pr)
8040 SetUpChildIO(to, from);
8042 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8045 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
8052 int OpenRcmd(host, user, cmd, pr)
8053 char *host, *user, *cmd;
8056 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
8060 #define INPUT_SOURCE_BUF_SIZE 8192
8069 char buf[INPUT_SOURCE_BUF_SIZE];
8074 DoInputCallback(closure, source, xid)
8079 InputSource *is = (InputSource *) closure;
8084 if (is->lineByLine) {
8085 count = read(is->fd, is->unused,
8086 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
8088 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
8091 is->unused += count;
8093 while (p < is->unused) {
8094 q = memchr(p, '\n', is->unused - p);
8095 if (q == NULL) break;
8097 (is->func)(is, is->closure, p, q - p, 0);
8101 while (p < is->unused) {
8106 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8111 (is->func)(is, is->closure, is->buf, count, error);
8115 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8122 ChildProc *cp = (ChildProc *) pr;
8124 is = (InputSource *) calloc(1, sizeof(InputSource));
8125 is->lineByLine = lineByLine;
8129 is->fd = fileno(stdin);
8131 is->kind = cp->kind;
8132 is->fd = cp->fdFrom;
8135 is->unused = is->buf;
8138 is->xid = XtAppAddInput(appContext, is->fd,
8139 (XtPointer) (XtInputReadMask),
8140 (XtInputCallbackProc) DoInputCallback,
8142 is->closure = closure;
8143 return (InputSourceRef) is;
8147 RemoveInputSource(isr)
8150 InputSource *is = (InputSource *) isr;
8152 if (is->xid == 0) return;
8153 XtRemoveInput(is->xid);
8157 int OutputToProcess(pr, message, count, outError)
8163 static int line = 0;
8164 ChildProc *cp = (ChildProc *) pr;
8169 if (appData.noJoin || !appData.useInternalWrap)
8170 outCount = fwrite(message, 1, count, stdout);
8173 int width = get_term_width();
8174 int len = wrap(NULL, message, count, width, &line);
8175 char *msg = malloc(len);
8179 outCount = fwrite(message, 1, count, stdout);
8182 dbgchk = wrap(msg, message, count, width, &line);
8183 if (dbgchk != len && appData.debugMode)
8184 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8185 outCount = fwrite(msg, 1, dbgchk, stdout);
8191 outCount = write(cp->fdTo, message, count);
8201 /* Output message to process, with "ms" milliseconds of delay
8202 between each character. This is needed when sending the logon
8203 script to ICC, which for some reason doesn't like the
8204 instantaneous send. */
8205 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8212 ChildProc *cp = (ChildProc *) pr;
8217 r = write(cp->fdTo, message++, 1);
8230 /**** Animation code by Hugh Fisher, DCS, ANU.
8232 Known problem: if a window overlapping the board is
8233 moved away while a piece is being animated underneath,
8234 the newly exposed area won't be updated properly.
8235 I can live with this.
8237 Known problem: if you look carefully at the animation
8238 of pieces in mono mode, they are being drawn as solid
8239 shapes without interior detail while moving. Fixing
8240 this would be a major complication for minimal return.
8243 /* Masks for XPM pieces. Black and white pieces can have
8244 different shapes, but in the interest of retaining my
8245 sanity pieces must have the same outline on both light
8246 and dark squares, and all pieces must use the same
8247 background square colors/images. */
8249 static int xpmDone = 0;
8252 CreateAnimMasks (pieceDepth)
8259 unsigned long plane;
8262 /* Need a bitmap just to get a GC with right depth */
8263 buf = XCreatePixmap(xDisplay, xBoardWindow,
8265 values.foreground = 1;
8266 values.background = 0;
8267 /* Don't use XtGetGC, not read only */
8268 maskGC = XCreateGC(xDisplay, buf,
8269 GCForeground | GCBackground, &values);
8270 XFreePixmap(xDisplay, buf);
8272 buf = XCreatePixmap(xDisplay, xBoardWindow,
8273 squareSize, squareSize, pieceDepth);
8274 values.foreground = XBlackPixel(xDisplay, xScreen);
8275 values.background = XWhitePixel(xDisplay, xScreen);
8276 bufGC = XCreateGC(xDisplay, buf,
8277 GCForeground | GCBackground, &values);
8279 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8280 /* Begin with empty mask */
8281 if(!xpmDone) // [HGM] pieces: keep using existing
8282 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8283 squareSize, squareSize, 1);
8284 XSetFunction(xDisplay, maskGC, GXclear);
8285 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8286 0, 0, squareSize, squareSize);
8288 /* Take a copy of the piece */
8293 XSetFunction(xDisplay, bufGC, GXcopy);
8294 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8296 0, 0, squareSize, squareSize, 0, 0);
8298 /* XOR the background (light) over the piece */
8299 XSetFunction(xDisplay, bufGC, GXxor);
8301 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8302 0, 0, squareSize, squareSize, 0, 0);
8304 XSetForeground(xDisplay, bufGC, lightSquareColor);
8305 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8308 /* We now have an inverted piece image with the background
8309 erased. Construct mask by just selecting all the non-zero
8310 pixels - no need to reconstruct the original image. */
8311 XSetFunction(xDisplay, maskGC, GXor);
8313 /* Might be quicker to download an XImage and create bitmap
8314 data from it rather than this N copies per piece, but it
8315 only takes a fraction of a second and there is a much
8316 longer delay for loading the pieces. */
8317 for (n = 0; n < pieceDepth; n ++) {
8318 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8319 0, 0, squareSize, squareSize,
8325 XFreePixmap(xDisplay, buf);
8326 XFreeGC(xDisplay, bufGC);
8327 XFreeGC(xDisplay, maskGC);
8331 InitAnimState (anim, info)
8333 XWindowAttributes * info;
8338 /* Each buffer is square size, same depth as window */
8339 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8340 squareSize, squareSize, info->depth);
8341 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8342 squareSize, squareSize, info->depth);
8344 /* Create a plain GC for blitting */
8345 mask = GCForeground | GCBackground | GCFunction |
8346 GCPlaneMask | GCGraphicsExposures;
8347 values.foreground = XBlackPixel(xDisplay, xScreen);
8348 values.background = XWhitePixel(xDisplay, xScreen);
8349 values.function = GXcopy;
8350 values.plane_mask = AllPlanes;
8351 values.graphics_exposures = False;
8352 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8354 /* Piece will be copied from an existing context at
8355 the start of each new animation/drag. */
8356 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8358 /* Outline will be a read-only copy of an existing */
8359 anim->outlineGC = None;
8365 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8366 XWindowAttributes info;
8368 if (xpmDone && gameInfo.variant == old) return;
8369 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8370 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8372 InitAnimState(&game, &info);
8373 InitAnimState(&player, &info);
8375 /* For XPM pieces, we need bitmaps to use as masks. */
8377 CreateAnimMasks(info.depth);
8383 static Boolean frameWaiting;
8385 static RETSIGTYPE FrameAlarm (sig)
8388 frameWaiting = False;
8389 /* In case System-V style signals. Needed?? */
8390 signal(SIGALRM, FrameAlarm);
8397 struct itimerval delay;
8399 XSync(xDisplay, False);
8402 frameWaiting = True;
8403 signal(SIGALRM, FrameAlarm);
8404 delay.it_interval.tv_sec =
8405 delay.it_value.tv_sec = time / 1000;
8406 delay.it_interval.tv_usec =
8407 delay.it_value.tv_usec = (time % 1000) * 1000;
8408 setitimer(ITIMER_REAL, &delay, NULL);
8409 while (frameWaiting) pause();
8410 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8411 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8412 setitimer(ITIMER_REAL, &delay, NULL);
8422 XSync(xDisplay, False);
8424 usleep(time * 1000);
8429 /* Convert board position to corner of screen rect and color */
8432 ScreenSquare(column, row, pt, color)
8433 int column; int row; XPoint * pt; int * color;
8436 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8437 pt->y = lineGap + row * (squareSize + lineGap);
8439 pt->x = lineGap + column * (squareSize + lineGap);
8440 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8442 *color = SquareColor(row, column);
8445 /* Convert window coords to square */
8448 BoardSquare(x, y, column, row)
8449 int x; int y; int * column; int * row;
8451 *column = EventToSquare(x, BOARD_WIDTH);
8452 if (flipView && *column >= 0)
8453 *column = BOARD_WIDTH - 1 - *column;
8454 *row = EventToSquare(y, BOARD_HEIGHT);
8455 if (!flipView && *row >= 0)
8456 *row = BOARD_HEIGHT - 1 - *row;
8461 #undef Max /* just in case */
8463 #define Max(a, b) ((a) > (b) ? (a) : (b))
8464 #define Min(a, b) ((a) < (b) ? (a) : (b))
8467 SetRect(rect, x, y, width, height)
8468 XRectangle * rect; int x; int y; int width; int height;
8472 rect->width = width;
8473 rect->height = height;
8476 /* Test if two frames overlap. If they do, return
8477 intersection rect within old and location of
8478 that rect within new. */
8481 Intersect(old, new, size, area, pt)
8482 XPoint * old; XPoint * new;
8483 int size; XRectangle * area; XPoint * pt;
8485 if (old->x > new->x + size || new->x > old->x + size ||
8486 old->y > new->y + size || new->y > old->y + size) {
8489 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8490 size - abs(old->x - new->x), size - abs(old->y - new->y));
8491 pt->x = Max(old->x - new->x, 0);
8492 pt->y = Max(old->y - new->y, 0);
8497 /* For two overlapping frames, return the rect(s)
8498 in the old that do not intersect with the new. */
8501 CalcUpdateRects(old, new, size, update, nUpdates)
8502 XPoint * old; XPoint * new; int size;
8503 XRectangle update[]; int * nUpdates;
8507 /* If old = new (shouldn't happen) then nothing to draw */
8508 if (old->x == new->x && old->y == new->y) {
8512 /* Work out what bits overlap. Since we know the rects
8513 are the same size we don't need a full intersect calc. */
8515 /* Top or bottom edge? */
8516 if (new->y > old->y) {
8517 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8519 } else if (old->y > new->y) {
8520 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8521 size, old->y - new->y);
8524 /* Left or right edge - don't overlap any update calculated above. */
8525 if (new->x > old->x) {
8526 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8527 new->x - old->x, size - abs(new->y - old->y));
8529 } else if (old->x > new->x) {
8530 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8531 old->x - new->x, size - abs(new->y - old->y));
8538 /* Generate a series of frame coords from start->mid->finish.
8539 The movement rate doubles until the half way point is
8540 reached, then halves back down to the final destination,
8541 which gives a nice slow in/out effect. The algorithmn
8542 may seem to generate too many intermediates for short
8543 moves, but remember that the purpose is to attract the
8544 viewers attention to the piece about to be moved and
8545 then to where it ends up. Too few frames would be less
8549 Tween(start, mid, finish, factor, frames, nFrames)
8550 XPoint * start; XPoint * mid;
8551 XPoint * finish; int factor;
8552 XPoint frames[]; int * nFrames;
8554 int fraction, n, count;
8558 /* Slow in, stepping 1/16th, then 1/8th, ... */
8560 for (n = 0; n < factor; n++)
8562 for (n = 0; n < factor; n++) {
8563 frames[count].x = start->x + (mid->x - start->x) / fraction;
8564 frames[count].y = start->y + (mid->y - start->y) / fraction;
8566 fraction = fraction / 2;
8570 frames[count] = *mid;
8573 /* Slow out, stepping 1/2, then 1/4, ... */
8575 for (n = 0; n < factor; n++) {
8576 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8577 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8579 fraction = fraction * 2;
8584 /* Draw a piece on the screen without disturbing what's there */
8587 SelectGCMask(piece, clip, outline, mask)
8588 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8592 /* Bitmap for piece being moved. */
8593 if (appData.monoMode) {
8594 *mask = *pieceToSolid(piece);
8595 } else if (useImages) {
8597 *mask = xpmMask[piece];
8599 *mask = ximMaskPm[piece];
8602 *mask = *pieceToSolid(piece);
8605 /* GC for piece being moved. Square color doesn't matter, but
8606 since it gets modified we make a copy of the original. */
8608 if (appData.monoMode)
8613 if (appData.monoMode)
8618 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8620 /* Outline only used in mono mode and is not modified */
8622 *outline = bwPieceGC;
8624 *outline = wbPieceGC;
8628 OverlayPiece(piece, clip, outline, dest)
8629 ChessSquare piece; GC clip; GC outline; Drawable dest;
8634 /* Draw solid rectangle which will be clipped to shape of piece */
8635 XFillRectangle(xDisplay, dest, clip,
8636 0, 0, squareSize, squareSize);
8637 if (appData.monoMode)
8638 /* Also draw outline in contrasting color for black
8639 on black / white on white cases */
8640 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8641 0, 0, squareSize, squareSize, 0, 0, 1);
8643 /* Copy the piece */
8648 if(appData.upsideDown && flipView) kind ^= 2;
8649 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8651 0, 0, squareSize, squareSize,
8656 /* Animate the movement of a single piece */
8659 BeginAnimation(anim, piece, startColor, start)
8667 if(appData.upsideDown && flipView) piece += piece < BlackPawn ? BlackPawn : -BlackPawn;
8668 /* The old buffer is initialised with the start square (empty) */
8669 BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0);
8670 anim->prevFrame = *start;
8672 /* The piece will be drawn using its own bitmap as a matte */
8673 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8674 XSetClipMask(xDisplay, anim->pieceGC, mask);
8678 AnimationFrame(anim, frame, piece)
8683 XRectangle updates[4];
8688 /* Save what we are about to draw into the new buffer */
8689 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8690 frame->x, frame->y, squareSize, squareSize,
8693 /* Erase bits of the previous frame */
8694 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8695 /* Where the new frame overlapped the previous,
8696 the contents in newBuf are wrong. */
8697 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8698 overlap.x, overlap.y,
8699 overlap.width, overlap.height,
8701 /* Repaint the areas in the old that don't overlap new */
8702 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8703 for (i = 0; i < count; i++)
8704 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8705 updates[i].x - anim->prevFrame.x,
8706 updates[i].y - anim->prevFrame.y,
8707 updates[i].width, updates[i].height,
8708 updates[i].x, updates[i].y);
8710 /* Easy when no overlap */
8711 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8712 0, 0, squareSize, squareSize,
8713 anim->prevFrame.x, anim->prevFrame.y);
8716 /* Save this frame for next time round */
8717 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8718 0, 0, squareSize, squareSize,
8720 anim->prevFrame = *frame;
8722 /* Draw piece over original screen contents, not current,
8723 and copy entire rect. Wipes out overlapping piece images. */
8724 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8725 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8726 0, 0, squareSize, squareSize,
8727 frame->x, frame->y);
8731 EndAnimation (anim, finish)
8735 XRectangle updates[4];
8740 /* The main code will redraw the final square, so we
8741 only need to erase the bits that don't overlap. */
8742 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8743 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8744 for (i = 0; i < count; i++)
8745 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8746 updates[i].x - anim->prevFrame.x,
8747 updates[i].y - anim->prevFrame.y,
8748 updates[i].width, updates[i].height,
8749 updates[i].x, updates[i].y);
8751 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8752 0, 0, squareSize, squareSize,
8753 anim->prevFrame.x, anim->prevFrame.y);
8758 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8760 ChessSquare piece; int startColor;
8761 XPoint * start; XPoint * finish;
8762 XPoint frames[]; int nFrames;
8766 BeginAnimation(anim, piece, startColor, start);
8767 for (n = 0; n < nFrames; n++) {
8768 AnimationFrame(anim, &(frames[n]), piece);
8769 FrameDelay(appData.animSpeed);
8771 EndAnimation(anim, finish);
8775 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
8778 ChessSquare piece = board[fromY][toY];
8779 board[fromY][toY] = EmptySquare;
8780 DrawPosition(FALSE, board);
8782 x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap);
8783 y = lineGap + toY * (squareSize + lineGap);
8785 x = lineGap + toX * (squareSize + lineGap);
8786 y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap);
8788 for(i=1; i<4*kFactor; i++) {
8789 int r = squareSize * 9 * i/(20*kFactor - 5);
8790 XFillArc(xDisplay, xBoardWindow, highlineGC,
8791 x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360);
8792 FrameDelay(appData.animSpeed);
8794 board[fromY][toY] = piece;
8797 /* Main control logic for deciding what to animate and how */
8800 AnimateMove(board, fromX, fromY, toX, toY)
8809 XPoint start, finish, mid;
8810 XPoint frames[kFactor * 2 + 1];
8811 int nFrames, startColor, endColor;
8813 /* Are we animating? */
8814 if (!appData.animate || appData.blindfold)
8817 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8818 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8819 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8821 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8822 piece = board[fromY][fromX];
8823 if (piece >= EmptySquare) return;
8828 hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1;
8831 if (appData.debugMode) {
8832 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8833 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8834 piece, fromX, fromY, toX, toY); }
8836 ScreenSquare(fromX, fromY, &start, &startColor);
8837 ScreenSquare(toX, toY, &finish, &endColor);
8840 /* Knight: make straight movement then diagonal */
8841 if (abs(toY - fromY) < abs(toX - fromX)) {
8842 mid.x = start.x + (finish.x - start.x) / 2;
8846 mid.y = start.y + (finish.y - start.y) / 2;
8849 mid.x = start.x + (finish.x - start.x) / 2;
8850 mid.y = start.y + (finish.y - start.y) / 2;
8853 /* Don't use as many frames for very short moves */
8854 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8855 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8857 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8858 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8859 if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
8861 for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
8862 if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
8865 /* Be sure end square is redrawn */
8866 damage[0][toY][toX] = True;
8870 DragPieceBegin(x, y)
8873 int boardX, boardY, color;
8876 /* Are we animating? */
8877 if (!appData.animateDragging || appData.blindfold)
8880 /* Figure out which square we start in and the
8881 mouse position relative to top left corner. */
8882 BoardSquare(x, y, &boardX, &boardY);
8883 player.startBoardX = boardX;
8884 player.startBoardY = boardY;
8885 ScreenSquare(boardX, boardY, &corner, &color);
8886 player.startSquare = corner;
8887 player.startColor = color;
8888 /* As soon as we start dragging, the piece will jump slightly to
8889 be centered over the mouse pointer. */
8890 player.mouseDelta.x = squareSize/2;
8891 player.mouseDelta.y = squareSize/2;
8892 /* Initialise animation */
8893 player.dragPiece = PieceForSquare(boardX, boardY);
8895 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8896 player.dragActive = True;
8897 BeginAnimation(&player, player.dragPiece, color, &corner);
8898 /* Mark this square as needing to be redrawn. Note that
8899 we don't remove the piece though, since logically (ie
8900 as seen by opponent) the move hasn't been made yet. */
8901 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8902 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8903 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8904 corner.x, corner.y, squareSize, squareSize,
8905 0, 0); // [HGM] zh: unstack in stead of grab
8906 if(gatingPiece != EmptySquare) {
8907 /* Kludge alert: When gating we want the introduced
8908 piece to appear on the from square. To generate an
8909 image of it, we draw it on the board, copy the image,
8910 and draw the original piece again. */
8911 ChessSquare piece = boards[currentMove][boardY][boardX];
8912 DrawSquare(boardY, boardX, gatingPiece, 0);
8913 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8914 corner.x, corner.y, squareSize, squareSize, 0, 0);
8915 DrawSquare(boardY, boardX, piece, 0);
8917 damage[0][boardY][boardX] = True;
8919 player.dragActive = False;
8929 /* Are we animating? */
8930 if (!appData.animateDragging || appData.blindfold)
8934 if (! player.dragActive)
8936 /* Move piece, maintaining same relative position
8937 of mouse within square */
8938 corner.x = x - player.mouseDelta.x;
8939 corner.y = y - player.mouseDelta.y;
8940 AnimationFrame(&player, &corner, player.dragPiece);
8942 if (appData.highlightDragging) {
8944 BoardSquare(x, y, &boardX, &boardY);
8945 SetHighlights(fromX, fromY, boardX, boardY);
8954 int boardX, boardY, color;
8957 /* Are we animating? */
8958 if (!appData.animateDragging || appData.blindfold)
8962 if (! player.dragActive)
8964 /* Last frame in sequence is square piece is
8965 placed on, which may not match mouse exactly. */
8966 BoardSquare(x, y, &boardX, &boardY);
8967 ScreenSquare(boardX, boardY, &corner, &color);
8968 EndAnimation(&player, &corner);
8970 /* Be sure end square is redrawn */
8971 damage[0][boardY][boardX] = True;
8973 /* This prevents weird things happening with fast successive
8974 clicks which on my Sun at least can cause motion events
8975 without corresponding press/release. */
8976 player.dragActive = False;
8979 /* Handle expose event while piece being dragged */
8984 if (!player.dragActive || appData.blindfold)
8987 /* What we're doing: logically, the move hasn't been made yet,
8988 so the piece is still in it's original square. But visually
8989 it's being dragged around the board. So we erase the square
8990 that the piece is on and draw it at the last known drag point. */
8991 BlankSquare(player.startSquare.x, player.startSquare.y,
8992 player.startColor, EmptySquare, xBoardWindow, 1);
8993 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8994 damage[0][player.startBoardY][player.startBoardX] = TRUE;
8997 #include <sys/ioctl.h>
8998 int get_term_width()
9000 int fd, default_width;
9003 default_width = 79; // this is FICS default anyway...
9005 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
9007 if (!ioctl(fd, TIOCGSIZE, &win))
9008 default_width = win.ts_cols;
9009 #elif defined(TIOCGWINSZ)
9011 if (!ioctl(fd, TIOCGWINSZ, &win))
9012 default_width = win.ws_col;
9014 return default_width;
9020 static int old_width = 0;
9021 int new_width = get_term_width();
9023 if (old_width != new_width)
9024 ics_printf("set width %d\n", new_width);
9025 old_width = new_width;
9028 void NotifyFrontendLogin()
9033 /* [AS] Arrow highlighting support */
9035 static double A_WIDTH = 5; /* Width of arrow body */
9037 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
9038 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
9040 static double Sqr( double x )
9045 static int Round( double x )
9047 return (int) (x + 0.5);
9050 void SquareToPos(int rank, int file, int *x, int *y)
9053 *x = lineGap + ((BOARD_WIDTH-1)-file) * (squareSize + lineGap);
9054 *y = lineGap + rank * (squareSize + lineGap);
9056 *x = lineGap + file * (squareSize + lineGap);
9057 *y = lineGap + ((BOARD_HEIGHT-1)-rank) * (squareSize + lineGap);
9061 /* Draw an arrow between two points using current settings */
9062 void DrawArrowBetweenPoints( int s_x, int s_y, int d_x, int d_y )
9065 double dx, dy, j, k, x, y;
9068 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
9070 arrow[0].x = s_x + A_WIDTH + 0.5;
9073 arrow[1].x = s_x + A_WIDTH + 0.5;
9074 arrow[1].y = d_y - h;
9076 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9077 arrow[2].y = d_y - h;
9082 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
9083 arrow[5].y = d_y - h;
9085 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9086 arrow[4].y = d_y - h;
9088 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
9091 else if( d_y == s_y ) {
9092 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
9095 arrow[0].y = s_y + A_WIDTH + 0.5;
9097 arrow[1].x = d_x - w;
9098 arrow[1].y = s_y + A_WIDTH + 0.5;
9100 arrow[2].x = d_x - w;
9101 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9106 arrow[5].x = d_x - w;
9107 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
9109 arrow[4].x = d_x - w;
9110 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9113 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
9116 /* [AS] Needed a lot of paper for this! :-) */
9117 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
9118 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
9120 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
9122 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
9127 arrow[0].x = Round(x - j);
9128 arrow[0].y = Round(y + j*dx);
9130 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
9131 arrow[1].y = Round(arrow[0].y - 2*j*dx);
9134 x = (double) d_x - k;
9135 y = (double) d_y - k*dy;
9138 x = (double) d_x + k;
9139 y = (double) d_y + k*dy;
9142 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
9144 arrow[6].x = Round(x - j);
9145 arrow[6].y = Round(y + j*dx);
9147 arrow[2].x = Round(arrow[6].x + 2*j);
9148 arrow[2].y = Round(arrow[6].y - 2*j*dx);
9150 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
9151 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
9156 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
9157 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
9160 XFillPolygon(xDisplay, xBoardWindow, highlineGC, arrow, 7, Nonconvex, CoordModeOrigin);
9161 // Polygon( hdc, arrow, 7 );
9164 /* [AS] Draw an arrow between two squares */
9165 void DrawArrowBetweenSquares( int s_col, int s_row, int d_col, int d_row )
9167 int s_x, s_y, d_x, d_y, hor, vert, i;
9169 if( s_col == d_col && s_row == d_row ) {
9173 /* Get source and destination points */
9174 SquareToPos( s_row, s_col, &s_x, &s_y);
9175 SquareToPos( d_row, d_col, &d_x, &d_y);
9178 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
9180 else if( d_y < s_y ) {
9181 d_y += squareSize / 2 + squareSize / 4;
9184 d_y += squareSize / 2;
9188 d_x += squareSize / 2 - squareSize / 4;
9190 else if( d_x < s_x ) {
9191 d_x += squareSize / 2 + squareSize / 4;
9194 d_x += squareSize / 2;
9197 s_x += squareSize / 2;
9198 s_y += squareSize / 2;
9201 A_WIDTH = squareSize / 14.; //[HGM] make float
9203 DrawArrowBetweenPoints( s_x, s_y, d_x, d_y );
9205 hor = 64*s_col + 32; vert = 64*s_row + 32;
9206 for(i=0; i<= 64; i++) {
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 damage[0][vert-6>>6][hor-6>>6] = True;
9211 hor += d_col - s_col; vert += d_row - s_row;
9215 Boolean IsDrawArrowEnabled()
9217 return appData.highlightMoveWithArrow && squareSize >= 32;
9220 void DrawArrowHighlight(int fromX, int fromY, int toX,int toY)
9222 if( IsDrawArrowEnabled() && fromX >= 0 && fromY >= 0 && toX >= 0 && toY >= 0)
9223 DrawArrowBetweenSquares(fromX, fromY, toX, toY);