2 * xboard.c -- X front end for XBoard
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
8 * 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
10 * The following terms apply to Digital Equipment Corporation's copyright
12 * ------------------------------------------------------------------------
15 * Permission to use, copy, modify, and distribute this software and its
16 * documentation for any purpose and without fee is hereby granted,
17 * provided that the above copyright notice appear in all copies and that
18 * both that copyright notice and this permission notice appear in
19 * supporting documentation, and that the name of Digital not be
20 * used in advertising or publicity pertaining to distribution of the
21 * software without specific, written prior permission.
23 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
30 * ------------------------------------------------------------------------
32 * The following terms apply to the enhanced version of XBoard
33 * distributed by the Free Software Foundation:
34 * ------------------------------------------------------------------------
36 * GNU XBoard is free software: you can redistribute it and/or modify
37 * it under the terms of the GNU General Public License as published by
38 * the Free Software Foundation, either version 3 of the License, or (at
39 * your option) any later version.
41 * GNU XBoard is distributed in the hope that it will be useful, but
42 * WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44 * General Public License for more details.
46 * You should have received a copy of the GNU General Public License
47 * along with this program. If not, see http://www.gnu.org/licenses/. *
49 *------------------------------------------------------------------------
50 ** See the file ChangeLog for a revision history. */
60 #include <sys/types.h>
65 # if HAVE_SYS_SOCKET_H
66 # include <sys/socket.h>
67 # include <netinet/in.h>
69 # else /* not HAVE_SYS_SOCKET_H */
70 # if HAVE_LAN_SOCKET_H
71 # include <lan/socket.h>
73 # include <lan/netdb.h>
74 # else /* not HAVE_LAN_SOCKET_H */
75 # define OMIT_SOCKETS 1
76 # endif /* not HAVE_LAN_SOCKET_H */
77 # endif /* not HAVE_SYS_SOCKET_H */
78 #endif /* !OMIT_SOCKETS */
83 #else /* not STDC_HEADERS */
84 extern char *getenv();
87 # else /* not HAVE_STRING_H */
89 # endif /* not HAVE_STRING_H */
90 #endif /* not STDC_HEADERS */
93 # include <sys/fcntl.h>
94 #else /* not HAVE_SYS_FCNTL_H */
97 # endif /* HAVE_FCNTL_H */
98 #endif /* not HAVE_SYS_FCNTL_H */
100 #if HAVE_SYS_SYSTEMINFO_H
101 # include <sys/systeminfo.h>
102 #endif /* HAVE_SYS_SYSTEMINFO_H */
104 #if TIME_WITH_SYS_TIME
105 # include <sys/time.h>
109 # include <sys/time.h>
120 # include <sys/wait.h>
125 # define NAMLEN(dirent) strlen((dirent)->d_name)
126 # define HAVE_DIR_STRUCT
128 # define dirent direct
129 # define NAMLEN(dirent) (dirent)->d_namlen
131 # include <sys/ndir.h>
132 # define HAVE_DIR_STRUCT
135 # include <sys/dir.h>
136 # define HAVE_DIR_STRUCT
140 # define HAVE_DIR_STRUCT
144 #include <X11/Intrinsic.h>
145 #include <X11/StringDefs.h>
146 #include <X11/Shell.h>
147 #include <X11/cursorfont.h>
148 #include <X11/Xatom.h>
149 #include <X11/Xmu/Atoms.h>
151 #include <X11/Xaw3d/Dialog.h>
152 #include <X11/Xaw3d/Form.h>
153 #include <X11/Xaw3d/List.h>
154 #include <X11/Xaw3d/Label.h>
155 #include <X11/Xaw3d/SimpleMenu.h>
156 #include <X11/Xaw3d/SmeBSB.h>
157 #include <X11/Xaw3d/SmeLine.h>
158 #include <X11/Xaw3d/Box.h>
159 #include <X11/Xaw3d/MenuButton.h>
160 #include <X11/Xaw3d/Text.h>
161 #include <X11/Xaw3d/AsciiText.h>
163 #include <X11/Xaw/Dialog.h>
164 #include <X11/Xaw/Form.h>
165 #include <X11/Xaw/List.h>
166 #include <X11/Xaw/Label.h>
167 #include <X11/Xaw/SimpleMenu.h>
168 #include <X11/Xaw/SmeBSB.h>
169 #include <X11/Xaw/SmeLine.h>
170 #include <X11/Xaw/Box.h>
171 #include <X11/Xaw/MenuButton.h>
172 #include <X11/Xaw/Text.h>
173 #include <X11/Xaw/AsciiText.h>
176 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
181 #include "pixmaps/pixmaps.h"
182 #define IMAGE_EXT "xpm"
184 #define IMAGE_EXT "xim"
185 #include "bitmaps/bitmaps.h"
188 #include "bitmaps/icon_white.bm"
189 #include "bitmaps/icon_black.bm"
190 #include "bitmaps/checkmark.bm"
192 #include "frontend.h"
194 #include "backendz.h"
198 #include "xgamelist.h"
199 #include "xhistory.h"
200 #include "xedittags.h"
203 // must be moved to xengineoutput.h
205 void EngineOutputProc P((Widget w, XEvent *event,
206 String *prms, Cardinal *nprms));
207 void EvalGraphProc P((Widget w, XEvent *event,
208 String *prms, Cardinal *nprms));
215 #define usleep(t) _sleep2(((t)+500)/1000)
219 # define _(s) gettext (s)
220 # define N_(s) gettext_noop (s)
238 int main P((int argc, char **argv));
239 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
240 char *init_path, char *mode, int (*show_entry)(), char **name_return));
241 RETSIGTYPE CmailSigHandler P((int sig));
242 RETSIGTYPE IntSigHandler P((int sig));
243 RETSIGTYPE TermSizeSigHandler P((int sig));
244 void CreateGCs P((void));
245 void CreateXIMPieces P((void));
246 void CreateXPMPieces P((void));
247 void CreateXPMBoard P((char *s, int n));
248 void CreatePieces P((void));
249 void CreatePieceMenus P((void));
250 Widget CreateMenuBar P((Menu *mb));
251 Widget CreateButtonBar P ((MenuItem *mi));
252 char *FindFont P((char *pattern, int targetPxlSize));
253 void PieceMenuPopup P((Widget w, XEvent *event,
254 String *params, Cardinal *num_params));
255 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
256 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
257 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
258 u_int wreq, u_int hreq));
259 void CreateGrid P((void));
260 int EventToSquare P((int x, int limit));
261 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
262 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
263 void HandleUserMove P((Widget w, XEvent *event,
264 String *prms, Cardinal *nprms));
265 void AnimateUserMove P((Widget w, XEvent * event,
266 String * params, Cardinal * nParams));
267 void HandlePV P((Widget w, XEvent * event,
268 String * params, Cardinal * nParams));
269 void SelectPV P((Widget w, XEvent * event,
270 String * params, Cardinal * nParams));
271 void StopPV P((Widget w, XEvent * event,
272 String * params, Cardinal * nParams));
273 void WhiteClock P((Widget w, XEvent *event,
274 String *prms, Cardinal *nprms));
275 void BlackClock P((Widget w, XEvent *event,
276 String *prms, Cardinal *nprms));
277 void DrawPositionProc P((Widget w, XEvent *event,
278 String *prms, Cardinal *nprms));
279 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
281 void CommentClick P((Widget w, XEvent * event,
282 String * params, Cardinal * nParams));
283 void CommentPopUp P((char *title, char *label));
284 void CommentPopDown P((void));
285 void CommentCallback P((Widget w, XtPointer client_data,
286 XtPointer call_data));
287 void ICSInputBoxPopUp P((void));
288 void ICSInputBoxPopDown P((void));
289 void FileNamePopUp P((char *label, char *def,
290 FileProc proc, char *openMode));
291 void FileNamePopDown P((void));
292 void FileNameCallback P((Widget w, XtPointer client_data,
293 XtPointer call_data));
294 void FileNameAction P((Widget w, XEvent *event,
295 String *prms, Cardinal *nprms));
296 void AskQuestionReplyAction P((Widget w, XEvent *event,
297 String *prms, Cardinal *nprms));
298 void AskQuestionProc P((Widget w, XEvent *event,
299 String *prms, Cardinal *nprms));
300 void AskQuestionPopDown P((void));
301 void PromotionPopDown P((void));
302 void PromotionCallback P((Widget w, XtPointer client_data,
303 XtPointer call_data));
304 void EditCommentPopDown P((void));
305 void EditCommentCallback P((Widget w, XtPointer client_data,
306 XtPointer call_data));
307 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
308 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
309 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
310 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
312 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
314 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
316 void LoadPositionProc P((Widget w, XEvent *event,
317 String *prms, Cardinal *nprms));
318 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
320 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
322 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
324 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
326 void PastePositionProc P((Widget w, XEvent *event, String *prms,
328 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
329 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
330 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
331 void SavePositionProc P((Widget w, XEvent *event,
332 String *prms, Cardinal *nprms));
333 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
334 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
336 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
337 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
338 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
340 void MachineWhiteProc P((Widget w, XEvent *event,
341 String *prms, Cardinal *nprms));
342 void AnalyzeModeProc P((Widget w, XEvent *event,
343 String *prms, Cardinal *nprms));
344 void AnalyzeFileProc P((Widget w, XEvent *event,
345 String *prms, Cardinal *nprms));
346 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
348 void IcsClientProc P((Widget w, XEvent *event, String *prms,
350 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
351 void EditPositionProc P((Widget w, XEvent *event,
352 String *prms, Cardinal *nprms));
353 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
354 void EditCommentProc P((Widget w, XEvent *event,
355 String *prms, Cardinal *nprms));
356 void IcsInputBoxProc P((Widget w, XEvent *event,
357 String *prms, Cardinal *nprms));
358 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
365 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
370 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
371 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
372 void StopObservingProc P((Widget w, XEvent *event, String *prms,
374 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
376 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
377 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
379 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
380 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
385 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
387 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
388 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
390 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
392 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
394 void AutocommProc P((Widget w, XEvent *event, String *prms,
396 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
397 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
398 void AutobsProc P((Widget w, XEvent *event, String *prms,
400 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
401 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
402 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
403 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
405 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
406 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
408 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
410 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
412 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
413 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
414 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
416 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
418 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
420 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
422 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
424 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
425 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
426 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
428 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
430 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
432 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
434 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
435 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
436 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
442 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
443 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
444 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
445 void DisplayMove P((int moveNumber));
446 void DisplayTitle P((char *title));
447 void ICSInitScript P((void));
448 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
449 void ErrorPopUp P((char *title, char *text, int modal));
450 void ErrorPopDown P((void));
451 static char *ExpandPathName P((char *path));
452 static void CreateAnimVars P((void));
453 static void DragPieceMove P((int x, int y));
454 static void DrawDragPiece P((void));
455 char *ModeToWidgetName P((GameMode mode));
456 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
457 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
458 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
459 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
460 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
461 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
462 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
463 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
464 void GameListOptionsPopDown P(());
465 void ShufflePopDown P(());
466 void EnginePopDown P(());
467 void UciPopDown P(());
468 void TimeControlPopDown P(());
469 void NewVariantPopDown P(());
470 void SettingsPopDown P(());
471 void update_ics_width P(());
472 int get_term_width P(());
473 int CopyMemoProc P(());
475 * XBoard depends on Xt R4 or higher
477 int xtVersion = XtSpecificationRelease;
482 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
483 jailSquareColor, highlightSquareColor, premoveHighlightColor;
484 Pixel lowTimeWarningColor;
485 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
486 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
487 wjPieceGC, bjPieceGC, prelineGC, countGC;
488 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
489 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
490 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
491 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
492 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
493 ICSInputShell, fileNameShell, askQuestionShell;
494 Widget historyShell, evalGraphShell, gameListShell;
495 int hOffset; // [HGM] dual
496 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
497 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
498 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
499 Font clockFontID, coordFontID, countFontID;
500 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
501 XtAppContext appContext;
503 char *oldICSInteractionTitle;
507 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
509 Position commentX = -1, commentY = -1;
510 Dimension commentW, commentH;
511 typedef unsigned int BoardSize;
513 Boolean chessProgram;
515 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
516 int squareSize, smallLayout = 0, tinyLayout = 0,
517 marginW, marginH, // [HGM] for run-time resizing
518 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
519 ICSInputBoxUp = False, askQuestionUp = False,
520 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
521 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
522 Pixel timerForegroundPixel, timerBackgroundPixel;
523 Pixel buttonForegroundPixel, buttonBackgroundPixel;
524 char *chessDir, *programName, *programVersion,
525 *gameCopyFilename, *gamePasteFilename;
526 Boolean alwaysOnTop = False;
527 Boolean saveSettingsOnExit;
528 char *settingsFileName;
529 char *icsTextMenuString;
531 char *firstChessProgramNames;
532 char *secondChessProgramNames;
534 WindowPlacement wpMain;
535 WindowPlacement wpConsole;
536 WindowPlacement wpComment;
537 WindowPlacement wpMoveHistory;
538 WindowPlacement wpEvalGraph;
539 WindowPlacement wpEngineOutput;
540 WindowPlacement wpGameList;
541 WindowPlacement wpTags;
545 Pixmap pieceBitmap[2][(int)BlackPawn];
546 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
547 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
548 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
549 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
550 Pixmap xpmBoardBitmap[2];
551 int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
552 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
553 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
554 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
555 XImage *ximLightSquare, *ximDarkSquare;
558 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
559 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
561 #define White(piece) ((int)(piece) < (int)BlackPawn)
563 /* Variables for doing smooth animation. This whole thing
564 would be much easier if the board was double-buffered,
565 but that would require a fairly major rewrite. */
570 GC blitGC, pieceGC, outlineGC;
571 XPoint startSquare, prevFrame, mouseDelta;
575 int startBoardX, startBoardY;
578 /* There can be two pieces being animated at once: a player
579 can begin dragging a piece before the remote opponent has moved. */
581 static AnimState game, player;
583 /* Bitmaps for use as masks when drawing XPM pieces.
584 Need one for each black and white piece. */
585 static Pixmap xpmMask[BlackKing + 1];
587 /* This magic number is the number of intermediate frames used
588 in each half of the animation. For short moves it's reduced
589 by 1. The total number of frames will be factor * 2 + 1. */
592 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
594 MenuItem fileMenu[] = {
595 {N_("New Game"), "New Game", ResetProc},
596 {N_("New Shuffle Game ..."), "New Shuffle Game", ShuffleMenuProc},
597 {N_("New Variant ..."), "New Variant", NewVariantProc}, // [HGM] variant: not functional yet
598 {"----", NULL, NothingProc},
599 {N_("Load Game"), "Load Game", LoadGameProc},
600 {N_("Load Position"), "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 {"----", NULL, NothingProc},
605 // {N_("Load Next Position"), "Load Next Position", LoadNextPositionProc},
606 // {N_("Load Previous Position"), "Load Previous Position", LoadPrevPositionProc},
607 // {N_("Reload Same Position"), "Reload Same Position", ReloadPositionProc},
608 {N_("Save Game"), "Save Game", SaveGameProc},
609 {N_("Save Position"), "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_("Exit"), "Exit", QuitProc},
618 MenuItem editMenu[] = {
619 {N_("Copy Game"), "Copy Game", CopyGameProc},
620 {N_("Copy Position"), "Copy Position", CopyPositionProc},
621 {"----", NULL, NothingProc},
622 {N_("Paste Game"), "Paste Game", PasteGameProc},
623 {N_("Paste Position"), "Paste Position", PastePositionProc},
624 {"----", NULL, NothingProc},
625 {N_("Edit Game"), "Edit Game", EditGameProc},
626 {N_("Edit Position"), "Edit Position", EditPositionProc},
627 {"----", NULL, NothingProc},
628 {N_("Edit Tags"), "Edit Tags", EditTagsProc},
629 {N_("Edit Comment"), "Edit Comment", EditCommentProc},
630 {"----", NULL, NothingProc},
631 {N_("Revert"), "Revert", RevertProc},
632 {N_("Annotate"), "Annotate", AnnotateProc},
633 {N_("Truncate Game"), "Truncate Game", TruncateGameProc},
634 {"----", NULL, NothingProc},
635 {N_("Backward"), "Backward", BackwardProc},
636 {N_("Forward"), "Forward", ForwardProc},
637 {N_("Back to Start"), "Back to Start", ToStartProc},
638 {N_("Forward to End"), "Forward to End", ToEndProc},
642 MenuItem viewMenu[] = {
643 {N_("Flip View"), "Flip View", FlipViewProc},
644 {"----", NULL, NothingProc},
645 {N_("Engine Output"), "Show Engine Output", EngineOutputProc},
646 {N_("Evaluation Graph"), "Show Evaluation Graph", EvalGraphProc},
647 {N_("Game List"), "Show Game List", ShowGameListProc},
648 {N_("Move History"), "Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
649 {"----", NULL, NothingProc},
650 {N_("Tags"), "Show Tags", EditTagsProc},
651 {N_("Comments"), "Show Comments", EditCommentProc},
652 {N_("ICS Input Box"), "ICS Input Box", IcsInputBoxProc},
656 MenuItem modeMenu[] = {
657 {N_("Machine White"), "Machine White", MachineWhiteProc},
658 {N_("Machine Black"), "Machine Black", MachineBlackProc},
659 {N_("Two Machines"), "Two Machines", TwoMachinesProc},
660 {N_("Analysis Mode"), "Analysis Mode", AnalyzeModeProc},
661 {N_("Analyze File"), "Analyze File", AnalyzeFileProc },
662 {N_("Edit Game"), "Edit Game", EditGameProc},
663 {N_("Edit Position"), "Edit Position", EditPositionProc},
664 {N_("Training"), "Training", TrainingProc},
665 {N_("ICS Client"), "ICS Client", IcsClientProc},
666 {"----", NULL, NothingProc},
667 {N_("Pause"), "Pause", PauseProc},
671 MenuItem actionMenu[] = {
672 {N_("Accept"), "Accept", AcceptProc},
673 {N_("Decline"), "Decline", DeclineProc},
674 {N_("Rematch"), "Rematch", RematchProc},
675 {"----", NULL, NothingProc},
676 {N_("Call Flag"), "Call Flag", CallFlagProc},
677 {N_("Draw"), "Draw", DrawProc},
678 {N_("Adjourn"), "Adjourn", AdjournProc},
679 {N_("Abort"), "Abort", AbortProc},
680 {N_("Resign"), "Resign", ResignProc},
681 {"----", NULL, NothingProc},
682 {N_("Stop Observing"), "Stop Observing", StopObservingProc},
683 {N_("Stop Examining"), "Stop Examining", StopExaminingProc},
684 {N_("Upload to Examine"), "Upload to Examine", UploadProc},
685 {"----", NULL, NothingProc},
686 {N_("Adjudicate to White"), "Adjudicate to White", AdjuWhiteProc},
687 {N_("Adjudicate to Black"), "Adjudicate to Black", AdjuBlackProc},
688 {N_("Adjudicate Draw"), "Adjudicate Draw", AdjuDrawProc},
692 MenuItem engineMenu[] = {
693 {N_("Engine #1 Settings ..."), "Engine #1 Settings", FirstSettingsProc},
694 {N_("Engine #2 Settings ..."), "Engine #2 Settings", SecondSettingsProc},
695 {"----", NULL, NothingProc},
696 {N_("Move Now"), "Move Now", MoveNowProc},
697 {N_("Retract Move"), "Retract Move", RetractMoveProc},
701 MenuItem optionsMenu[] = {
702 {N_("Time Control ..."), "Time Control", TimeControlProc},
703 {N_("Common Engine ..."), "Common Engine", UciMenuProc},
704 {N_("Adjudications ..."), "Adjudications", EngineMenuProc},
705 {N_("Game List ..."), "Game List", GameListOptionsPopUp},
706 {"----", NULL, NothingProc},
707 {N_("Always Queen"), "Always Queen", AlwaysQueenProc},
708 {N_("Animate Dragging"), "Animate Dragging", AnimateDraggingProc},
709 {N_("Animate Moving"), "Animate Moving", AnimateMovingProc},
710 {N_("Auto Comment"), "Auto Comment", AutocommProc},
711 {N_("Auto Flag"), "Auto Flag", AutoflagProc},
712 {N_("Auto Flip View"), "Auto Flip View", AutoflipProc},
713 {N_("Auto Observe"), "Auto Observe", AutobsProc},
714 {N_("Auto Raise Board"), "Auto Raise Board", AutoraiseProc},
715 {N_("Auto Save"), "Auto Save", AutosaveProc},
716 {N_("Blindfold"), "Blindfold", BlindfoldProc},
717 {N_("Flash Moves"), "Flash Moves", FlashMovesProc},
718 {N_("Get Move List"), "Get Move List", GetMoveListProc},
720 {N_("Highlight Dragging"), "Highlight Dragging", HighlightDraggingProc},
722 {N_("Highlight Last Move"), "Highlight Last Move", HighlightLastMoveProc},
723 {N_("Move Sound"), "Move Sound", MoveSoundProc},
724 {N_("ICS Alarm"), "ICS Alarm", IcsAlarmProc},
725 {N_("Old Save Style"), "Old Save Style", OldSaveStyleProc},
726 {N_("Periodic Updates"), "Periodic Updates", PeriodicUpdatesProc},
727 {N_("Ponder Next Move"), "Ponder Next Move", PonderNextMoveProc},
728 {N_("Popup Exit Message"), "Popup Exit Message", PopupExitMessageProc},
729 {N_("Popup Move Errors"), "Popup Move Errors", PopupMoveErrorsProc},
730 {N_("Premove"), "Premove", PremoveProc},
731 {N_("Quiet Play"), "Quiet Play", QuietPlayProc},
732 {N_("Show Coords"), "Show Coords", ShowCoordsProc},
733 {N_("Hide Thinking"), "Hide Thinking", HideThinkingProc},
734 {N_("Test Legality"), "Test Legality", TestLegalityProc},
735 {"----", NULL, NothingProc},
736 {N_("Save Settings Now"), "Save Settings Now", SaveSettingsProc},
737 {N_("Save Settings on Exit"), "Save Settings on Exit", SaveOnExitProc},
741 MenuItem helpMenu[] = {
742 {N_("Info XBoard"), "Info XBoard", InfoProc},
743 {N_("Man XBoard"), "Man XBoard", ManProc},
744 {"----", NULL, NothingProc},
745 {N_("Hint"), "Hint", HintProc},
746 {N_("Book"), "Book", BookProc},
747 {"----", NULL, NothingProc},
748 {N_("About XBoard"), "About XBoard", AboutProc},
753 {N_("File"), "File", fileMenu},
754 {N_("Edit"), "Edit", editMenu},
755 {N_("View"), "View", viewMenu},
756 {N_("Mode"), "Mode", modeMenu},
757 {N_("Action"), "Action", actionMenu},
758 {N_("Engine"), "Engine", engineMenu},
759 {N_("Options"), "Options", optionsMenu},
760 {N_("Help"), "Help", helpMenu},
764 #define PAUSE_BUTTON "P"
765 MenuItem buttonBar[] = {
766 {"<<", "<<", ToStartProc},
767 {"<", "<", BackwardProc},
768 {PAUSE_BUTTON, PAUSE_BUTTON, PauseProc},
769 {">", ">", ForwardProc},
770 {">>", ">>", ToEndProc},
774 #define PIECE_MENU_SIZE 18
775 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
776 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
777 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
778 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
779 N_("Empty square"), N_("Clear board") },
780 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
781 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
782 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
783 N_("Empty square"), N_("Clear board") }
785 /* must be in same order as PieceMenuStrings! */
786 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
787 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
788 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
789 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
790 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
791 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
792 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
793 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
794 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
797 #define DROP_MENU_SIZE 6
798 String dropMenuStrings[DROP_MENU_SIZE] = {
799 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
801 /* must be in same order as PieceMenuStrings! */
802 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
803 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
804 WhiteRook, WhiteQueen
812 DropMenuEnables dmEnables[] = {
830 { XtNborderWidth, 0 },
831 { XtNdefaultDistance, 0 },
835 { XtNborderWidth, 0 },
836 { XtNresizable, (XtArgVal) True },
840 { XtNborderWidth, 0 },
846 { XtNjustify, (XtArgVal) XtJustifyRight },
847 { XtNlabel, (XtArgVal) "..." },
848 { XtNresizable, (XtArgVal) True },
849 { XtNresize, (XtArgVal) False }
852 Arg messageArgs[] = {
853 { XtNjustify, (XtArgVal) XtJustifyLeft },
854 { XtNlabel, (XtArgVal) "..." },
855 { XtNresizable, (XtArgVal) True },
856 { XtNresize, (XtArgVal) False }
860 { XtNborderWidth, 0 },
861 { XtNjustify, (XtArgVal) XtJustifyLeft }
864 XtResource clientResources[] = {
865 { "flashCount", "flashCount", XtRInt, sizeof(int),
866 XtOffset(AppDataPtr, flashCount), XtRImmediate,
867 (XtPointer) FLASH_COUNT },
870 XrmOptionDescRec shellOptions[] = {
871 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
872 { "-flash", "flashCount", XrmoptionNoArg, "3" },
873 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
876 XtActionsRec boardActions[] = {
877 { "DrawPosition", DrawPositionProc },
878 { "HandleUserMove", HandleUserMove },
879 { "AnimateUserMove", AnimateUserMove },
880 { "HandlePV", HandlePV },
881 { "SelectPV", SelectPV },
882 { "StopPV", StopPV },
883 { "FileNameAction", FileNameAction },
884 { "AskQuestionProc", AskQuestionProc },
885 { "AskQuestionReplyAction", AskQuestionReplyAction },
886 { "PieceMenuPopup", PieceMenuPopup },
887 { "WhiteClock", WhiteClock },
888 { "BlackClock", BlackClock },
889 { "Iconify", Iconify },
890 { "ResetProc", ResetProc },
891 { "NewVariantProc", NewVariantProc },
892 { "LoadGameProc", LoadGameProc },
893 { "LoadNextGameProc", LoadNextGameProc },
894 { "LoadPrevGameProc", LoadPrevGameProc },
895 { "LoadSelectedProc", LoadSelectedProc },
896 { "SetFilterProc", SetFilterProc },
897 { "ReloadGameProc", ReloadGameProc },
898 { "LoadPositionProc", LoadPositionProc },
899 { "LoadNextPositionProc", LoadNextPositionProc },
900 { "LoadPrevPositionProc", LoadPrevPositionProc },
901 { "ReloadPositionProc", ReloadPositionProc },
902 { "CopyPositionProc", CopyPositionProc },
903 { "PastePositionProc", PastePositionProc },
904 { "CopyGameProc", CopyGameProc },
905 { "PasteGameProc", PasteGameProc },
906 { "SaveGameProc", SaveGameProc },
907 { "SavePositionProc", SavePositionProc },
908 { "MailMoveProc", MailMoveProc },
909 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
910 { "QuitProc", QuitProc },
911 { "MachineWhiteProc", MachineWhiteProc },
912 { "MachineBlackProc", MachineBlackProc },
913 { "AnalysisModeProc", AnalyzeModeProc },
914 { "AnalyzeFileProc", AnalyzeFileProc },
915 { "TwoMachinesProc", TwoMachinesProc },
916 { "IcsClientProc", IcsClientProc },
917 { "EditGameProc", EditGameProc },
918 { "EditPositionProc", EditPositionProc },
919 { "TrainingProc", EditPositionProc },
920 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
921 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
922 { "ShowGameListProc", ShowGameListProc },
923 { "ShowMoveListProc", HistoryShowProc},
924 { "EditTagsProc", EditCommentProc },
925 { "EditCommentProc", EditCommentProc },
926 { "IcsAlarmProc", IcsAlarmProc },
927 { "IcsInputBoxProc", IcsInputBoxProc },
928 { "PauseProc", PauseProc },
929 { "AcceptProc", AcceptProc },
930 { "DeclineProc", DeclineProc },
931 { "RematchProc", RematchProc },
932 { "CallFlagProc", CallFlagProc },
933 { "DrawProc", DrawProc },
934 { "AdjournProc", AdjournProc },
935 { "AbortProc", AbortProc },
936 { "ResignProc", ResignProc },
937 { "AdjuWhiteProc", AdjuWhiteProc },
938 { "AdjuBlackProc", AdjuBlackProc },
939 { "AdjuDrawProc", AdjuDrawProc },
940 { "EnterKeyProc", EnterKeyProc },
941 { "UpKeyProc", UpKeyProc },
942 { "DownKeyProc", DownKeyProc },
943 { "StopObservingProc", StopObservingProc },
944 { "StopExaminingProc", StopExaminingProc },
945 { "UploadProc", UploadProc },
946 { "BackwardProc", BackwardProc },
947 { "ForwardProc", ForwardProc },
948 { "ToStartProc", ToStartProc },
949 { "ToEndProc", ToEndProc },
950 { "RevertProc", RevertProc },
951 { "AnnotateProc", AnnotateProc },
952 { "TruncateGameProc", TruncateGameProc },
953 { "MoveNowProc", MoveNowProc },
954 { "RetractMoveProc", RetractMoveProc },
955 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
956 { "UciMenuProc", (XtActionProc) UciMenuProc },
957 { "TimeControlProc", (XtActionProc) TimeControlProc },
958 { "AlwaysQueenProc", AlwaysQueenProc },
959 { "AnimateDraggingProc", AnimateDraggingProc },
960 { "AnimateMovingProc", AnimateMovingProc },
961 { "AutoflagProc", AutoflagProc },
962 { "AutoflipProc", AutoflipProc },
963 { "AutobsProc", AutobsProc },
964 { "AutoraiseProc", AutoraiseProc },
965 { "AutosaveProc", AutosaveProc },
966 { "BlindfoldProc", BlindfoldProc },
967 { "FlashMovesProc", FlashMovesProc },
968 { "FlipViewProc", FlipViewProc },
969 { "GetMoveListProc", GetMoveListProc },
971 { "HighlightDraggingProc", HighlightDraggingProc },
973 { "HighlightLastMoveProc", HighlightLastMoveProc },
974 { "IcsAlarmProc", IcsAlarmProc },
975 { "MoveSoundProc", MoveSoundProc },
976 { "OldSaveStyleProc", OldSaveStyleProc },
977 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
978 { "PonderNextMoveProc", PonderNextMoveProc },
979 { "PopupExitMessageProc", PopupExitMessageProc },
980 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
981 { "PremoveProc", PremoveProc },
982 { "QuietPlayProc", QuietPlayProc },
983 { "ShowCoordsProc", ShowCoordsProc },
984 { "ShowThinkingProc", ShowThinkingProc },
985 { "HideThinkingProc", HideThinkingProc },
986 { "TestLegalityProc", TestLegalityProc },
987 { "SaveSettingsProc", SaveSettingsProc },
988 { "SaveOnExitProc", SaveOnExitProc },
989 { "InfoProc", InfoProc },
990 { "ManProc", ManProc },
991 { "HintProc", HintProc },
992 { "BookProc", BookProc },
993 { "AboutGameProc", AboutGameProc },
994 { "AboutProc", AboutProc },
995 { "DebugProc", DebugProc },
996 { "NothingProc", NothingProc },
997 { "CommentClick", (XtActionProc) CommentClick },
998 { "CommentPopDown", (XtActionProc) CommentPopDown },
999 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
1000 { "TagsPopDown", (XtActionProc) TagsPopDown },
1001 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
1002 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
1003 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
1004 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
1005 { "GameListPopDown", (XtActionProc) GameListPopDown },
1006 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
1007 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1008 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
1009 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1010 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1011 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
1012 { "EnginePopDown", (XtActionProc) EnginePopDown },
1013 { "UciPopDown", (XtActionProc) UciPopDown },
1014 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
1015 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
1016 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
1017 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1020 char globalTranslations[] =
1021 ":<Key>F9: ResignProc() \n \
1022 :Ctrl<Key>n: ResetProc() \n \
1023 :Meta<Key>V: NewVariantProc() \n \
1024 :Ctrl<Key>o: LoadGameProc() \n \
1025 :Meta<Key>Next: LoadNextGameProc() \n \
1026 :Meta<Key>Prior: LoadPrevGameProc() \n \
1027 :Ctrl<Key>s: SaveGameProc() \n \
1028 :Ctrl<Key>c: CopyGameProc() \n \
1029 :Ctrl<Key>v: PasteGameProc() \n \
1030 :Ctrl<Key>O: LoadPositionProc() \n \
1031 :Shift Meta<Key>Next: LoadNextPositionProc() \n \
1032 :Shift Meta<Key>Prior: LoadPrevPositionProc() \n \
1033 :Ctrl<Key>S: SavePositionProc() \n \
1034 :Ctrl<Key>C: CopyPositionProc() \n \
1035 :Ctrl<Key>V: PastePositionProc() \n \
1036 :Ctrl<Key>q: QuitProc() \n \
1037 :Ctrl<Key>w: MachineWhiteProc() \n \
1038 :Ctrl<Key>b: MachineBlackProc() \n \
1039 :Ctrl<Key>t: TwoMachinesProc() \n \
1040 :Ctrl<Key>a: AnalysisModeProc() \n \
1041 :Ctrl<Key>f: AnalyzeFileProc() \n \
1042 :Ctrl<Key>e: EditGameProc() \n \
1043 :Ctrl<Key>E: EditPositionProc() \n \
1044 :Meta<Key>O: EngineOutputProc() \n \
1045 :Meta<Key>E: EvalGraphProc() \n \
1046 :Meta<Key>G: ShowGameListProc() \n \
1047 :Meta<Key>H: ShowMoveListProc() \n \
1048 :<Key>Pause: PauseProc() \n \
1049 :<Key>F3: AcceptProc() \n \
1050 :<Key>F4: DeclineProc() \n \
1051 :<Key>F12: RematchProc() \n \
1052 :<Key>F5: CallFlagProc() \n \
1053 :<Key>F6: DrawProc() \n \
1054 :<Key>F7: AdjournProc() \n \
1055 :<Key>F8: AbortProc() \n \
1056 :<Key>F10: StopObservingProc() \n \
1057 :<Key>F11: StopExaminingProc() \n \
1058 :Meta Ctrl<Key>F12: DebugProc() \n \
1059 :Meta<Key>End: ToEndProc() \n \
1060 :Meta<Key>Right: ForwardProc() \n \
1061 :Meta<Key>Home: ToStartProc() \n \
1062 :Meta<Key>Left: BackwardProc() \n \
1063 :<Key>Home: RevertProc() \n \
1064 :<Key>End: TruncateGameProc() \n \
1065 :Ctrl<Key>m: MoveNowProc() \n \
1066 :Ctrl<Key>x: RetractMoveProc() \n \
1067 :Meta<Key>J: EngineMenuProc() \n \
1068 :Meta<Key>U: UciMenuProc() \n \
1069 :Meta<Key>T: TimeControlProc() \n \
1070 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1071 :Ctrl<Key>F: AutoflagProc() \n \
1072 :Ctrl<Key>A: AnimateMovingProc() \n \
1073 :Ctrl<Key>P: PonderNextMoveProc() \n \
1074 :Ctrl<Key>L: TestLegalityProc() \n \
1075 :Ctrl<Key>H: HideThinkingProc() \n \
1076 :<Key>-: Iconify() \n \
1077 :<Key>F1: ManProc() \n \
1078 :<Key>F2: FlipViewProc() \n \
1079 <KeyDown>.: BackwardProc() \n \
1080 <KeyUp>.: ForwardProc() \n \
1081 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1082 \"Send to chess program:\",,1) \n \
1083 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1084 \"Send to second chess program:\",,2) \n";
1086 char boardTranslations[] =
1087 "<Btn1Down>: HandleUserMove(0) \n \
1088 Shift<Btn1Up>: HandleUserMove(1) \n \
1089 <Btn1Up>: HandleUserMove(0) \n \
1090 <Btn1Motion>: AnimateUserMove() \n \
1091 <Btn3Motion>: HandlePV() \n \
1092 <Btn3Up>: PieceMenuPopup(menuB) \n \
1093 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1094 PieceMenuPopup(menuB) \n \
1095 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1096 PieceMenuPopup(menuW) \n \
1097 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1098 PieceMenuPopup(menuW) \n \
1099 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1100 PieceMenuPopup(menuB) \n";
1102 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1103 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1105 char ICSInputTranslations[] =
1106 "<Key>Up: UpKeyProc() \n "
1107 "<Key>Down: DownKeyProc() \n "
1108 "<Key>Return: EnterKeyProc() \n";
1110 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1111 // as the widget is destroyed before the up-click can call extend-end
1112 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1114 String xboardResources[] = {
1115 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1116 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1117 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1122 /* Max possible square size */
1123 #define MAXSQSIZE 256
1125 static int xpm_avail[MAXSQSIZE];
1127 #ifdef HAVE_DIR_STRUCT
1129 /* Extract piece size from filename */
1131 xpm_getsize(name, len, ext)
1142 if ((p=strchr(name, '.')) == NULL ||
1143 StrCaseCmp(p+1, ext) != 0)
1149 while (*p && isdigit(*p))
1156 /* Setup xpm_avail */
1158 xpm_getavail(dirname, ext)
1166 for (i=0; i<MAXSQSIZE; ++i)
1169 if (appData.debugMode)
1170 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1172 dir = opendir(dirname);
1175 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1176 programName, dirname);
1180 while ((ent=readdir(dir)) != NULL) {
1181 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1182 if (i > 0 && i < MAXSQSIZE)
1192 xpm_print_avail(fp, ext)
1198 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1199 for (i=1; i<MAXSQSIZE; ++i) {
1205 /* Return XPM piecesize closest to size */
1207 xpm_closest_to(dirname, size, ext)
1213 int sm_diff = MAXSQSIZE;
1217 xpm_getavail(dirname, ext);
1219 if (appData.debugMode)
1220 xpm_print_avail(stderr, ext);
1222 for (i=1; i<MAXSQSIZE; ++i) {
1225 diff = (diff<0) ? -diff : diff;
1226 if (diff < sm_diff) {
1234 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1240 #else /* !HAVE_DIR_STRUCT */
1241 /* If we are on a system without a DIR struct, we can't
1242 read the directory, so we can't collect a list of
1243 filenames, etc., so we can't do any size-fitting. */
1245 xpm_closest_to(dirname, size, ext)
1250 fprintf(stderr, _("\
1251 Warning: No DIR structure found on this system --\n\
1252 Unable to autosize for XPM/XIM pieces.\n\
1253 Please report this error to frankm@hiwaay.net.\n\
1254 Include system type & operating system in message.\n"));
1257 #endif /* HAVE_DIR_STRUCT */
1259 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1260 "magenta", "cyan", "white" };
1264 TextColors textColors[(int)NColorClasses];
1266 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1268 parse_color(str, which)
1272 char *p, buf[100], *d;
1275 if (strlen(str) > 99) /* watch bounds on buf */
1280 for (i=0; i<which; ++i) {
1287 /* Could be looking at something like:
1289 .. in which case we want to stop on a comma also */
1290 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1294 return -1; /* Use default for empty field */
1297 if (which == 2 || isdigit(*p))
1300 while (*p && isalpha(*p))
1305 for (i=0; i<8; ++i) {
1306 if (!StrCaseCmp(buf, cnames[i]))
1307 return which? (i+40) : (i+30);
1309 if (!StrCaseCmp(buf, "default")) return -1;
1311 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1316 parse_cpair(cc, str)
1320 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1321 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1326 /* bg and attr are optional */
1327 textColors[(int)cc].bg = parse_color(str, 1);
1328 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1329 textColors[(int)cc].attr = 0;
1335 /* Arrange to catch delete-window events */
1336 Atom wm_delete_window;
1338 CatchDeleteWindow(Widget w, String procname)
1341 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1342 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1343 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1350 XtSetArg(args[0], XtNiconic, False);
1351 XtSetValues(shellWidget, args, 1);
1353 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1356 //---------------------------------------------------------------------------------------------------------
1357 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1360 #define CW_USEDEFAULT (1<<31)
1361 #define ICS_TEXT_MENU_SIZE 90
1362 #define DEBUG_FILE "xboard.debug"
1363 #define SetCurrentDirectory chdir
1364 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1368 // these two must some day move to frontend.h, when they are implemented
1369 Boolean GameListIsUp();
1371 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1374 // front-end part of option handling
1376 // [HGM] This platform-dependent table provides the location for storing the color info
1377 extern char *crWhite, * crBlack;
1381 &appData.whitePieceColor,
1382 &appData.blackPieceColor,
1383 &appData.lightSquareColor,
1384 &appData.darkSquareColor,
1385 &appData.highlightSquareColor,
1386 &appData.premoveHighlightColor,
1387 &appData.lowTimeWarningColor,
1398 // [HGM] font: keep a font for each square size, even non-stndard ones
1399 #define NUM_SIZES 18
1400 #define MAX_SIZE 130
1401 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1402 char *fontTable[NUM_FONTS][MAX_SIZE];
1405 ParseFont(char *name, int number)
1406 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1408 if(sscanf(name, "size%d:", &size)) {
1409 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1410 // defer processing it until we know if it matches our board size
1411 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1412 fontTable[number][size] = strdup(strchr(name, ':')+1);
1413 fontValid[number][size] = True;
1418 case 0: // CLOCK_FONT
1419 appData.clockFont = strdup(name);
1421 case 1: // MESSAGE_FONT
1422 appData.font = strdup(name);
1424 case 2: // COORD_FONT
1425 appData.coordFont = strdup(name);
1430 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1435 { // only 2 fonts currently
1436 appData.clockFont = CLOCK_FONT_NAME;
1437 appData.coordFont = COORD_FONT_NAME;
1438 appData.font = DEFAULT_FONT_NAME;
1443 { // no-op, until we identify the code for this already in XBoard and move it here
1447 ParseColor(int n, char *name)
1448 { // in XBoard, just copy the color-name string
1449 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1453 ParseTextAttribs(ColorClass cc, char *s)
1455 (&appData.colorShout)[cc] = strdup(s);
1459 ParseBoardSize(void *addr, char *name)
1461 appData.boardSize = strdup(name);
1466 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1470 SetCommPortDefaults()
1471 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1474 // [HGM] args: these three cases taken out to stay in front-end
1476 SaveFontArg(FILE *f, ArgDescriptor *ad)
1479 int i, n = (int)ad->argLoc;
1481 case 0: // CLOCK_FONT
1482 name = appData.clockFont;
1484 case 1: // MESSAGE_FONT
1485 name = appData.font;
1487 case 2: // COORD_FONT
1488 name = appData.coordFont;
1493 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1494 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1495 fontTable[n][squareSize] = strdup(name);
1496 fontValid[n][squareSize] = True;
1499 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1500 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1505 { // nothing to do, as the sounds are at all times represented by their text-string names already
1509 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1510 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1511 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1515 SaveColor(FILE *f, ArgDescriptor *ad)
1516 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1517 if(colorVariable[(int)ad->argLoc])
1518 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1522 SaveBoardSize(FILE *f, char *name, void *addr)
1523 { // wrapper to shield back-end from BoardSize & sizeInfo
1524 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1528 ParseCommPortSettings(char *s)
1529 { // no such option in XBoard (yet)
1532 extern Widget engineOutputShell;
1533 extern Widget tagsShell, editTagsShell;
1535 GetActualPlacement(Widget wg, WindowPlacement *wp)
1545 XtSetArg(args[i], XtNx, &x); i++;
1546 XtSetArg(args[i], XtNy, &y); i++;
1547 XtSetArg(args[i], XtNwidth, &w); i++;
1548 XtSetArg(args[i], XtNheight, &h); i++;
1549 XtGetValues(wg, args, i);
1558 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1559 // In XBoard this will have to wait until awareness of window parameters is implemented
1560 GetActualPlacement(shellWidget, &wpMain);
1561 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1562 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1563 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1564 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1565 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1566 else GetActualPlacement(editShell, &wpComment);
1567 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1568 else GetActualPlacement(editTagsShell, &wpTags);
1572 PrintCommPortSettings(FILE *f, char *name)
1573 { // This option does not exist in XBoard
1577 MySearchPath(char *installDir, char *name, char *fullname)
1578 { // just append installDir and name. Perhaps ExpandPath should be used here?
1579 name = ExpandPathName(name);
1580 if(name && name[0] == '/')
1581 safeStrCpy(fullname, name, MSG_SIZ );
1583 sprintf(fullname, "%s%c%s", installDir, '/', name);
1589 MyGetFullPathName(char *name, char *fullname)
1590 { // should use ExpandPath?
1591 name = ExpandPathName(name);
1592 safeStrCpy(fullname, name, MSG_SIZ );
1597 EnsureOnScreen(int *x, int *y, int minX, int minY)
1604 { // [HGM] args: allows testing if main window is realized from back-end
1605 return xBoardWindow != 0;
1609 PopUpStartupDialog()
1610 { // start menu not implemented in XBoard
1614 ConvertToLine(int argc, char **argv)
1616 static char line[128*1024], buf[1024];
1620 for(i=1; i<argc; i++)
1622 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1623 && argv[i][0] != '{' )
1624 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1626 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1627 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1630 line[strlen(line)-1] = NULLCHAR;
1634 //--------------------------------------------------------------------------------------------
1636 extern Boolean twoBoards, partnerUp;
1639 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1641 #define BoardSize int
1642 void InitDrawingSizes(BoardSize boardSize, int flags)
1643 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1644 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1646 XtGeometryResult gres;
1649 if(!formWidget) return;
1652 * Enable shell resizing.
1654 shellArgs[0].value = (XtArgVal) &w;
1655 shellArgs[1].value = (XtArgVal) &h;
1656 XtGetValues(shellWidget, shellArgs, 2);
1658 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1659 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1660 XtSetValues(shellWidget, &shellArgs[2], 4);
1662 XtSetArg(args[0], XtNdefaultDistance, &sep);
1663 XtGetValues(formWidget, args, 1);
1665 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1666 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1668 hOffset = boardWidth + 10;
1669 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1670 secondSegments[i] = gridSegments[i];
1671 secondSegments[i].x1 += hOffset;
1672 secondSegments[i].x2 += hOffset;
1675 XtSetArg(args[0], XtNwidth, boardWidth);
1676 XtSetArg(args[1], XtNheight, boardHeight);
1677 XtSetValues(boardWidget, args, 2);
1679 timerWidth = (boardWidth - sep) / 2;
1680 XtSetArg(args[0], XtNwidth, timerWidth);
1681 XtSetValues(whiteTimerWidget, args, 1);
1682 XtSetValues(blackTimerWidget, args, 1);
1684 XawFormDoLayout(formWidget, False);
1686 if (appData.titleInWindow) {
1688 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1689 XtSetArg(args[i], XtNheight, &h); i++;
1690 XtGetValues(titleWidget, args, i);
1692 w = boardWidth - 2*bor;
1694 XtSetArg(args[0], XtNwidth, &w);
1695 XtGetValues(menuBarWidget, args, 1);
1696 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1699 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1700 if (gres != XtGeometryYes && appData.debugMode) {
1702 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1703 programName, gres, w, h, wr, hr);
1707 XawFormDoLayout(formWidget, True);
1710 * Inhibit shell resizing.
1712 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1713 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1714 shellArgs[4].value = shellArgs[2].value = w;
1715 shellArgs[5].value = shellArgs[3].value = h;
1716 XtSetValues(shellWidget, &shellArgs[0], 6);
1718 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1721 for(i=0; i<4; i++) {
1723 for(p=0; p<=(int)WhiteKing; p++)
1724 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1725 if(gameInfo.variant == VariantShogi) {
1726 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1727 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1728 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1729 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1730 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1733 if(gameInfo.variant == VariantGothic) {
1734 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1737 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1738 xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
1739 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1742 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1743 for(p=0; p<=(int)WhiteKing; p++)
1744 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1745 if(gameInfo.variant == VariantShogi) {
1746 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1747 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1748 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1749 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1750 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1753 if(gameInfo.variant == VariantGothic) {
1754 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1757 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1758 ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
1759 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1764 for(i=0; i<2; i++) {
1766 for(p=0; p<=(int)WhiteKing; p++)
1767 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1768 if(gameInfo.variant == VariantShogi) {
1769 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1770 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1771 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1772 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1773 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1776 if(gameInfo.variant == VariantGothic) {
1777 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1780 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1781 pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
1782 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1797 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1798 XSetWindowAttributes window_attributes;
1800 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1801 XrmValue vFrom, vTo;
1802 XtGeometryResult gres;
1805 int forceMono = False;
1807 srandom(time(0)); // [HGM] book: make random truly random
1809 setbuf(stdout, NULL);
1810 setbuf(stderr, NULL);
1813 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1814 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1818 programName = strrchr(argv[0], '/');
1819 if (programName == NULL)
1820 programName = argv[0];
1825 XtSetLanguageProc(NULL, NULL, NULL);
1826 bindtextdomain(PACKAGE, LOCALEDIR);
1827 textdomain(PACKAGE);
1831 XtAppInitialize(&appContext, "XBoard", shellOptions,
1832 XtNumber(shellOptions),
1833 &argc, argv, xboardResources, NULL, 0);
1834 appData.boardSize = "";
1835 InitAppData(ConvertToLine(argc, argv));
1837 if (p == NULL) p = "/tmp";
1838 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1839 gameCopyFilename = (char*) malloc(i);
1840 gamePasteFilename = (char*) malloc(i);
1841 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1842 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1844 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1845 clientResources, XtNumber(clientResources),
1848 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1849 static char buf[MSG_SIZ];
1850 EscapeExpand(buf, appData.initString);
1851 appData.initString = strdup(buf);
1852 EscapeExpand(buf, appData.secondInitString);
1853 appData.secondInitString = strdup(buf);
1854 EscapeExpand(buf, appData.firstComputerString);
1855 appData.firstComputerString = strdup(buf);
1856 EscapeExpand(buf, appData.secondComputerString);
1857 appData.secondComputerString = strdup(buf);
1860 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1863 if (chdir(chessDir) != 0) {
1864 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1870 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1871 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1872 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1873 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1876 setbuf(debugFP, NULL);
1879 /* [HGM,HR] make sure board size is acceptable */
1880 if(appData.NrFiles > BOARD_FILES ||
1881 appData.NrRanks > BOARD_RANKS )
1882 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1885 /* This feature does not work; animation needs a rewrite */
1886 appData.highlightDragging = FALSE;
1890 xDisplay = XtDisplay(shellWidget);
1891 xScreen = DefaultScreen(xDisplay);
1892 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1894 gameInfo.variant = StringToVariant(appData.variant);
1895 InitPosition(FALSE);
1898 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1900 if (isdigit(appData.boardSize[0])) {
1901 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1902 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1903 &fontPxlSize, &smallLayout, &tinyLayout);
1905 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1906 programName, appData.boardSize);
1910 /* Find some defaults; use the nearest known size */
1911 SizeDefaults *szd, *nearest;
1912 int distance = 99999;
1913 nearest = szd = sizeDefaults;
1914 while (szd->name != NULL) {
1915 if (abs(szd->squareSize - squareSize) < distance) {
1917 distance = abs(szd->squareSize - squareSize);
1918 if (distance == 0) break;
1922 if (i < 2) lineGap = nearest->lineGap;
1923 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1924 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1925 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1926 if (i < 6) smallLayout = nearest->smallLayout;
1927 if (i < 7) tinyLayout = nearest->tinyLayout;
1930 SizeDefaults *szd = sizeDefaults;
1931 if (*appData.boardSize == NULLCHAR) {
1932 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1933 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1936 if (szd->name == NULL) szd--;
1937 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1939 while (szd->name != NULL &&
1940 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1941 if (szd->name == NULL) {
1942 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1943 programName, appData.boardSize);
1947 squareSize = szd->squareSize;
1948 lineGap = szd->lineGap;
1949 clockFontPxlSize = szd->clockFontPxlSize;
1950 coordFontPxlSize = szd->coordFontPxlSize;
1951 fontPxlSize = szd->fontPxlSize;
1952 smallLayout = szd->smallLayout;
1953 tinyLayout = szd->tinyLayout;
1954 // [HGM] font: use defaults from settings file if available and not overruled
1956 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
1957 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
1958 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
1959 appData.font = fontTable[MESSAGE_FONT][squareSize];
1960 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
1961 appData.coordFont = fontTable[COORD_FONT][squareSize];
1963 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1964 if (strlen(appData.pixmapDirectory) > 0) {
1965 p = ExpandPathName(appData.pixmapDirectory);
1967 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1968 appData.pixmapDirectory);
1971 if (appData.debugMode) {
1972 fprintf(stderr, _("\
1973 XBoard square size (hint): %d\n\
1974 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1976 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1977 if (appData.debugMode) {
1978 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1981 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1983 /* [HR] height treated separately (hacked) */
1984 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1985 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1986 if (appData.showJail == 1) {
1987 /* Jail on top and bottom */
1988 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1989 XtSetArg(boardArgs[2], XtNheight,
1990 boardHeight + 2*(lineGap + squareSize));
1991 } else if (appData.showJail == 2) {
1993 XtSetArg(boardArgs[1], XtNwidth,
1994 boardWidth + 2*(lineGap + squareSize));
1995 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1998 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1999 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2003 * Determine what fonts to use.
2005 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2006 clockFontID = XLoadFont(xDisplay, appData.clockFont);
2007 clockFontStruct = XQueryFont(xDisplay, clockFontID);
2008 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2009 coordFontID = XLoadFont(xDisplay, appData.coordFont);
2010 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2011 appData.font = FindFont(appData.font, fontPxlSize);
2012 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
2013 countFontStruct = XQueryFont(xDisplay, countFontID);
2014 // appData.font = FindFont(appData.font, fontPxlSize);
2016 xdb = XtDatabase(xDisplay);
2017 XrmPutStringResource(&xdb, "*font", appData.font);
2020 * Detect if there are not enough colors available and adapt.
2022 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2023 appData.monoMode = True;
2026 if (!appData.monoMode) {
2027 vFrom.addr = (caddr_t) appData.lightSquareColor;
2028 vFrom.size = strlen(appData.lightSquareColor);
2029 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2030 if (vTo.addr == NULL) {
2031 appData.monoMode = True;
2034 lightSquareColor = *(Pixel *) vTo.addr;
2037 if (!appData.monoMode) {
2038 vFrom.addr = (caddr_t) appData.darkSquareColor;
2039 vFrom.size = strlen(appData.darkSquareColor);
2040 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2041 if (vTo.addr == NULL) {
2042 appData.monoMode = True;
2045 darkSquareColor = *(Pixel *) vTo.addr;
2048 if (!appData.monoMode) {
2049 vFrom.addr = (caddr_t) appData.whitePieceColor;
2050 vFrom.size = strlen(appData.whitePieceColor);
2051 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2052 if (vTo.addr == NULL) {
2053 appData.monoMode = True;
2056 whitePieceColor = *(Pixel *) vTo.addr;
2059 if (!appData.monoMode) {
2060 vFrom.addr = (caddr_t) appData.blackPieceColor;
2061 vFrom.size = strlen(appData.blackPieceColor);
2062 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2063 if (vTo.addr == NULL) {
2064 appData.monoMode = True;
2067 blackPieceColor = *(Pixel *) vTo.addr;
2071 if (!appData.monoMode) {
2072 vFrom.addr = (caddr_t) appData.highlightSquareColor;
2073 vFrom.size = strlen(appData.highlightSquareColor);
2074 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2075 if (vTo.addr == NULL) {
2076 appData.monoMode = True;
2079 highlightSquareColor = *(Pixel *) vTo.addr;
2083 if (!appData.monoMode) {
2084 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
2085 vFrom.size = strlen(appData.premoveHighlightColor);
2086 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2087 if (vTo.addr == NULL) {
2088 appData.monoMode = True;
2091 premoveHighlightColor = *(Pixel *) vTo.addr;
2096 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2099 if (appData.bitmapDirectory == NULL ||
2100 appData.bitmapDirectory[0] == NULLCHAR)
2101 appData.bitmapDirectory = DEF_BITMAP_DIR;
2104 if (appData.lowTimeWarning && !appData.monoMode) {
2105 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2106 vFrom.size = strlen(appData.lowTimeWarningColor);
2107 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2108 if (vTo.addr == NULL)
2109 appData.monoMode = True;
2111 lowTimeWarningColor = *(Pixel *) vTo.addr;
2114 if (appData.monoMode && appData.debugMode) {
2115 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2116 (unsigned long) XWhitePixel(xDisplay, xScreen),
2117 (unsigned long) XBlackPixel(xDisplay, xScreen));
2120 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2121 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2122 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2123 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2124 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2125 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2126 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2127 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2128 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2129 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2131 if (appData.colorize) {
2133 _("%s: can't parse color names; disabling colorization\n"),
2136 appData.colorize = FALSE;
2138 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2139 textColors[ColorNone].attr = 0;
2141 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2147 layoutName = "tinyLayout";
2148 } else if (smallLayout) {
2149 layoutName = "smallLayout";
2151 layoutName = "normalLayout";
2153 /* Outer layoutWidget is there only to provide a name for use in
2154 resources that depend on the layout style */
2156 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2157 layoutArgs, XtNumber(layoutArgs));
2159 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2160 formArgs, XtNumber(formArgs));
2161 XtSetArg(args[0], XtNdefaultDistance, &sep);
2162 XtGetValues(formWidget, args, 1);
2165 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2166 XtSetArg(args[0], XtNtop, XtChainTop);
2167 XtSetArg(args[1], XtNbottom, XtChainTop);
2168 XtSetArg(args[2], XtNright, XtChainLeft);
2169 XtSetValues(menuBarWidget, args, 3);
2171 widgetList[j++] = whiteTimerWidget =
2172 XtCreateWidget("whiteTime", labelWidgetClass,
2173 formWidget, timerArgs, XtNumber(timerArgs));
2174 XtSetArg(args[0], XtNfont, clockFontStruct);
2175 XtSetArg(args[1], XtNtop, XtChainTop);
2176 XtSetArg(args[2], XtNbottom, XtChainTop);
2177 XtSetValues(whiteTimerWidget, args, 3);
2179 widgetList[j++] = blackTimerWidget =
2180 XtCreateWidget("blackTime", 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(blackTimerWidget, args, 3);
2187 if (appData.titleInWindow) {
2188 widgetList[j++] = titleWidget =
2189 XtCreateWidget("title", labelWidgetClass, formWidget,
2190 titleArgs, XtNumber(titleArgs));
2191 XtSetArg(args[0], XtNtop, XtChainTop);
2192 XtSetArg(args[1], XtNbottom, XtChainTop);
2193 XtSetValues(titleWidget, args, 2);
2196 if (appData.showButtonBar) {
2197 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2198 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2199 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2200 XtSetArg(args[2], XtNtop, XtChainTop);
2201 XtSetArg(args[3], XtNbottom, XtChainTop);
2202 XtSetValues(buttonBarWidget, args, 4);
2205 widgetList[j++] = messageWidget =
2206 XtCreateWidget("message", labelWidgetClass, formWidget,
2207 messageArgs, XtNumber(messageArgs));
2208 XtSetArg(args[0], XtNtop, XtChainTop);
2209 XtSetArg(args[1], XtNbottom, XtChainTop);
2210 XtSetValues(messageWidget, args, 2);
2212 widgetList[j++] = boardWidget =
2213 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2214 XtNumber(boardArgs));
2216 XtManageChildren(widgetList, j);
2218 timerWidth = (boardWidth - sep) / 2;
2219 XtSetArg(args[0], XtNwidth, timerWidth);
2220 XtSetValues(whiteTimerWidget, args, 1);
2221 XtSetValues(blackTimerWidget, args, 1);
2223 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2224 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2225 XtGetValues(whiteTimerWidget, args, 2);
2227 if (appData.showButtonBar) {
2228 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2229 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2230 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2234 * formWidget uses these constraints but they are stored
2238 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2239 XtSetValues(menuBarWidget, args, i);
2240 if (appData.titleInWindow) {
2243 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2244 XtSetValues(whiteTimerWidget, args, i);
2246 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2247 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2248 XtSetValues(blackTimerWidget, args, i);
2250 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2251 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2252 XtSetValues(titleWidget, args, i);
2254 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2255 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2256 XtSetValues(messageWidget, args, i);
2257 if (appData.showButtonBar) {
2259 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2260 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2261 XtSetValues(buttonBarWidget, args, i);
2265 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2266 XtSetValues(whiteTimerWidget, args, i);
2268 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2269 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2270 XtSetValues(blackTimerWidget, args, i);
2272 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2273 XtSetValues(titleWidget, args, i);
2275 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2276 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2277 XtSetValues(messageWidget, args, i);
2278 if (appData.showButtonBar) {
2280 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2281 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2282 XtSetValues(buttonBarWidget, args, i);
2287 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2288 XtSetValues(whiteTimerWidget, args, i);
2290 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2291 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2292 XtSetValues(blackTimerWidget, args, i);
2294 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2295 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2296 XtSetValues(messageWidget, args, i);
2297 if (appData.showButtonBar) {
2299 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2300 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2301 XtSetValues(buttonBarWidget, args, i);
2305 XtSetArg(args[0], XtNfromVert, messageWidget);
2306 XtSetArg(args[1], XtNtop, XtChainTop);
2307 XtSetArg(args[2], XtNbottom, XtChainBottom);
2308 XtSetArg(args[3], XtNleft, XtChainLeft);
2309 XtSetArg(args[4], XtNright, XtChainRight);
2310 XtSetValues(boardWidget, args, 5);
2312 XtRealizeWidget(shellWidget);
2315 XtSetArg(args[0], XtNx, wpMain.x);
2316 XtSetArg(args[1], XtNy, wpMain.y);
2317 XtSetValues(shellWidget, args, 2);
2321 * Correct the width of the message and title widgets.
2322 * It is not known why some systems need the extra fudge term.
2323 * The value "2" is probably larger than needed.
2325 XawFormDoLayout(formWidget, False);
2327 #define WIDTH_FUDGE 2
2329 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2330 XtSetArg(args[i], XtNheight, &h); i++;
2331 XtGetValues(messageWidget, args, i);
2332 if (appData.showButtonBar) {
2334 XtSetArg(args[i], XtNwidth, &w); i++;
2335 XtGetValues(buttonBarWidget, args, i);
2336 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2338 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2341 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2342 if (gres != XtGeometryYes && appData.debugMode) {
2343 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2344 programName, gres, w, h, wr, hr);
2347 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2348 /* The size used for the child widget in layout lags one resize behind
2349 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2351 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2352 if (gres != XtGeometryYes && appData.debugMode) {
2353 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2354 programName, gres, w, h, wr, hr);
2357 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2358 XtSetArg(args[1], XtNright, XtChainRight);
2359 XtSetValues(messageWidget, args, 2);
2361 if (appData.titleInWindow) {
2363 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2364 XtSetArg(args[i], XtNheight, &h); i++;
2365 XtGetValues(titleWidget, args, i);
2367 w = boardWidth - 2*bor;
2369 XtSetArg(args[0], XtNwidth, &w);
2370 XtGetValues(menuBarWidget, args, 1);
2371 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2374 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2375 if (gres != XtGeometryYes && appData.debugMode) {
2377 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2378 programName, gres, w, h, wr, hr);
2381 XawFormDoLayout(formWidget, True);
2383 xBoardWindow = XtWindow(boardWidget);
2385 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2386 // not need to go into InitDrawingSizes().
2390 * Create X checkmark bitmap and initialize option menu checks.
2392 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2393 checkmark_bits, checkmark_width, checkmark_height);
2394 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2395 if (appData.alwaysPromoteToQueen) {
2396 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2399 if (appData.animateDragging) {
2400 XtSetValues(XtNameToWidget(menuBarWidget,
2401 "menuOptions.Animate Dragging"),
2404 if (appData.animate) {
2405 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2408 if (appData.autoComment) {
2409 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2412 if (appData.autoCallFlag) {
2413 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2416 if (appData.autoFlipView) {
2417 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2420 if (appData.autoObserve) {
2421 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2424 if (appData.autoRaiseBoard) {
2425 XtSetValues(XtNameToWidget(menuBarWidget,
2426 "menuOptions.Auto Raise Board"), args, 1);
2428 if (appData.autoSaveGames) {
2429 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2432 if (appData.saveGameFile[0] != NULLCHAR) {
2433 /* Can't turn this off from menu */
2434 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2436 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2440 if (appData.blindfold) {
2441 XtSetValues(XtNameToWidget(menuBarWidget,
2442 "menuOptions.Blindfold"), args, 1);
2444 if (appData.flashCount > 0) {
2445 XtSetValues(XtNameToWidget(menuBarWidget,
2446 "menuOptions.Flash Moves"),
2449 if (appData.getMoveList) {
2450 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2454 if (appData.highlightDragging) {
2455 XtSetValues(XtNameToWidget(menuBarWidget,
2456 "menuOptions.Highlight Dragging"),
2460 if (appData.highlightLastMove) {
2461 XtSetValues(XtNameToWidget(menuBarWidget,
2462 "menuOptions.Highlight Last Move"),
2465 if (appData.icsAlarm) {
2466 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2469 if (appData.ringBellAfterMoves) {
2470 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2473 if (appData.oldSaveStyle) {
2474 XtSetValues(XtNameToWidget(menuBarWidget,
2475 "menuOptions.Old Save Style"), args, 1);
2477 if (appData.periodicUpdates) {
2478 XtSetValues(XtNameToWidget(menuBarWidget,
2479 "menuOptions.Periodic Updates"), args, 1);
2481 if (appData.ponderNextMove) {
2482 XtSetValues(XtNameToWidget(menuBarWidget,
2483 "menuOptions.Ponder Next Move"), args, 1);
2485 if (appData.popupExitMessage) {
2486 XtSetValues(XtNameToWidget(menuBarWidget,
2487 "menuOptions.Popup Exit Message"), args, 1);
2489 if (appData.popupMoveErrors) {
2490 XtSetValues(XtNameToWidget(menuBarWidget,
2491 "menuOptions.Popup Move Errors"), args, 1);
2493 if (appData.premove) {
2494 XtSetValues(XtNameToWidget(menuBarWidget,
2495 "menuOptions.Premove"), args, 1);
2497 if (appData.quietPlay) {
2498 XtSetValues(XtNameToWidget(menuBarWidget,
2499 "menuOptions.Quiet Play"), args, 1);
2501 if (appData.showCoords) {
2502 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2505 if (appData.hideThinkingFromHuman) {
2506 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2509 if (appData.testLegality) {
2510 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2513 if (saveSettingsOnExit) {
2514 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2521 ReadBitmap(&wIconPixmap, "icon_white.bm",
2522 icon_white_bits, icon_white_width, icon_white_height);
2523 ReadBitmap(&bIconPixmap, "icon_black.bm",
2524 icon_black_bits, icon_black_width, icon_black_height);
2525 iconPixmap = wIconPixmap;
2527 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2528 XtSetValues(shellWidget, args, i);
2531 * Create a cursor for the board widget.
2533 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2534 XChangeWindowAttributes(xDisplay, xBoardWindow,
2535 CWCursor, &window_attributes);
2538 * Inhibit shell resizing.
2540 shellArgs[0].value = (XtArgVal) &w;
2541 shellArgs[1].value = (XtArgVal) &h;
2542 XtGetValues(shellWidget, shellArgs, 2);
2543 shellArgs[4].value = shellArgs[2].value = w;
2544 shellArgs[5].value = shellArgs[3].value = h;
2545 XtSetValues(shellWidget, &shellArgs[2], 4);
2546 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2547 marginH = h - boardHeight;
2549 CatchDeleteWindow(shellWidget, "QuitProc");
2554 if (appData.bitmapDirectory[0] != NULLCHAR) {
2558 CreateXPMBoard(appData.liteBackTextureFile, 1);
2559 CreateXPMBoard(appData.darkBackTextureFile, 0);
2563 /* Create regular pieces */
2564 if (!useImages) CreatePieces();
2569 if (appData.animate || appData.animateDragging)
2572 XtAugmentTranslations(formWidget,
2573 XtParseTranslationTable(globalTranslations));
2574 XtAugmentTranslations(boardWidget,
2575 XtParseTranslationTable(boardTranslations));
2576 XtAugmentTranslations(whiteTimerWidget,
2577 XtParseTranslationTable(whiteTranslations));
2578 XtAugmentTranslations(blackTimerWidget,
2579 XtParseTranslationTable(blackTranslations));
2581 /* Why is the following needed on some versions of X instead
2582 * of a translation? */
2583 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2584 (XtEventHandler) EventProc, NULL);
2587 /* [AS] Restore layout */
2588 if( wpMoveHistory.visible ) {
2592 if( wpEvalGraph.visible )
2597 if( wpEngineOutput.visible ) {
2598 EngineOutputPopUp();
2603 if (errorExitStatus == -1) {
2604 if (appData.icsActive) {
2605 /* We now wait until we see "login:" from the ICS before
2606 sending the logon script (problems with timestamp otherwise) */
2607 /*ICSInitScript();*/
2608 if (appData.icsInputBox) ICSInputBoxPopUp();
2612 signal(SIGWINCH, TermSizeSigHandler);
2614 signal(SIGINT, IntSigHandler);
2615 signal(SIGTERM, IntSigHandler);
2616 if (*appData.cmailGameName != NULLCHAR) {
2617 signal(SIGUSR1, CmailSigHandler);
2620 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2622 XtSetKeyboardFocus(shellWidget, formWidget);
2624 XtAppMainLoop(appContext);
2625 if (appData.debugMode) fclose(debugFP); // [DM] debug
2632 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2633 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2635 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2636 unlink(gameCopyFilename);
2637 unlink(gamePasteFilename);
2640 RETSIGTYPE TermSizeSigHandler(int sig)
2653 CmailSigHandler(sig)
2659 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2661 /* Activate call-back function CmailSigHandlerCallBack() */
2662 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2664 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2668 CmailSigHandlerCallBack(isr, closure, message, count, error)
2676 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2678 /**** end signal code ****/
2684 /* try to open the icsLogon script, either in the location given
2685 * or in the users HOME directory
2692 f = fopen(appData.icsLogon, "r");
2695 homedir = getenv("HOME");
2696 if (homedir != NULL)
2698 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2699 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2700 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2701 f = fopen(buf, "r");
2706 ProcessICSInitScript(f);
2708 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2717 EditCommentPopDown();
2732 if (!menuBarWidget) return;
2733 w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2735 DisplayError("menuEdit.Revert", 0);
2737 XtSetSensitive(w, !grey);
2739 w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2741 DisplayError("menuEdit.Annotate", 0);
2743 XtSetSensitive(w, !grey);
2748 SetMenuEnables(enab)
2752 if (!menuBarWidget) return;
2753 while (enab->name != NULL) {
2754 w = XtNameToWidget(menuBarWidget, enab->name);
2756 DisplayError(enab->name, 0);
2758 XtSetSensitive(w, enab->value);
2764 Enables icsEnables[] = {
2765 { "menuFile.Mail Move", False },
2766 { "menuFile.Reload CMail Message", False },
2767 { "menuMode.Machine Black", False },
2768 { "menuMode.Machine White", False },
2769 { "menuMode.Analysis Mode", False },
2770 { "menuMode.Analyze File", False },
2771 { "menuMode.Two Machines", False },
2773 { "menuHelp.Hint", False },
2774 { "menuHelp.Book", False },
2775 { "menuEngine.Move Now", False },
2776 { "menuOptions.Periodic Updates", False },
2777 { "menuOptions.Hide Thinking", False },
2778 { "menuOptions.Ponder Next Move", False },
2779 { "menuEngine.Engine #1 Settings", False },
2781 { "menuEngine.Engine #2 Settings", False },
2782 { "menuEdit.Annotate", False },
2786 Enables ncpEnables[] = {
2787 { "menuFile.Mail Move", False },
2788 { "menuFile.Reload CMail Message", False },
2789 { "menuMode.Machine White", False },
2790 { "menuMode.Machine Black", False },
2791 { "menuMode.Analysis Mode", False },
2792 { "menuMode.Analyze File", False },
2793 { "menuMode.Two Machines", False },
2794 { "menuMode.ICS Client", False },
2795 { "menuView.ICS Input Box", False },
2796 { "Action", False },
2797 { "menuEdit.Revert", False },
2798 { "menuEdit.Annotate", False },
2799 { "menuEngine.Engine #1 Settings", False },
2800 { "menuEngine.Engine #2 Settings", False },
2801 { "menuEngine.Move Now", False },
2802 { "menuEngine.Retract Move", False },
2803 { "menuOptions.Auto Comment", False },
2804 { "menuOptions.Auto Flag", False },
2805 { "menuOptions.Auto Flip View", False },
2806 { "menuOptions.Auto Observe", False },
2807 { "menuOptions.Auto Raise Board", False },
2808 { "menuOptions.Get Move List", False },
2809 { "menuOptions.ICS Alarm", False },
2810 { "menuOptions.Move Sound", False },
2811 { "menuOptions.Quiet Play", False },
2812 { "menuOptions.Hide Thinking", False },
2813 { "menuOptions.Periodic Updates", False },
2814 { "menuOptions.Ponder Next Move", False },
2815 { "menuHelp.Hint", False },
2816 { "menuHelp.Book", False },
2820 Enables gnuEnables[] = {
2821 { "menuMode.ICS Client", False },
2822 { "menuView.ICS Input Box", False },
2823 { "menuAction.Accept", False },
2824 { "menuAction.Decline", False },
2825 { "menuAction.Rematch", False },
2826 { "menuAction.Adjourn", False },
2827 { "menuAction.Stop Examining", False },
2828 { "menuAction.Stop Observing", False },
2829 { "menuAction.Upload to Examine", False },
2830 { "menuEdit.Revert", False },
2831 { "menuEdit.Annotate", False },
2832 { "menuOptions.Auto Comment", False },
2833 { "menuOptions.Auto Observe", False },
2834 { "menuOptions.Auto Raise Board", False },
2835 { "menuOptions.Get Move List", False },
2836 { "menuOptions.Premove", False },
2837 { "menuOptions.Quiet Play", False },
2839 /* The next two options rely on SetCmailMode being called *after* */
2840 /* SetGNUMode so that when GNU is being used to give hints these */
2841 /* menu options are still available */
2843 { "menuFile.Mail Move", False },
2844 { "menuFile.Reload CMail Message", False },
2848 Enables cmailEnables[] = {
2850 { "menuAction.Call Flag", False },
2851 { "menuAction.Draw", True },
2852 { "menuAction.Adjourn", False },
2853 { "menuAction.Abort", False },
2854 { "menuAction.Stop Observing", False },
2855 { "menuAction.Stop Examining", False },
2856 { "menuFile.Mail Move", True },
2857 { "menuFile.Reload CMail Message", True },
2861 Enables trainingOnEnables[] = {
2862 { "menuMode.Edit Comment", False },
2863 { "menuMode.Pause", False },
2864 { "menuEdit.Forward", False },
2865 { "menuEdit.Backward", False },
2866 { "menuEdit.Forward to End", False },
2867 { "menuEdit.Back to Start", False },
2868 { "menuEngine.Move Now", False },
2869 { "menuEdit.Truncate Game", False },
2873 Enables trainingOffEnables[] = {
2874 { "menuMode.Edit Comment", True },
2875 { "menuMode.Pause", True },
2876 { "menuEdit.Forward", True },
2877 { "menuEdit.Backward", True },
2878 { "menuEdit.Forward to End", True },
2879 { "menuEdit.Back to Start", True },
2880 { "menuEngine.Move Now", True },
2881 { "menuEdit.Truncate Game", True },
2885 Enables machineThinkingEnables[] = {
2886 { "menuFile.Load Game", False },
2887 // { "menuFile.Load Next Game", False },
2888 // { "menuFile.Load Previous Game", False },
2889 // { "menuFile.Reload Same Game", False },
2890 { "menuEdit.Paste Game", False },
2891 { "menuFile.Load Position", False },
2892 // { "menuFile.Load Next Position", False },
2893 // { "menuFile.Load Previous Position", False },
2894 // { "menuFile.Reload Same Position", False },
2895 { "menuEdit.Paste Position", False },
2896 { "menuMode.Machine White", False },
2897 { "menuMode.Machine Black", False },
2898 { "menuMode.Two Machines", False },
2899 { "menuEngine.Retract Move", False },
2903 Enables userThinkingEnables[] = {
2904 { "menuFile.Load Game", True },
2905 // { "menuFile.Load Next Game", True },
2906 // { "menuFile.Load Previous Game", True },
2907 // { "menuFile.Reload Same Game", True },
2908 { "menuEdit.Paste Game", True },
2909 { "menuFile.Load Position", True },
2910 // { "menuFile.Load Next Position", True },
2911 // { "menuFile.Load Previous Position", True },
2912 // { "menuFile.Reload Same Position", True },
2913 { "menuEdit.Paste Position", True },
2914 { "menuMode.Machine White", True },
2915 { "menuMode.Machine Black", True },
2916 { "menuMode.Two Machines", True },
2917 { "menuEngine.Retract Move", True },
2923 SetMenuEnables(icsEnables);
2926 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2927 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2934 SetMenuEnables(ncpEnables);
2940 SetMenuEnables(gnuEnables);
2946 SetMenuEnables(cmailEnables);
2952 SetMenuEnables(trainingOnEnables);
2953 if (appData.showButtonBar) {
2954 XtSetSensitive(buttonBarWidget, False);
2960 SetTrainingModeOff()
2962 SetMenuEnables(trainingOffEnables);
2963 if (appData.showButtonBar) {
2964 XtSetSensitive(buttonBarWidget, True);
2969 SetUserThinkingEnables()
2971 if (appData.noChessProgram) return;
2972 SetMenuEnables(userThinkingEnables);
2976 SetMachineThinkingEnables()
2978 if (appData.noChessProgram) return;
2979 SetMenuEnables(machineThinkingEnables);
2981 case MachinePlaysBlack:
2982 case MachinePlaysWhite:
2983 case TwoMachinesPlay:
2984 XtSetSensitive(XtNameToWidget(menuBarWidget,
2985 ModeToWidgetName(gameMode)), True);
2992 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2993 #define HISTORY_SIZE 64
\r
2994 static char *history[HISTORY_SIZE];
\r
2995 int histIn = 0, histP = 0;
\r
2998 SaveInHistory(char *cmd)
\r
3000 if (history[histIn] != NULL) {
\r
3001 free(history[histIn]);
\r
3002 history[histIn] = NULL;
\r
3004 if (*cmd == NULLCHAR) return;
\r
3005 history[histIn] = StrSave(cmd);
\r
3006 histIn = (histIn + 1) % HISTORY_SIZE;
\r
3007 if (history[histIn] != NULL) {
\r
3008 free(history[histIn]);
\r
3009 history[histIn] = NULL;
\r
3015 PrevInHistory(char *cmd)
\r
3018 if (histP == histIn) {
\r
3019 if (history[histIn] != NULL) free(history[histIn]);
\r
3020 history[histIn] = StrSave(cmd);
\r
3022 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
3023 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
3025 return history[histP];
\r
3031 if (histP == histIn) return NULL;
\r
3032 histP = (histP + 1) % HISTORY_SIZE;
\r
3033 return history[histP];
\r
3035 // end of borrowed code
\r
3037 #define Abs(n) ((n)<0 ? -(n) : (n))
3040 * Find a font that matches "pattern" that is as close as
3041 * possible to the targetPxlSize. Prefer fonts that are k
3042 * pixels smaller to fonts that are k pixels larger. The
3043 * pattern must be in the X Consortium standard format,
3044 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3045 * The return value should be freed with XtFree when no
3049 FindFont(pattern, targetPxlSize)
3053 char **fonts, *p, *best, *scalable, *scalableTail;
3054 int i, j, nfonts, minerr, err, pxlSize;
3057 char **missing_list;
3059 char *def_string, *base_fnt_lst, strInt[3];
3061 XFontStruct **fnt_list;
3063 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3064 snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
3065 p = strstr(pattern, "--");
3066 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3067 strcat(base_fnt_lst, strInt);
3068 strcat(base_fnt_lst, strchr(p + 2, '-'));
3070 if ((fntSet = XCreateFontSet(xDisplay,
3074 &def_string)) == NULL) {
3076 fprintf(stderr, _("Unable to create font set.\n"));
3080 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3082 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3084 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3085 programName, pattern);
3093 for (i=0; i<nfonts; i++) {
3096 if (*p != '-') continue;
3098 if (*p == NULLCHAR) break;
3099 if (*p++ == '-') j++;
3101 if (j < 7) continue;
3104 scalable = fonts[i];
3107 err = pxlSize - targetPxlSize;
3108 if (Abs(err) < Abs(minerr) ||
3109 (minerr > 0 && err < 0 && -err == minerr)) {
3115 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3116 /* If the error is too big and there is a scalable font,
3117 use the scalable font. */
3118 int headlen = scalableTail - scalable;
3119 p = (char *) XtMalloc(strlen(scalable) + 10);
3120 while (isdigit(*scalableTail)) scalableTail++;
3121 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3123 p = (char *) XtMalloc(strlen(best) + 2);
3124 safeStrCpy(p, best, strlen(best)+1 );
3126 if (appData.debugMode) {
3127 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3128 pattern, targetPxlSize, p);
3131 if (missing_count > 0)
3132 XFreeStringList(missing_list);
3133 XFreeFontSet(xDisplay, fntSet);
3135 XFreeFontNames(fonts);
3142 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3143 | GCBackground | GCFunction | GCPlaneMask;
3144 XGCValues gc_values;
3147 gc_values.plane_mask = AllPlanes;
3148 gc_values.line_width = lineGap;
3149 gc_values.line_style = LineSolid;
3150 gc_values.function = GXcopy;
3152 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3153 gc_values.background = XBlackPixel(xDisplay, xScreen);
3154 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3156 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3157 gc_values.background = XWhitePixel(xDisplay, xScreen);
3158 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3159 XSetFont(xDisplay, coordGC, coordFontID);
3161 // [HGM] make font for holdings counts (white on black0
3162 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3163 gc_values.background = XBlackPixel(xDisplay, xScreen);
3164 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3165 XSetFont(xDisplay, countGC, countFontID);
3167 if (appData.monoMode) {
3168 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3169 gc_values.background = XWhitePixel(xDisplay, xScreen);
3170 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3172 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3173 gc_values.background = XBlackPixel(xDisplay, xScreen);
3174 lightSquareGC = wbPieceGC
3175 = XtGetGC(shellWidget, value_mask, &gc_values);
3177 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3178 gc_values.background = XWhitePixel(xDisplay, xScreen);
3179 darkSquareGC = bwPieceGC
3180 = XtGetGC(shellWidget, value_mask, &gc_values);
3182 if (DefaultDepth(xDisplay, xScreen) == 1) {
3183 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3184 gc_values.function = GXcopyInverted;
3185 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3186 gc_values.function = GXcopy;
3187 if (XBlackPixel(xDisplay, xScreen) == 1) {
3188 bwPieceGC = darkSquareGC;
3189 wbPieceGC = copyInvertedGC;
3191 bwPieceGC = copyInvertedGC;
3192 wbPieceGC = lightSquareGC;
3196 gc_values.foreground = highlightSquareColor;
3197 gc_values.background = highlightSquareColor;
3198 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3200 gc_values.foreground = premoveHighlightColor;
3201 gc_values.background = premoveHighlightColor;
3202 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3204 gc_values.foreground = lightSquareColor;
3205 gc_values.background = darkSquareColor;
3206 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3208 gc_values.foreground = darkSquareColor;
3209 gc_values.background = lightSquareColor;
3210 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3212 gc_values.foreground = jailSquareColor;
3213 gc_values.background = jailSquareColor;
3214 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3216 gc_values.foreground = whitePieceColor;
3217 gc_values.background = darkSquareColor;
3218 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3220 gc_values.foreground = whitePieceColor;
3221 gc_values.background = lightSquareColor;
3222 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3224 gc_values.foreground = whitePieceColor;
3225 gc_values.background = jailSquareColor;
3226 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3228 gc_values.foreground = blackPieceColor;
3229 gc_values.background = darkSquareColor;
3230 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3232 gc_values.foreground = blackPieceColor;
3233 gc_values.background = lightSquareColor;
3234 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3236 gc_values.foreground = blackPieceColor;
3237 gc_values.background = jailSquareColor;
3238 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3242 void loadXIM(xim, xmask, filename, dest, mask)
3255 fp = fopen(filename, "rb");
3257 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3264 for (y=0; y<h; ++y) {
3265 for (x=0; x<h; ++x) {
3270 XPutPixel(xim, x, y, blackPieceColor);
3272 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3275 XPutPixel(xim, x, y, darkSquareColor);
3277 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3280 XPutPixel(xim, x, y, whitePieceColor);
3282 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3285 XPutPixel(xim, x, y, lightSquareColor);
3287 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3293 /* create Pixmap of piece */
3294 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3296 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3299 /* create Pixmap of clipmask
3300 Note: We assume the white/black pieces have the same
3301 outline, so we make only 6 masks. This is okay
3302 since the XPM clipmask routines do the same. */
3304 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3306 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3309 /* now create the 1-bit version */
3310 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3313 values.foreground = 1;
3314 values.background = 0;
3316 /* Don't use XtGetGC, not read only */
3317 maskGC = XCreateGC(xDisplay, *mask,
3318 GCForeground | GCBackground, &values);
3319 XCopyPlane(xDisplay, temp, *mask, maskGC,
3320 0, 0, squareSize, squareSize, 0, 0, 1);
3321 XFreePixmap(xDisplay, temp);
3326 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3328 void CreateXIMPieces()
3333 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3338 /* The XSynchronize calls were copied from CreatePieces.
3339 Not sure if needed, but can't hurt */
3340 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3343 /* temp needed by loadXIM() */
3344 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3345 0, 0, ss, ss, AllPlanes, XYPixmap);
3347 if (strlen(appData.pixmapDirectory) == 0) {
3351 if (appData.monoMode) {
3352 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3356 fprintf(stderr, _("\nLoading XIMs...\n"));
3358 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3359 fprintf(stderr, "%d", piece+1);
3360 for (kind=0; kind<4; kind++) {
3361 fprintf(stderr, ".");
3362 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3363 ExpandPathName(appData.pixmapDirectory),
3364 piece <= (int) WhiteKing ? "" : "w",
3365 pieceBitmapNames[piece],
3367 ximPieceBitmap[kind][piece] =
3368 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3369 0, 0, ss, ss, AllPlanes, XYPixmap);
3370 if (appData.debugMode)
3371 fprintf(stderr, _("(File:%s:) "), buf);
3372 loadXIM(ximPieceBitmap[kind][piece],
3374 &(xpmPieceBitmap2[kind][piece]),
3375 &(ximMaskPm2[piece]));
3376 if(piece <= (int)WhiteKing)
3377 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3379 fprintf(stderr," ");
3381 /* Load light and dark squares */
3382 /* If the LSQ and DSQ pieces don't exist, we will
3383 draw them with solid squares. */
3384 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3385 if (access(buf, 0) != 0) {
3389 fprintf(stderr, _("light square "));
3391 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3392 0, 0, ss, ss, AllPlanes, XYPixmap);
3393 if (appData.debugMode)
3394 fprintf(stderr, _("(File:%s:) "), buf);
3396 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3397 fprintf(stderr, _("dark square "));
3398 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3399 ExpandPathName(appData.pixmapDirectory), ss);
3400 if (appData.debugMode)
3401 fprintf(stderr, _("(File:%s:) "), buf);
3403 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3404 0, 0, ss, ss, AllPlanes, XYPixmap);
3405 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3406 xpmJailSquare = xpmLightSquare;
3408 fprintf(stderr, _("Done.\n"));
3410 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3414 void CreateXPMBoard(char *s, int kind)
3418 if(s == NULL || *s == 0 || *s == '*') return;
3419 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3420 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3424 void CreateXPMPieces()
3428 u_int ss = squareSize;
3430 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3431 XpmColorSymbol symbols[4];
3433 /* The XSynchronize calls were copied from CreatePieces.
3434 Not sure if needed, but can't hurt */
3435 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3437 /* Setup translations so piece colors match square colors */
3438 symbols[0].name = "light_piece";
3439 symbols[0].value = appData.whitePieceColor;
3440 symbols[1].name = "dark_piece";
3441 symbols[1].value = appData.blackPieceColor;
3442 symbols[2].name = "light_square";
3443 symbols[2].value = appData.lightSquareColor;
3444 symbols[3].name = "dark_square";
3445 symbols[3].value = appData.darkSquareColor;
3447 attr.valuemask = XpmColorSymbols;
3448 attr.colorsymbols = symbols;
3449 attr.numsymbols = 4;
3451 if (appData.monoMode) {
3452 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3456 if (strlen(appData.pixmapDirectory) == 0) {
3457 XpmPieces* pieces = builtInXpms;
3460 while (pieces->size != squareSize && pieces->size) pieces++;
3461 if (!pieces->size) {
3462 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3465 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3466 for (kind=0; kind<4; kind++) {
3468 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3469 pieces->xpm[piece][kind],
3470 &(xpmPieceBitmap2[kind][piece]),
3471 NULL, &attr)) != 0) {
3472 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3476 if(piece <= (int) WhiteKing)
3477 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3481 xpmJailSquare = xpmLightSquare;
3485 fprintf(stderr, _("\nLoading XPMs...\n"));
3488 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3489 fprintf(stderr, "%d ", piece+1);
3490 for (kind=0; kind<4; kind++) {
3491 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3492 ExpandPathName(appData.pixmapDirectory),
3493 piece > (int) WhiteKing ? "w" : "",
3494 pieceBitmapNames[piece],
3496 if (appData.debugMode) {
3497 fprintf(stderr, _("(File:%s:) "), buf);
3499 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3500 &(xpmPieceBitmap2[kind][piece]),
3501 NULL, &attr)) != 0) {
3502 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3503 // [HGM] missing: read of unorthodox piece failed; substitute King.
3504 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3505 ExpandPathName(appData.pixmapDirectory),
3507 if (appData.debugMode) {
3508 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3510 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3511 &(xpmPieceBitmap2[kind][piece]),
3515 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3520 if(piece <= (int) WhiteKing)
3521 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3524 /* Load light and dark squares */
3525 /* If the LSQ and DSQ pieces don't exist, we will
3526 draw them with solid squares. */
3527 fprintf(stderr, _("light square "));
3528 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3529 if (access(buf, 0) != 0) {
3533 if (appData.debugMode)
3534 fprintf(stderr, _("(File:%s:) "), buf);
3536 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3537 &xpmLightSquare, NULL, &attr)) != 0) {
3538 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3541 fprintf(stderr, _("dark square "));
3542 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3543 ExpandPathName(appData.pixmapDirectory), ss);
3544 if (appData.debugMode) {
3545 fprintf(stderr, _("(File:%s:) "), buf);
3547 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3548 &xpmDarkSquare, NULL, &attr)) != 0) {
3549 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3553 xpmJailSquare = xpmLightSquare;
3554 fprintf(stderr, _("Done.\n"));
3556 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3559 #endif /* HAVE_LIBXPM */
3562 /* No built-in bitmaps */
3567 u_int ss = squareSize;
3569 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3572 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3573 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3574 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3575 pieceBitmapNames[piece],
3576 ss, kind == SOLID ? 's' : 'o');
3577 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3578 if(piece <= (int)WhiteKing)
3579 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3583 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3587 /* With built-in bitmaps */
3590 BuiltInBits* bib = builtInBits;
3593 u_int ss = squareSize;
3595 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3598 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3600 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3601 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3602 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3603 pieceBitmapNames[piece],
3604 ss, kind == SOLID ? 's' : 'o');
3605 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3606 bib->bits[kind][piece], ss, ss);
3607 if(piece <= (int)WhiteKing)
3608 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3612 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3617 void ReadBitmap(pm, name, bits, wreq, hreq)
3620 unsigned char bits[];
3626 char msg[MSG_SIZ], fullname[MSG_SIZ];
3628 if (*appData.bitmapDirectory != NULLCHAR) {
3629 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3630 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3631 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3632 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3633 &w, &h, pm, &x_hot, &y_hot);
3634 fprintf(stderr, "load %s\n", name);
3635 if (errcode != BitmapSuccess) {
3637 case BitmapOpenFailed:
3638 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3640 case BitmapFileInvalid:
3641 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3643 case BitmapNoMemory:
3644 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3648 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3652 fprintf(stderr, _("%s: %s...using built-in\n"),
3654 } else if (w != wreq || h != hreq) {
3656 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3657 programName, fullname, w, h, wreq, hreq);
3663 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3672 if (lineGap == 0) return;
3674 /* [HR] Split this into 2 loops for non-square boards. */
3676 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3677 gridSegments[i].x1 = 0;
3678 gridSegments[i].x2 =
3679 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3680 gridSegments[i].y1 = gridSegments[i].y2
3681 = lineGap / 2 + (i * (squareSize + lineGap));
3684 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3685 gridSegments[j + i].y1 = 0;
3686 gridSegments[j + i].y2 =
3687 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3688 gridSegments[j + i].x1 = gridSegments[j + i].x2
3689 = lineGap / 2 + (j * (squareSize + lineGap));
3693 static void MenuBarSelect(w, addr, index)
3698 XtActionProc proc = (XtActionProc) addr;
3700 (proc)(NULL, NULL, NULL, NULL);
3703 void CreateMenuBarPopup(parent, name, mb)
3713 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3716 XtSetArg(args[j], XtNleftMargin, 20); j++;
3717 XtSetArg(args[j], XtNrightMargin, 20); j++;
3719 while (mi->string != NULL) {
3720 if (strcmp(mi->string, "----") == 0) {
3721 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3724 XtSetArg(args[j], XtNlabel, XtNewString(mi->string));
3725 entry = XtCreateManagedWidget(mi->ref, smeBSBObjectClass,
3727 XtAddCallback(entry, XtNcallback,
3728 (XtCallbackProc) MenuBarSelect,
3729 (caddr_t) mi->proc);
3735 Widget CreateMenuBar(mb)
3739 Widget anchor, menuBar;
3741 char menuName[MSG_SIZ];
3744 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3745 XtSetArg(args[j], XtNvSpace, 0); j++;
3746 XtSetArg(args[j], XtNborderWidth, 0); j++;
3747 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3748 formWidget, args, j);
3750 while (mb->name != NULL) {
3751 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3752 strncat(menuName, mb->ref, MSG_SIZ - strlen(menuName) - 1);
3754 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3757 shortName[0] = mb->name[0];
3758 shortName[1] = NULLCHAR;
3759 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3762 XtSetArg(args[j], XtNlabel, XtNewString(mb->name)); j++;
3765 XtSetArg(args[j], XtNborderWidth, 0); j++;
3766 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3768 CreateMenuBarPopup(menuBar, menuName, mb);
3774 Widget CreateButtonBar(mi)
3778 Widget button, buttonBar;
3782 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3784 XtSetArg(args[j], XtNhSpace, 0); j++;
3786 XtSetArg(args[j], XtNborderWidth, 0); j++;
3787 XtSetArg(args[j], XtNvSpace, 0); j++;
3788 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3789 formWidget, args, j);
3791 while (mi->string != NULL) {
3794 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3795 XtSetArg(args[j], XtNborderWidth, 0); j++;
3797 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3798 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3799 buttonBar, args, j);
3800 XtAddCallback(button, XtNcallback,
3801 (XtCallbackProc) MenuBarSelect,
3802 (caddr_t) mi->proc);
3809 CreatePieceMenu(name, color)
3816 ChessSquare selection;
3818 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3819 boardWidget, args, 0);
3821 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3822 String item = pieceMenuStrings[color][i];
3824 if (strcmp(item, "----") == 0) {
3825 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3828 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3829 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3831 selection = pieceMenuTranslation[color][i];
3832 XtAddCallback(entry, XtNcallback,
3833 (XtCallbackProc) PieceMenuSelect,
3834 (caddr_t) selection);
3835 if (selection == WhitePawn || selection == BlackPawn) {
3836 XtSetArg(args[0], XtNpopupOnEntry, entry);
3837 XtSetValues(menu, args, 1);
3850 ChessSquare selection;
3852 whitePieceMenu = CreatePieceMenu("menuW", 0);
3853 blackPieceMenu = CreatePieceMenu("menuB", 1);
3855 XtRegisterGrabAction(PieceMenuPopup, True,
3856 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3857 GrabModeAsync, GrabModeAsync);
3859 XtSetArg(args[0], XtNlabel, _("Drop"));
3860 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3861 boardWidget, args, 1);
3862 for (i = 0; i < DROP_MENU_SIZE; i++) {
3863 String item = dropMenuStrings[i];
3865 if (strcmp(item, "----") == 0) {
3866 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3869 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3870 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3872 selection = dropMenuTranslation[i];
3873 XtAddCallback(entry, XtNcallback,
3874 (XtCallbackProc) DropMenuSelect,
3875 (caddr_t) selection);
3880 void SetupDropMenu()
3888 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3889 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3890 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3891 dmEnables[i].piece);
3892 XtSetSensitive(entry, p != NULL || !appData.testLegality
3893 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3894 && !appData.icsActive));
3896 while (p && *p++ == dmEnables[i].piece) count++;
3897 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3899 XtSetArg(args[j], XtNlabel, label); j++;
3900 XtSetValues(entry, args, j);
3904 void PieceMenuPopup(w, event, params, num_params)
3908 Cardinal *num_params;
3910 String whichMenu; int menuNr;
3911 if (event->type == ButtonRelease)
3912 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3913 else if (event->type == ButtonPress)
3914 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3916 case 0: whichMenu = params[0]; break;
3917 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3919 case -1: if (errorUp) ErrorPopDown();
3922 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3925 static void PieceMenuSelect(w, piece, junk)
3930 if (pmFromX < 0 || pmFromY < 0) return;
3931 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3934 static void DropMenuSelect(w, piece, junk)
3939 if (pmFromX < 0 || pmFromY < 0) return;
3940 DropMenuEvent(piece, pmFromX, pmFromY);
3943 void WhiteClock(w, event, prms, nprms)
3949 if (gameMode == EditPosition || gameMode == IcsExamining) {
3950 SetWhiteToPlayEvent();
3951 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3956 void BlackClock(w, event, prms, nprms)
3962 if (gameMode == EditPosition || gameMode == IcsExamining) {
3963 SetBlackToPlayEvent();
3964 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3971 * If the user selects on a border boundary, return -1; if off the board,
3972 * return -2. Otherwise map the event coordinate to the square.
3974 int EventToSquare(x, limit)
3982 if ((x % (squareSize + lineGap)) >= squareSize)
3984 x /= (squareSize + lineGap);
3990 static void do_flash_delay(msec)
3996 static void drawHighlight(file, rank, gc)
4002 if (lineGap == 0 || appData.blindfold) return;
4005 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
4006 (squareSize + lineGap);
4007 y = lineGap/2 + rank * (squareSize + lineGap);
4009 x = lineGap/2 + file * (squareSize + lineGap);
4010 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
4011 (squareSize + lineGap);
4014 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
4015 squareSize+lineGap, squareSize+lineGap);
4018 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
4019 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4022 SetHighlights(fromX, fromY, toX, toY)
4023 int fromX, fromY, toX, toY;
4025 if (hi1X != fromX || hi1Y != fromY) {
4026 if (hi1X >= 0 && hi1Y >= 0) {
4027 drawHighlight(hi1X, hi1Y, lineGC);
4029 } // [HGM] first erase both, then draw new!
4030 if (hi2X != toX || hi2Y != toY) {
4031 if (hi2X >= 0 && hi2Y >= 0) {
4032 drawHighlight(hi2X, hi2Y, lineGC);
4035 if (hi1X != fromX || hi1Y != fromY) {
4036 if (fromX >= 0 && fromY >= 0) {
4037 drawHighlight(fromX, fromY, highlineGC);
4040 if (hi2X != toX || hi2Y != toY) {
4041 if (toX >= 0 && toY >= 0) {
4042 drawHighlight(toX, toY, highlineGC);
4054 SetHighlights(-1, -1, -1, -1);
4059 SetPremoveHighlights(fromX, fromY, toX, toY)
4060 int fromX, fromY, toX, toY;
4062 if (pm1X != fromX || pm1Y != fromY) {
4063 if (pm1X >= 0 && pm1Y >= 0) {
4064 drawHighlight(pm1X, pm1Y, lineGC);
4066 if (fromX >= 0 && fromY >= 0) {
4067 drawHighlight(fromX, fromY, prelineGC);
4070 if (pm2X != toX || pm2Y != toY) {
4071 if (pm2X >= 0 && pm2Y >= 0) {
4072 drawHighlight(pm2X, pm2Y, lineGC);
4074 if (toX >= 0 && toY >= 0) {
4075 drawHighlight(toX, toY, prelineGC);
4085 ClearPremoveHighlights()
4087 SetPremoveHighlights(-1, -1, -1, -1);
4090 static int CutOutSquare(x, y, x0, y0, kind)
4091 int x, y, *x0, *y0, kind;
4093 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
4094 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
4096 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
4097 if(textureW[kind] < W*squareSize)
4098 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
4100 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
4101 if(textureH[kind] < H*squareSize)
4102 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
4104 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
4108 static void BlankSquare(x, y, color, piece, dest, fac)
4109 int x, y, color, fac;
4112 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
4114 if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
4115 XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
4116 squareSize, squareSize, x*fac, y*fac);
4118 if (useImages && useImageSqs) {
4122 pm = xpmLightSquare;
4127 case 2: /* neutral */
4132 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4133 squareSize, squareSize, x*fac, y*fac);
4143 case 2: /* neutral */
4148 XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
4153 I split out the routines to draw a piece so that I could
4154 make a generic flash routine.
4156 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4158 int square_color, x, y;
4161 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4162 switch (square_color) {
4164 case 2: /* neutral */
4166 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4167 ? *pieceToOutline(piece)
4168 : *pieceToSolid(piece),
4169 dest, bwPieceGC, 0, 0,
4170 squareSize, squareSize, x, y);
4173 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4174 ? *pieceToSolid(piece)
4175 : *pieceToOutline(piece),
4176 dest, wbPieceGC, 0, 0,
4177 squareSize, squareSize, x, y);
4182 static void monoDrawPiece(piece, square_color, x, y, dest)
4184 int square_color, x, y;
4187 switch (square_color) {
4189 case 2: /* neutral */
4191 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4192 ? *pieceToOutline(piece)
4193 : *pieceToSolid(piece),
4194 dest, bwPieceGC, 0, 0,
4195 squareSize, squareSize, x, y, 1);
4198 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4199 ? *pieceToSolid(piece)
4200 : *pieceToOutline(piece),
4201 dest, wbPieceGC, 0, 0,
4202 squareSize, squareSize, x, y, 1);
4207 static void colorDrawPiece(piece, square_color, x, y, dest)
4209 int square_color, x, y;
4212 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4213 switch (square_color) {
4215 XCopyPlane(xDisplay, *pieceToSolid(piece),
4216 dest, (int) piece < (int) BlackPawn
4217 ? wlPieceGC : blPieceGC, 0, 0,
4218 squareSize, squareSize, x, y, 1);
4221 XCopyPlane(xDisplay, *pieceToSolid(piece),
4222 dest, (int) piece < (int) BlackPawn
4223 ? wdPieceGC : bdPieceGC, 0, 0,
4224 squareSize, squareSize, x, y, 1);
4226 case 2: /* neutral */
4228 XCopyPlane(xDisplay, *pieceToSolid(piece),
4229 dest, (int) piece < (int) BlackPawn
4230 ? wjPieceGC : bjPieceGC, 0, 0,
4231 squareSize, squareSize, x, y, 1);
4236 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4238 int square_color, x, y;
4241 int kind, p = piece;
4243 switch (square_color) {
4245 case 2: /* neutral */
4247 if ((int)piece < (int) BlackPawn) {
4255 if ((int)piece < (int) BlackPawn) {
4263 if(appData.upsideDown && flipView) kind ^= 2; // swap white and black pieces
4264 if(useTexture & square_color+1) {
4265 BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
4266 XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
4267 XSetClipOrigin(xDisplay, wlPieceGC, x, y);
4268 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);
4269 XSetClipMask(xDisplay, wlPieceGC, None);
4270 XSetClipOrigin(xDisplay, wlPieceGC, 0, 0);
4272 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4273 dest, wlPieceGC, 0, 0,
4274 squareSize, squareSize, x, y);
4277 typedef void (*DrawFunc)();
4279 DrawFunc ChooseDrawFunc()
4281 if (appData.monoMode) {
4282 if (DefaultDepth(xDisplay, xScreen) == 1) {
4283 return monoDrawPiece_1bit;
4285 return monoDrawPiece;
4289 return colorDrawPieceImage;
4291 return colorDrawPiece;
4295 /* [HR] determine square color depending on chess variant. */
4296 static int SquareColor(row, column)
4301 if (gameInfo.variant == VariantXiangqi) {
4302 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4304 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4306 } else if (row <= 4) {
4312 square_color = ((column + row) % 2) == 1;
4315 /* [hgm] holdings: next line makes all holdings squares light */
4316 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4318 return square_color;
4321 void DrawSquare(row, column, piece, do_flash)
4322 int row, column, do_flash;
4325 int square_color, x, y, direction, font_ascent, font_descent;
4328 XCharStruct overall;
4332 /* Calculate delay in milliseconds (2-delays per complete flash) */
4333 flash_delay = 500 / appData.flashRate;
4336 x = lineGap + ((BOARD_WIDTH-1)-column) *
4337 (squareSize + lineGap);
4338 y = lineGap + row * (squareSize + lineGap);
4340 x = lineGap + column * (squareSize + lineGap);
4341 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4342 (squareSize + lineGap);
4345 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4347 square_color = SquareColor(row, column);
4349 if ( // [HGM] holdings: blank out area between board and holdings
4350 column == BOARD_LEFT-1 || column == BOARD_RGHT
4351 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4352 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4353 BlankSquare(x, y, 2, EmptySquare, xBoardWindow, 1);
4355 // [HGM] print piece counts next to holdings
4356 string[1] = NULLCHAR;
4357 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4358 string[0] = '0' + piece;
4359 XTextExtents(countFontStruct, string, 1, &direction,
4360 &font_ascent, &font_descent, &overall);
4361 if (appData.monoMode) {
4362 XDrawImageString(xDisplay, xBoardWindow, countGC,
4363 x + squareSize - overall.width - 2,
4364 y + font_ascent + 1, string, 1);
4366 XDrawString(xDisplay, xBoardWindow, countGC,
4367 x + squareSize - overall.width - 2,
4368 y + font_ascent + 1, string, 1);
4371 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4372 string[0] = '0' + piece;
4373 XTextExtents(countFontStruct, string, 1, &direction,
4374 &font_ascent, &font_descent, &overall);
4375 if (appData.monoMode) {
4376 XDrawImageString(xDisplay, xBoardWindow, countGC,
4377 x + 2, y + font_ascent + 1, string, 1);
4379 XDrawString(xDisplay, xBoardWindow, countGC,
4380 x + 2, y + font_ascent + 1, string, 1);
4384 if (piece == EmptySquare || appData.blindfold) {
4385 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4387 drawfunc = ChooseDrawFunc();
4388 if (do_flash && appData.flashCount > 0) {
4389 for (i=0; i<appData.flashCount; ++i) {
4391 drawfunc(piece, square_color, x, y, xBoardWindow);
4392 XSync(xDisplay, False);
4393 do_flash_delay(flash_delay);
4395 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4396 XSync(xDisplay, False);
4397 do_flash_delay(flash_delay);
4400 drawfunc(piece, square_color, x, y, xBoardWindow);
4404 string[1] = NULLCHAR;
4405 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4406 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4407 string[0] = 'a' + column - BOARD_LEFT;
4408 XTextExtents(coordFontStruct, string, 1, &direction,
4409 &font_ascent, &font_descent, &overall);
4410 if (appData.monoMode) {
4411 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4412 x + squareSize - overall.width - 2,
4413 y + squareSize - font_descent - 1, string, 1);
4415 XDrawString(xDisplay, xBoardWindow, coordGC,
4416 x + squareSize - overall.width - 2,
4417 y + squareSize - font_descent - 1, string, 1);
4420 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4421 string[0] = ONE + row;
4422 XTextExtents(coordFontStruct, string, 1, &direction,
4423 &font_ascent, &font_descent, &overall);
4424 if (appData.monoMode) {
4425 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4426 x + 2, y + font_ascent + 1, string, 1);
4428 XDrawString(xDisplay, xBoardWindow, coordGC,
4429 x + 2, y + font_ascent + 1, string, 1);
4432 if(!partnerUp && marker[row][column]) {
4433 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4434 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4439 /* Why is this needed on some versions of X? */
4440 void EventProc(widget, unused, event)
4445 if (!XtIsRealized(widget))
4448 switch (event->type) {
4450 if (event->xexpose.count > 0) return; /* no clipping is done */
4451 XDrawPosition(widget, True, NULL);
4452 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4453 flipView = !flipView; partnerUp = !partnerUp;
4454 XDrawPosition(widget, True, NULL);
4455 flipView = !flipView; partnerUp = !partnerUp;
4459 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
\r
4466 void DrawPosition(fullRedraw, board)
4467 /*Boolean*/int fullRedraw;
4470 XDrawPosition(boardWidget, fullRedraw, board);
4473 /* Returns 1 if there are "too many" differences between b1 and b2
4474 (i.e. more than 1 move was made) */
4475 static int too_many_diffs(b1, b2)
4481 for (i=0; i<BOARD_HEIGHT; ++i) {
4482 for (j=0; j<BOARD_WIDTH; ++j) {
4483 if (b1[i][j] != b2[i][j]) {
4484 if (++c > 4) /* Castling causes 4 diffs */
4493 /* Matrix describing castling maneuvers */
4494 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4495 static int castling_matrix[4][5] = {
4496 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4497 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4498 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4499 { 7, 7, 4, 5, 6 } /* 0-0, black */
4502 /* Checks whether castling occurred. If it did, *rrow and *rcol
4503 are set to the destination (row,col) of the rook that moved.
4505 Returns 1 if castling occurred, 0 if not.
4507 Note: Only handles a max of 1 castling move, so be sure
4508 to call too_many_diffs() first.
4510 static int check_castle_draw(newb, oldb, rrow, rcol)
4517 /* For each type of castling... */
4518 for (i=0; i<4; ++i) {
4519 r = castling_matrix[i];
4521 /* Check the 4 squares involved in the castling move */
4523 for (j=1; j<=4; ++j) {
4524 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4531 /* All 4 changed, so it must be a castling move */
4540 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4541 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4543 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4546 void DrawSeekBackground( int left, int top, int right, int bottom )
4548 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4551 void DrawSeekText(char *buf, int x, int y)
4553 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4556 void DrawSeekDot(int x, int y, int colorNr)
4558 int square = colorNr & 0x80;
4561 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4563 XFillRectangle(xDisplay, xBoardWindow, color,
4564 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4566 XFillArc(xDisplay, xBoardWindow, color,
4567 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4570 static int damage[2][BOARD_RANKS][BOARD_FILES];
4573 * event handler for redrawing the board
4575 void XDrawPosition(w, repaint, board)
4577 /*Boolean*/int repaint;
4581 static int lastFlipView = 0;
4582 static int lastBoardValid[2] = {0, 0};
4583 static Board lastBoard[2];
4586 int nr = twoBoards*partnerUp;
4588 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4590 if (board == NULL) {
4591 if (!lastBoardValid[nr]) return;
4592 board = lastBoard[nr];
4594 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4595 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4596 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Flip View"),
4601 * It would be simpler to clear the window with XClearWindow()
4602 * but this causes a very distracting flicker.
4605 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4607 /* If too much changes (begin observing new game, etc.), don't
4609 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4611 /* Special check for castling so we don't flash both the king
4612 and the rook (just flash the king). */
4614 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4615 /* Draw rook with NO flashing. King will be drawn flashing later */
4616 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4617 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4621 /* First pass -- Draw (newly) empty squares and repair damage.
4622 This prevents you from having a piece show up twice while it
4623 is flashing on its new square */
4624 for (i = 0; i < BOARD_HEIGHT; i++)
4625 for (j = 0; j < BOARD_WIDTH; j++)
4626 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4627 || damage[nr][i][j]) {
4628 DrawSquare(i, j, board[i][j], 0);
4629 damage[nr][i][j] = False;
4632 /* Second pass -- Draw piece(s) in new position and flash them */
4633 for (i = 0; i < BOARD_HEIGHT; i++)
4634 for (j = 0; j < BOARD_WIDTH; j++)
4635 if (board[i][j] != lastBoard[nr][i][j]) {
4636 DrawSquare(i, j, board[i][j], do_flash);
4640 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4641 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4642 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4644 for (i = 0; i < BOARD_HEIGHT; i++)
4645 for (j = 0; j < BOARD_WIDTH; j++) {
4646 DrawSquare(i, j, board[i][j], 0);
4647 damage[nr][i][j] = False;
4651 CopyBoard(lastBoard[nr], board);
4652 lastBoardValid[nr] = 1;
4653 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4654 lastFlipView = flipView;
4656 /* Draw highlights */
4657 if (pm1X >= 0 && pm1Y >= 0) {
4658 drawHighlight(pm1X, pm1Y, prelineGC);
4660 if (pm2X >= 0 && pm2Y >= 0) {
4661 drawHighlight(pm2X, pm2Y, prelineGC);
4663 if (hi1X >= 0 && hi1Y >= 0) {
4664 drawHighlight(hi1X, hi1Y, highlineGC);
4666 if (hi2X >= 0 && hi2Y >= 0) {
4667 drawHighlight(hi2X, hi2Y, highlineGC);
4670 /* If piece being dragged around board, must redraw that too */
4673 XSync(xDisplay, False);
4678 * event handler for redrawing the board
4680 void DrawPositionProc(w, event, prms, nprms)
4686 XDrawPosition(w, True, NULL);
4691 * event handler for parsing user moves
4693 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4694 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4695 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4696 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4697 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4698 // and at the end FinishMove() to perform the move after optional promotion popups.
4699 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4700 void HandleUserMove(w, event, prms, nprms)
4706 if (w != boardWidget || errorExitStatus != -1) return;
4707 if(nprms) shiftKey = !strcmp(prms[0], "1");
4710 if (event->type == ButtonPress) {
4711 XtPopdown(promotionShell);
4712 XtDestroyWidget(promotionShell);
4713 promotionUp = False;
4721 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4722 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4723 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4726 void AnimateUserMove (Widget w, XEvent * event,
4727 String * params, Cardinal * nParams)
4729 DragPieceMove(event->xmotion.x, event->xmotion.y);
4732 void HandlePV (Widget w, XEvent * event,
4733 String * params, Cardinal * nParams)
4734 { // [HGM] pv: walk PV
4735 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4738 Widget CommentCreate(name, text, mutable, callback, lines)
4740 int /*Boolean*/ mutable;
4741 XtCallbackProc callback;
4745 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4750 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4751 XtGetValues(boardWidget, args, j);
4754 XtSetArg(args[j], XtNresizable, True); j++;
4757 XtCreatePopupShell(name, topLevelShellWidgetClass,
4758 shellWidget, args, j);
4761 XtCreatePopupShell(name, transientShellWidgetClass,
4762 shellWidget, args, j);
4765 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4766 layoutArgs, XtNumber(layoutArgs));
4768 XtCreateManagedWidget("form", formWidgetClass, layout,
4769 formArgs, XtNumber(formArgs));
4773 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4774 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4776 XtSetArg(args[j], XtNstring, text); j++;
4777 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4778 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4779 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4780 XtSetArg(args[j], XtNright, XtChainRight); j++;
4781 XtSetArg(args[j], XtNresizable, True); j++;
4782 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4783 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4784 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4785 XtSetArg(args[j], XtNautoFill, True); j++;
4786 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4788 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4789 XtOverrideTranslations(edit, XtParseTranslationTable(commentTranslations));
4793 XtSetArg(args[j], XtNfromVert, edit); j++;
4794 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4795 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4796 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4797 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4799 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4800 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4803 XtSetArg(args[j], XtNfromVert, edit); j++;
4804 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4805 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4806 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4807 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4808 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4810 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4811 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4814 XtSetArg(args[j], XtNfromVert, edit); j++;
4815 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4816 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4817 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4818 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4819 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4821 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4822 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4825 XtSetArg(args[j], XtNfromVert, edit); j++;
4826 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4827 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4828 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4829 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4831 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4832 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4835 XtSetArg(args[j], XtNfromVert, edit); j++;
4836 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4837 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4838 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4839 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4840 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4842 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4843 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4846 XtRealizeWidget(shell);
4848 if (commentX == -1) {
4851 Dimension pw_height;
4852 Dimension ew_height;
4855 XtSetArg(args[j], XtNheight, &ew_height); j++;
4856 XtGetValues(edit, args, j);
4859 XtSetArg(args[j], XtNheight, &pw_height); j++;
4860 XtGetValues(shell, args, j);
4861 commentH = pw_height + (lines - 1) * ew_height;
4862 commentW = bw_width - 16;
4864 XSync(xDisplay, False);
4866 /* This code seems to tickle an X bug if it is executed too soon
4867 after xboard starts up. The coordinates get transformed as if
4868 the main window was positioned at (0, 0).
4870 XtTranslateCoords(shellWidget,
4871 (bw_width - commentW) / 2, 0 - commentH / 2,
4872 &commentX, &commentY);
4874 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4875 RootWindowOfScreen(XtScreen(shellWidget)),
4876 (bw_width - commentW) / 2, 0 - commentH / 2,
4881 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4884 if(wpComment.width > 0) {
4885 commentX = wpComment.x;
4886 commentY = wpComment.y;
4887 commentW = wpComment.width;
4888 commentH = wpComment.height;
4892 XtSetArg(args[j], XtNheight, commentH); j++;
4893 XtSetArg(args[j], XtNwidth, commentW); j++;
4894 XtSetArg(args[j], XtNx, commentX); j++;
4895 XtSetArg(args[j], XtNy, commentY); j++;
4896 XtSetValues(shell, args, j);
4897 XtSetKeyboardFocus(shell, edit);
4902 /* Used for analysis window and ICS input window */
4903 Widget MiscCreate(name, text, mutable, callback, lines)
4905 int /*Boolean*/ mutable;
4906 XtCallbackProc callback;
4910 Widget shell, layout, form, edit;
4912 Dimension bw_width, pw_height, ew_height, w, h;
4918 XtSetArg(args[j], XtNresizable, True); j++;
4921 XtCreatePopupShell(name, topLevelShellWidgetClass,
4922 shellWidget, args, j);
4925 XtCreatePopupShell(name, transientShellWidgetClass,
4926 shellWidget, args, j);
4929 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4930 layoutArgs, XtNumber(layoutArgs));
4932 XtCreateManagedWidget("form", formWidgetClass, layout,
4933 formArgs, XtNumber(formArgs));
4937 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4938 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4940 XtSetArg(args[j], XtNstring, text); j++;
4941 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4942 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4943 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4944 XtSetArg(args[j], XtNright, XtChainRight); j++;
4945 XtSetArg(args[j], XtNresizable, True); j++;
4946 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4947 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4948 XtSetArg(args[j], XtNautoFill, True); j++;
4949 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4951 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4953 XtRealizeWidget(shell);
4956 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4957 XtGetValues(boardWidget, args, j);
4960 XtSetArg(args[j], XtNheight, &ew_height); j++;
4961 XtGetValues(edit, args, j);
4964 XtSetArg(args[j], XtNheight, &pw_height); j++;
4965 XtGetValues(shell, args, j);
4966 h = pw_height + (lines - 1) * ew_height;
4969 XSync(xDisplay, False);
4971 /* This code seems to tickle an X bug if it is executed too soon
4972 after xboard starts up. The coordinates get transformed as if
4973 the main window was positioned at (0, 0).
4975 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4977 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4978 RootWindowOfScreen(XtScreen(shellWidget)),
4979 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4983 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4986 XtSetArg(args[j], XtNheight, h); j++;
4987 XtSetArg(args[j], XtNwidth, w); j++;
4988 XtSetArg(args[j], XtNx, x); j++;
4989 XtSetArg(args[j], XtNy, y); j++;
4990 XtSetValues(shell, args, j);
4996 static int savedIndex; /* gross that this is global */
4998 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
5001 XawTextPosition index, dummy;
5004 XawTextGetSelectionPos(w, &index, &dummy);
5005 XtSetArg(arg, XtNstring, &val);
5006 XtGetValues(w, &arg, 1);
5007 ReplaceComment(savedIndex, val);
5008 if(savedIndex != currentMove) ToNrEvent(savedIndex);
5009 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
5012 void EditCommentPopUp(index, title, text)
5021 if (text == NULL) text = "";
5023 if (editShell == NULL) {
5025 CommentCreate(title, text, True, EditCommentCallback, 4);
5026 XtRealizeWidget(editShell);
5027 CatchDeleteWindow(editShell, "EditCommentPopDown");
5029 edit = XtNameToWidget(editShell, "*form.text");
5031 XtSetArg(args[j], XtNstring, text); j++;
5032 XtSetValues(edit, args, j);
5034 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5035 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5036 XtSetValues(editShell, args, j);
5039 XtPopup(editShell, XtGrabNone);
5043 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5044 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"),
5046 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"),
5050 void EditCommentCallback(w, client_data, call_data)
5052 XtPointer client_data, call_data;
5060 XtSetArg(args[j], XtNlabel, &name); j++;
5061 XtGetValues(w, args, j);
5063 if (strcmp(name, _("ok")) == 0) {
5064 edit = XtNameToWidget(editShell, "*form.text");
5066 XtSetArg(args[j], XtNstring, &val); j++;
5067 XtGetValues(edit, args, j);
5068 ReplaceComment(savedIndex, val);
5069 EditCommentPopDown();
5070 } else if (strcmp(name, _("cancel")) == 0) {
5071 EditCommentPopDown();
5072 } else if (strcmp(name, _("clear")) == 0) {
5073 edit = XtNameToWidget(editShell, "*form.text");
5074 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5075 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5079 void EditCommentPopDown()
5084 if (!editUp) return;
5086 XtSetArg(args[j], XtNx, &commentX); j++;
5087 XtSetArg(args[j], XtNy, &commentY); j++;
5088 XtSetArg(args[j], XtNheight, &commentH); j++;
5089 XtSetArg(args[j], XtNwidth, &commentW); j++;
5090 XtGetValues(editShell, args, j);
5091 XtPopdown(editShell);
5094 XtSetArg(args[j], XtNleftBitmap, None); j++;
5095 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"),
5097 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"),
5101 void ICSInputBoxPopUp()
5106 char *title = _("ICS Input");
5109 if (ICSInputShell == NULL) {
5110 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
5111 tr = XtParseTranslationTable(ICSInputTranslations);
5112 edit = XtNameToWidget(ICSInputShell, "*form.text");
5113 XtOverrideTranslations(edit, tr);
5114 XtRealizeWidget(ICSInputShell);
5115 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
5118 edit = XtNameToWidget(ICSInputShell, "*form.text");
5120 XtSetArg(args[j], XtNstring, ""); j++;
5121 XtSetValues(edit, args, j);
5123 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5124 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5125 XtSetValues(ICSInputShell, args, j);
5128 XtPopup(ICSInputShell, XtGrabNone);
5129 XtSetKeyboardFocus(ICSInputShell, edit);
5131 ICSInputBoxUp = True;
5133 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5134 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.ICS Input Box"),
5138 void ICSInputSendText()
5145 edit = XtNameToWidget(ICSInputShell, "*form.text");
5147 XtSetArg(args[j], XtNstring, &val); j++;
5148 XtGetValues(edit, args, j);
5150 SendMultiLineToICS(val);
5151 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5152 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5155 void ICSInputBoxPopDown()
5160 if (!ICSInputBoxUp) return;
5162 XtPopdown(ICSInputShell);
5163 ICSInputBoxUp = False;
5165 XtSetArg(args[j], XtNleftBitmap, None); j++;
5166 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.ICS Input Box"),
5170 void CommentPopUp(title, text)
5177 savedIndex = currentMove; // [HGM] vari
5178 if (commentShell == NULL) {
5180 CommentCreate(title, text, False, CommentCallback, 4);
5181 XtRealizeWidget(commentShell);
5182 CatchDeleteWindow(commentShell, "CommentPopDown");
5184 edit = XtNameToWidget(commentShell, "*form.text");
5186 XtSetArg(args[j], XtNstring, text); j++;
5187 XtSetValues(edit, args, j);
5189 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5190 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5191 XtSetValues(commentShell, args, j);
5194 XtPopup(commentShell, XtGrabNone);
5195 XSync(xDisplay, False);
5200 void CommentCallback(w, client_data, call_data)
5202 XtPointer client_data, call_data;
5209 XtSetArg(args[j], XtNlabel, &name); j++;
5210 XtGetValues(w, args, j);
5212 if (strcmp(name, _("close")) == 0) {
5214 } else if (strcmp(name, _("edit")) == 0) {
5221 void CommentPopDown()
5226 if (!commentUp) return;
5228 XtSetArg(args[j], XtNx, &commentX); j++;
5229 XtSetArg(args[j], XtNy, &commentY); j++;
5230 XtSetArg(args[j], XtNwidth, &commentW); j++;
5231 XtSetArg(args[j], XtNheight, &commentH); j++;
5232 XtGetValues(commentShell, args, j);
5233 XtPopdown(commentShell);
5234 XSync(xDisplay, False);
5238 void FileNamePopUp(label, def, proc, openMode)
5244 fileProc = proc; /* I can't see a way not */
5245 fileOpenMode = openMode; /* to use globals here */
5246 { // [HGM] use file-selector dialog stolen from Ghostview
5248 int index; // this is not supported yet
5250 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5251 def, openMode, NULL, &name))
5252 (void) (*fileProc)(f, index=0, name);
5256 void FileNamePopDown()
5258 if (!filenameUp) return;
5259 XtPopdown(fileNameShell);
5260 XtDestroyWidget(fileNameShell);
5265 void FileNameCallback(w, client_data, call_data)
5267 XtPointer client_data, call_data;
5272 XtSetArg(args[0], XtNlabel, &name);
5273 XtGetValues(w, args, 1);
5275 if (strcmp(name, _("cancel")) == 0) {
5280 FileNameAction(w, NULL, NULL, NULL);
5283 void FileNameAction(w, event, prms, nprms)
5295 name = XawDialogGetValueString(w = XtParent(w));
5297 if ((name != NULL) && (*name != NULLCHAR)) {
5298 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
5299 XtPopdown(w = XtParent(XtParent(w)));
5303 p = strrchr(buf, ' ');
5310 fullname = ExpandPathName(buf);
5312 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5315 f = fopen(fullname, fileOpenMode);
5317 DisplayError(_("Failed to open file"), errno);
5319 (void) (*fileProc)(f, index, buf);
5326 XtPopdown(w = XtParent(XtParent(w)));
5332 void PromotionPopUp()
5335 Widget dialog, layout;
5337 Dimension bw_width, pw_width;
5341 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5342 XtGetValues(boardWidget, args, j);
5345 XtSetArg(args[j], XtNresizable, True); j++;
5346 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5348 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5349 shellWidget, args, j);
5351 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5352 layoutArgs, XtNumber(layoutArgs));
5355 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5356 XtSetArg(args[j], XtNborderWidth, 0); j++;
5357 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5360 if(gameInfo.variant != VariantShogi) {
5361 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5362 (XtPointer) dialog);
5363 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5364 (XtPointer) dialog);
5365 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5366 (XtPointer) dialog);
5367 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5368 (XtPointer) dialog);
5369 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5370 gameInfo.variant == VariantGiveaway) {
5371 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5372 (XtPointer) dialog);
5374 if(gameInfo.variant == VariantCapablanca ||
5375 gameInfo.variant == VariantGothic ||
5376 gameInfo.variant == VariantCapaRandom) {
5377 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5378 (XtPointer) dialog);
5379 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5380 (XtPointer) dialog);
5382 } else // [HGM] shogi
5384 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5385 (XtPointer) dialog);
5386 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5387 (XtPointer) dialog);
5389 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5390 (XtPointer) dialog);
5392 XtRealizeWidget(promotionShell);
5393 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5396 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5397 XtGetValues(promotionShell, args, j);
5399 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5400 lineGap + squareSize/3 +
5401 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5402 0 : 6*(squareSize + lineGap)), &x, &y);
5405 XtSetArg(args[j], XtNx, x); j++;
5406 XtSetArg(args[j], XtNy, y); j++;
5407 XtSetValues(promotionShell, args, j);
5409 XtPopup(promotionShell, XtGrabNone);
5414 void PromotionPopDown()
5416 if (!promotionUp) return;
5417 XtPopdown(promotionShell);
5418 XtDestroyWidget(promotionShell);
5419 promotionUp = False;
5422 void PromotionCallback(w, client_data, call_data)
5424 XtPointer client_data, call_data;
5430 XtSetArg(args[0], XtNlabel, &name);
5431 XtGetValues(w, args, 1);
5435 if (fromX == -1) return;
5437 if (strcmp(name, _("cancel")) == 0) {
5441 } else if (strcmp(name, _("Knight")) == 0) {
5443 } else if (strcmp(name, _("Promote")) == 0) {
5445 } else if (strcmp(name, _("Defer")) == 0) {
5448 promoChar = ToLower(name[0]);
5451 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5453 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5454 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5459 void ErrorCallback(w, client_data, call_data)
5461 XtPointer client_data, call_data;
5464 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5466 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5472 if (!errorUp) return;
5474 XtPopdown(errorShell);
5475 XtDestroyWidget(errorShell);
5476 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5479 void ErrorPopUp(title, label, modal)
5480 char *title, *label;
5484 Widget dialog, layout;
5488 Dimension bw_width, pw_width;
5489 Dimension pw_height;
5493 XtSetArg(args[i], XtNresizable, True); i++;
5494 XtSetArg(args[i], XtNtitle, title); i++;
5496 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5497 shellWidget, args, i);
5499 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5500 layoutArgs, XtNumber(layoutArgs));
5503 XtSetArg(args[i], XtNlabel, label); i++;
5504 XtSetArg(args[i], XtNborderWidth, 0); i++;
5505 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5508 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5510 XtRealizeWidget(errorShell);
5511 CatchDeleteWindow(errorShell, "ErrorPopDown");
5514 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5515 XtGetValues(boardWidget, args, i);
5517 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5518 XtSetArg(args[i], XtNheight, &pw_height); i++;
5519 XtGetValues(errorShell, args, i);
5522 /* This code seems to tickle an X bug if it is executed too soon
5523 after xboard starts up. The coordinates get transformed as if
5524 the main window was positioned at (0, 0).
5526 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5527 0 - pw_height + squareSize / 3, &x, &y);
5529 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5530 RootWindowOfScreen(XtScreen(boardWidget)),
5531 (bw_width - pw_width) / 2,
5532 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5536 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5539 XtSetArg(args[i], XtNx, x); i++;
5540 XtSetArg(args[i], XtNy, y); i++;
5541 XtSetValues(errorShell, args, i);
5544 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5547 /* Disable all user input other than deleting the window */
5548 static int frozen = 0;
5552 /* Grab by a widget that doesn't accept input */
5553 XtAddGrab(messageWidget, TRUE, FALSE);
5557 /* Undo a FreezeUI */
5560 if (!frozen) return;
5561 XtRemoveGrab(messageWidget);
5565 char *ModeToWidgetName(mode)
5569 case BeginningOfGame:
5570 if (appData.icsActive)
5571 return "menuMode.ICS Client";
5572 else if (appData.noChessProgram ||
5573 *appData.cmailGameName != NULLCHAR)
5574 return "menuMode.Edit Game";
5576 return "menuMode.Machine Black";
5577 case MachinePlaysBlack:
5578 return "menuMode.Machine Black";
5579 case MachinePlaysWhite:
5580 return "menuMode.Machine White";
5582 return "menuMode.Analysis Mode";
5584 return "menuMode.Analyze File";
5585 case TwoMachinesPlay:
5586 return "menuMode.Two Machines";
5588 return "menuMode.Edit Game";
5589 case PlayFromGameFile:
5590 return "menuFile.Load Game";
5592 return "menuMode.Edit Position";
5594 return "menuMode.Training";
5595 case IcsPlayingWhite:
5596 case IcsPlayingBlack:
5600 return "menuMode.ICS Client";
5607 void ModeHighlight()
5610 static int oldPausing = FALSE;
5611 static GameMode oldmode = (GameMode) -1;
5614 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5616 if (pausing != oldPausing) {
5617 oldPausing = pausing;
5619 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5621 XtSetArg(args[0], XtNleftBitmap, None);
5623 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5626 if (appData.showButtonBar) {
5627 /* Always toggle, don't set. Previous code messes up when
5628 invoked while the button is pressed, as releasing it
5629 toggles the state again. */
5632 XtSetArg(args[0], XtNbackground, &oldbg);
5633 XtSetArg(args[1], XtNforeground, &oldfg);
5634 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5636 XtSetArg(args[0], XtNbackground, oldfg);
5637 XtSetArg(args[1], XtNforeground, oldbg);
5639 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5643 wname = ModeToWidgetName(oldmode);
5644 if (wname != NULL) {
5645 XtSetArg(args[0], XtNleftBitmap, None);
5646 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5648 wname = ModeToWidgetName(gameMode);
5649 if (wname != NULL) {
5650 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5651 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5655 /* Maybe all the enables should be handled here, not just this one */
5656 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5657 gameMode == Training || gameMode == PlayFromGameFile);
5662 * Button/menu procedures
5664 void ResetProc(w, event, prms, nprms)
5673 int LoadGamePopUp(f, gameNumber, title)
5678 cmailMsgLoaded = FALSE;
5679 if (gameNumber == 0) {
5680 int error = GameListBuild(f);
5682 DisplayError(_("Cannot build game list"), error);
5683 } else if (!ListEmpty(&gameList) &&
5684 ((ListGame *) gameList.tailPred)->number > 1) {
5685 GameListPopUp(f, title);
5691 return LoadGame(f, gameNumber, title, FALSE);
5694 void LoadGameProc(w, event, prms, nprms)
5700 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5703 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5706 void LoadNextGameProc(w, event, prms, nprms)
5715 void LoadPrevGameProc(w, event, prms, nprms)
5724 void ReloadGameProc(w, event, prms, nprms)
5733 void LoadNextPositionProc(w, event, prms, nprms)
5742 void LoadPrevPositionProc(w, event, prms, nprms)
5751 void ReloadPositionProc(w, event, prms, nprms)
5760 void LoadPositionProc(w, event, prms, nprms)
5766 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5769 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5772 void SaveGameProc(w, event, prms, nprms)
5778 FileNamePopUp(_("Save game file name?"),
5779 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5783 void SavePositionProc(w, event, prms, nprms)
5789 FileNamePopUp(_("Save position file name?"),
5790 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5794 void ReloadCmailMsgProc(w, event, prms, nprms)
5800 ReloadCmailMsgEvent(FALSE);
5803 void MailMoveProc(w, event, prms, nprms)
5812 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5813 char *selected_fen_position=NULL;
5816 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5817 Atom *type_return, XtPointer *value_return,
5818 unsigned long *length_return, int *format_return)
5820 char *selection_tmp;
5822 if (!selected_fen_position) return False; /* should never happen */
5823 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5824 /* note: since no XtSelectionDoneProc was registered, Xt will
5825 * automatically call XtFree on the value returned. So have to
5826 * make a copy of it allocated with XtMalloc */
5827 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5828 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
5830 *value_return=selection_tmp;
5831 *length_return=strlen(selection_tmp);
5832 *type_return=*target;
5833 *format_return = 8; /* bits per byte */
5835 } else if (*target == XA_TARGETS(xDisplay)) {
5836 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5837 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5838 targets_tmp[1] = XA_STRING;
5839 *value_return = targets_tmp;
5840 *type_return = XA_ATOM;
5842 *format_return = 8 * sizeof(Atom);
5843 if (*format_return > 32) {
5844 *length_return *= *format_return / 32;
5845 *format_return = 32;
5853 /* note: when called from menu all parameters are NULL, so no clue what the
5854 * Widget which was clicked on was, or what the click event was
5856 void CopyPositionProc(w, event, prms, nprms)
5863 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5864 * have a notion of a position that is selected but not copied.
5865 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5867 if(gameMode == EditPosition) EditPositionDone(TRUE);
5868 if (selected_fen_position) free(selected_fen_position);
5869 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5870 if (!selected_fen_position) return;
5871 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5873 SendPositionSelection,
5874 NULL/* lose_ownership_proc */ ,
5875 NULL/* transfer_done_proc */);
5876 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5878 SendPositionSelection,
5879 NULL/* lose_ownership_proc */ ,
5880 NULL/* transfer_done_proc */);
5883 /* function called when the data to Paste is ready */
5885 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5886 Atom *type, XtPointer value, unsigned long *len, int *format)
5889 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5890 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5891 EditPositionPasteFEN(fenstr);
5895 /* called when Paste Position button is pressed,
5896 * all parameters will be NULL */
5897 void PastePositionProc(w, event, prms, nprms)
5903 XtGetSelectionValue(menuBarWidget,
5904 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5905 /* (XtSelectionCallbackProc) */ PastePositionCB,
5906 NULL, /* client_data passed to PastePositionCB */
5908 /* better to use the time field from the event that triggered the
5909 * call to this function, but that isn't trivial to get
5917 SendGameSelection(Widget w, Atom *selection, Atom *target,
5918 Atom *type_return, XtPointer *value_return,
5919 unsigned long *length_return, int *format_return)
5921 char *selection_tmp;
5923 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5924 FILE* f = fopen(gameCopyFilename, "r");
5927 if (f == NULL) return False;
5931 selection_tmp = XtMalloc(len + 1);
5932 count = fread(selection_tmp, 1, len, f);
5934 XtFree(selection_tmp);
5937 selection_tmp[len] = NULLCHAR;
5938 *value_return = selection_tmp;
5939 *length_return = len;
5940 *type_return = *target;
5941 *format_return = 8; /* bits per byte */
5943 } else if (*target == XA_TARGETS(xDisplay)) {
5944 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5945 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5946 targets_tmp[1] = XA_STRING;
5947 *value_return = targets_tmp;
5948 *type_return = XA_ATOM;
5950 *format_return = 8 * sizeof(Atom);
5951 if (*format_return > 32) {
5952 *length_return *= *format_return / 32;
5953 *format_return = 32;
5961 /* note: when called from menu all parameters are NULL, so no clue what the
5962 * Widget which was clicked on was, or what the click event was
5964 void CopyGameProc(w, event, prms, nprms)
5972 ret = SaveGameToFile(gameCopyFilename, FALSE);
5976 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5977 * have a notion of a game that is selected but not copied.
5978 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5980 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5983 NULL/* lose_ownership_proc */ ,
5984 NULL/* transfer_done_proc */);
5985 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5988 NULL/* lose_ownership_proc */ ,
5989 NULL/* transfer_done_proc */);
5992 /* function called when the data to Paste is ready */
5994 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5995 Atom *type, XtPointer value, unsigned long *len, int *format)
5998 if (value == NULL || *len == 0) {
5999 return; /* nothing had been selected to copy */
6001 f = fopen(gamePasteFilename, "w");
6003 DisplayError(_("Can't open temp file"), errno);
6006 fwrite(value, 1, *len, f);
6009 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
6012 /* called when Paste Game button is pressed,
6013 * all parameters will be NULL */
6014 void PasteGameProc(w, event, prms, nprms)
6020 XtGetSelectionValue(menuBarWidget,
6021 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
6022 /* (XtSelectionCallbackProc) */ PasteGameCB,
6023 NULL, /* client_data passed to PasteGameCB */
6025 /* better to use the time field from the event that triggered the
6026 * call to this function, but that isn't trivial to get
6036 SaveGameProc(NULL, NULL, NULL, NULL);
6040 void QuitProc(w, event, prms, nprms)
6049 void PauseProc(w, event, prms, nprms)
6059 void MachineBlackProc(w, event, prms, nprms)
6065 MachineBlackEvent();
6068 void MachineWhiteProc(w, event, prms, nprms)
6074 MachineWhiteEvent();
6077 void AnalyzeModeProc(w, event, prms, nprms)
6085 if (!first.analysisSupport) {
6086 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6087 DisplayError(buf, 0);
6090 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
6091 if (appData.icsActive) {
6092 if (gameMode != IcsObserving) {
6093 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
6094 DisplayError(buf, 0);
6096 if (appData.icsEngineAnalyze) {
6097 if (appData.debugMode)
6098 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
6104 /* if enable, use want disable icsEngineAnalyze */
6105 if (appData.icsEngineAnalyze) {
6110 appData.icsEngineAnalyze = TRUE;
6111 if (appData.debugMode)
6112 fprintf(debugFP, _("ICS engine analyze starting... \n"));
6114 if (!appData.showThinking)
6115 ShowThinkingProc(w,event,prms,nprms);
6120 void AnalyzeFileProc(w, event, prms, nprms)
6126 if (!first.analysisSupport) {
6128 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6129 DisplayError(buf, 0);
6134 if (!appData.showThinking)
6135 ShowThinkingProc(w,event,prms,nprms);
6138 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
6139 AnalysisPeriodicEvent(1);
6142 void TwoMachinesProc(w, event, prms, nprms)
6151 void IcsClientProc(w, event, prms, nprms)
6160 void EditGameProc(w, event, prms, nprms)
6169 void EditPositionProc(w, event, prms, nprms)
6175 EditPositionEvent();
6178 void TrainingProc(w, event, prms, nprms)
6187 void EditCommentProc(w, event, prms, nprms)
6194 EditCommentPopDown();
6200 void IcsInputBoxProc(w, event, prms, nprms)
6206 if (ICSInputBoxUp) {
6207 ICSInputBoxPopDown();
6213 void AcceptProc(w, event, prms, nprms)
6222 void DeclineProc(w, event, prms, nprms)
6231 void RematchProc(w, event, prms, nprms)
6240 void CallFlagProc(w, event, prms, nprms)
6249 void DrawProc(w, event, prms, nprms)
6258 void AbortProc(w, event, prms, nprms)
6267 void AdjournProc(w, event, prms, nprms)
6276 void ResignProc(w, event, prms, nprms)
6285 void AdjuWhiteProc(w, event, prms, nprms)
6291 UserAdjudicationEvent(+1);
6294 void AdjuBlackProc(w, event, prms, nprms)
6300 UserAdjudicationEvent(-1);
6303 void AdjuDrawProc(w, event, prms, nprms)
6309 UserAdjudicationEvent(0);
6312 void EnterKeyProc(w, event, prms, nprms)
6318 if (ICSInputBoxUp == True)
6322 void UpKeyProc(w, event, prms, nprms)
6327 { // [HGM] input: let up-arrow recall previous line from history
6334 if (!ICSInputBoxUp) return;
6335 edit = XtNameToWidget(ICSInputShell, "*form.text");
6337 XtSetArg(args[j], XtNstring, &val); j++;
6338 XtGetValues(edit, args, j);
6339 val = PrevInHistory(val);
6340 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6341 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6343 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6344 XawTextReplace(edit, 0, 0, &t);
6345 XawTextSetInsertionPoint(edit, 9999);
6349 void DownKeyProc(w, event, prms, nprms)
6354 { // [HGM] input: let down-arrow recall next line from history
6359 if (!ICSInputBoxUp) return;
6360 edit = XtNameToWidget(ICSInputShell, "*form.text");
6361 val = NextInHistory();
6362 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6363 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6365 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6366 XawTextReplace(edit, 0, 0, &t);
6367 XawTextSetInsertionPoint(edit, 9999);
6371 void StopObservingProc(w, event, prms, nprms)
6377 StopObservingEvent();
6380 void StopExaminingProc(w, event, prms, nprms)
6386 StopExaminingEvent();
6389 void UploadProc(w, event, prms, nprms)
6399 void ForwardProc(w, event, prms, nprms)
6409 void BackwardProc(w, event, prms, nprms)
6418 void ToStartProc(w, event, prms, nprms)
6427 void ToEndProc(w, event, prms, nprms)
6436 void RevertProc(w, event, prms, nprms)
6445 void AnnotateProc(w, event, prms, nprms)
6454 void TruncateGameProc(w, event, prms, nprms)
6460 TruncateGameEvent();
6462 void RetractMoveProc(w, event, prms, nprms)
6471 void MoveNowProc(w, event, prms, nprms)
6481 void AlwaysQueenProc(w, event, prms, nprms)
6489 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6491 if (appData.alwaysPromoteToQueen) {
6492 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6494 XtSetArg(args[0], XtNleftBitmap, None);
6496 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6500 void AnimateDraggingProc(w, event, prms, nprms)
6508 appData.animateDragging = !appData.animateDragging;
6510 if (appData.animateDragging) {
6511 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6514 XtSetArg(args[0], XtNleftBitmap, None);
6516 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6520 void AnimateMovingProc(w, event, prms, nprms)
6528 appData.animate = !appData.animate;
6530 if (appData.animate) {
6531 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6534 XtSetArg(args[0], XtNleftBitmap, None);
6536 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6540 void AutocommProc(w, event, prms, nprms)
6548 appData.autoComment = !appData.autoComment;
6550 if (appData.autoComment) {
6551 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6553 XtSetArg(args[0], XtNleftBitmap, None);
6555 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6560 void AutoflagProc(w, event, prms, nprms)
6568 appData.autoCallFlag = !appData.autoCallFlag;
6570 if (appData.autoCallFlag) {
6571 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6573 XtSetArg(args[0], XtNleftBitmap, None);
6575 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6579 void AutoflipProc(w, event, prms, nprms)
6587 appData.autoFlipView = !appData.autoFlipView;
6589 if (appData.autoFlipView) {
6590 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6592 XtSetArg(args[0], XtNleftBitmap, None);
6594 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6598 void AutobsProc(w, event, prms, nprms)
6606 appData.autoObserve = !appData.autoObserve;
6608 if (appData.autoObserve) {
6609 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6611 XtSetArg(args[0], XtNleftBitmap, None);
6613 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6617 void AutoraiseProc(w, event, prms, nprms)
6625 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6627 if (appData.autoRaiseBoard) {
6628 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6630 XtSetArg(args[0], XtNleftBitmap, None);
6632 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6636 void AutosaveProc(w, event, prms, nprms)
6644 appData.autoSaveGames = !appData.autoSaveGames;
6646 if (appData.autoSaveGames) {
6647 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6649 XtSetArg(args[0], XtNleftBitmap, None);
6651 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6655 void BlindfoldProc(w, event, prms, nprms)
6663 appData.blindfold = !appData.blindfold;
6665 if (appData.blindfold) {
6666 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6668 XtSetArg(args[0], XtNleftBitmap, None);
6670 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6673 DrawPosition(True, NULL);
6676 void TestLegalityProc(w, event, prms, nprms)
6684 appData.testLegality = !appData.testLegality;
6686 if (appData.testLegality) {
6687 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6689 XtSetArg(args[0], XtNleftBitmap, None);
6691 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6696 void FlashMovesProc(w, event, prms, nprms)
6704 if (appData.flashCount == 0) {
6705 appData.flashCount = 3;
6707 appData.flashCount = -appData.flashCount;
6710 if (appData.flashCount > 0) {
6711 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6713 XtSetArg(args[0], XtNleftBitmap, None);
6715 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6719 void FlipViewProc(w, event, prms, nprms)
6725 flipView = !flipView;
6726 DrawPosition(True, NULL);
6729 void GetMoveListProc(w, event, prms, nprms)
6737 appData.getMoveList = !appData.getMoveList;
6739 if (appData.getMoveList) {
6740 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6743 XtSetArg(args[0], XtNleftBitmap, None);
6745 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6750 void HighlightDraggingProc(w, event, prms, nprms)
6758 appData.highlightDragging = !appData.highlightDragging;
6760 if (appData.highlightDragging) {
6761 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6763 XtSetArg(args[0], XtNleftBitmap, None);
6765 XtSetValues(XtNameToWidget(menuBarWidget,
6766 "menuOptions.Highlight Dragging"), args, 1);
6770 void HighlightLastMoveProc(w, event, prms, nprms)
6778 appData.highlightLastMove = !appData.highlightLastMove;
6780 if (appData.highlightLastMove) {
6781 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6783 XtSetArg(args[0], XtNleftBitmap, None);
6785 XtSetValues(XtNameToWidget(menuBarWidget,
6786 "menuOptions.Highlight Last Move"), args, 1);
6789 void IcsAlarmProc(w, event, prms, nprms)
6797 appData.icsAlarm = !appData.icsAlarm;
6799 if (appData.icsAlarm) {
6800 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6802 XtSetArg(args[0], XtNleftBitmap, None);
6804 XtSetValues(XtNameToWidget(menuBarWidget,
6805 "menuOptions.ICS Alarm"), args, 1);
6808 void MoveSoundProc(w, event, prms, nprms)
6816 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6818 if (appData.ringBellAfterMoves) {
6819 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6821 XtSetArg(args[0], XtNleftBitmap, None);
6823 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6828 void OldSaveStyleProc(w, event, prms, nprms)
6836 appData.oldSaveStyle = !appData.oldSaveStyle;
6838 if (appData.oldSaveStyle) {
6839 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6841 XtSetArg(args[0], XtNleftBitmap, None);
6843 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6847 void PeriodicUpdatesProc(w, event, prms, nprms)
6855 PeriodicUpdatesEvent(!appData.periodicUpdates);
6857 if (appData.periodicUpdates) {
6858 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6860 XtSetArg(args[0], XtNleftBitmap, None);
6862 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6866 void PonderNextMoveProc(w, event, prms, nprms)
6874 PonderNextMoveEvent(!appData.ponderNextMove);
6876 if (appData.ponderNextMove) {
6877 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6879 XtSetArg(args[0], XtNleftBitmap, None);
6881 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6885 void PopupExitMessageProc(w, event, prms, nprms)
6893 appData.popupExitMessage = !appData.popupExitMessage;
6895 if (appData.popupExitMessage) {
6896 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6898 XtSetArg(args[0], XtNleftBitmap, None);
6900 XtSetValues(XtNameToWidget(menuBarWidget,
6901 "menuOptions.Popup Exit Message"), args, 1);
6904 void PopupMoveErrorsProc(w, event, prms, nprms)
6912 appData.popupMoveErrors = !appData.popupMoveErrors;
6914 if (appData.popupMoveErrors) {
6915 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6917 XtSetArg(args[0], XtNleftBitmap, None);
6919 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6923 void PremoveProc(w, event, prms, nprms)
6931 appData.premove = !appData.premove;
6933 if (appData.premove) {
6934 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6936 XtSetArg(args[0], XtNleftBitmap, None);
6938 XtSetValues(XtNameToWidget(menuBarWidget,
6939 "menuOptions.Premove"), args, 1);
6942 void QuietPlayProc(w, event, prms, nprms)
6950 appData.quietPlay = !appData.quietPlay;
6952 if (appData.quietPlay) {
6953 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6955 XtSetArg(args[0], XtNleftBitmap, None);
6957 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6961 void ShowCoordsProc(w, event, prms, nprms)
6969 appData.showCoords = !appData.showCoords;
6971 if (appData.showCoords) {
6972 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6974 XtSetArg(args[0], XtNleftBitmap, None);
6976 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6979 DrawPosition(True, NULL);
6982 void ShowThinkingProc(w, event, prms, nprms)
6988 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6989 ShowThinkingEvent();
6992 void HideThinkingProc(w, event, prms, nprms)
7000 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
7001 ShowThinkingEvent();
7003 if (appData.hideThinkingFromHuman) {
7004 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
7006 XtSetArg(args[0], XtNleftBitmap, None);
7008 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
7012 void SaveOnExitProc(w, event, prms, nprms)
7020 saveSettingsOnExit = !saveSettingsOnExit;
7022 if (saveSettingsOnExit) {
7023 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
7025 XtSetArg(args[0], XtNleftBitmap, None);
7027 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
7031 void SaveSettingsProc(w, event, prms, nprms)
7037 SaveSettings(settingsFileName);
7040 void InfoProc(w, event, prms, nprms)
7047 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
7052 void ManProc(w, event, prms, nprms)
7060 if (nprms && *nprms > 0)
7064 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
7068 void HintProc(w, event, prms, nprms)
7077 void BookProc(w, event, prms, nprms)
7086 void AboutProc(w, event, prms, nprms)
7094 char *zippy = " (with Zippy code)";
7098 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
7099 programVersion, zippy,
7100 "Copyright 1991 Digital Equipment Corporation",
7101 "Enhancements Copyright 1992-2009 Free Software Foundation",
7102 "Enhancements Copyright 2005 Alessandro Scotti",
7103 PACKAGE, " is free software and carries NO WARRANTY;",
7104 "see the file COPYING for more information.");
7105 ErrorPopUp(_("About XBoard"), buf, FALSE);
7108 void DebugProc(w, event, prms, nprms)
7114 appData.debugMode = !appData.debugMode;
7117 void AboutGameProc(w, event, prms, nprms)
7126 void NothingProc(w, event, prms, nprms)
7135 void Iconify(w, event, prms, nprms)
7144 XtSetArg(args[0], XtNiconic, True);
7145 XtSetValues(shellWidget, args, 1);
7148 void DisplayMessage(message, extMessage)
7149 char *message, *extMessage;
7151 /* display a message in the message widget */
7160 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
7165 message = extMessage;
7169 /* need to test if messageWidget already exists, since this function
7170 can also be called during the startup, if for example a Xresource
7171 is not set up correctly */
7174 XtSetArg(arg, XtNlabel, message);
7175 XtSetValues(messageWidget, &arg, 1);
7181 void DisplayTitle(text)
7186 char title[MSG_SIZ];
7189 if (text == NULL) text = "";
7191 if (appData.titleInWindow) {
7193 XtSetArg(args[i], XtNlabel, text); i++;
7194 XtSetValues(titleWidget, args, i);
7197 if (*text != NULLCHAR) {
7198 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
7199 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
7200 } else if (appData.icsActive) {
7201 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7202 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7203 } else if (appData.cmailGameName[0] != NULLCHAR) {
7204 snprintf(icon, sizeof(icon), "%s", "CMail");
7205 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7207 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7208 } else if (gameInfo.variant == VariantGothic) {
7209 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7210 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
7213 } else if (gameInfo.variant == VariantFalcon) {
7214 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7215 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
7217 } else if (appData.noChessProgram) {
7218 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7219 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
7221 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
7222 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7225 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7226 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7227 XtSetValues(shellWidget, args, i);
7232 DisplayError(message, error)
7239 if (appData.debugMode || appData.matchMode) {
7240 fprintf(stderr, "%s: %s\n", programName, message);
7243 if (appData.debugMode || appData.matchMode) {
7244 fprintf(stderr, "%s: %s: %s\n",
7245 programName, message, strerror(error));
7247 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7250 ErrorPopUp(_("Error"), message, FALSE);
7254 void DisplayMoveError(message)
7259 DrawPosition(FALSE, NULL);
7260 if (appData.debugMode || appData.matchMode) {
7261 fprintf(stderr, "%s: %s\n", programName, message);
7263 if (appData.popupMoveErrors) {
7264 ErrorPopUp(_("Error"), message, FALSE);
7266 DisplayMessage(message, "");
7271 void DisplayFatalError(message, error, status)
7277 errorExitStatus = status;
7279 fprintf(stderr, "%s: %s\n", programName, message);
7281 fprintf(stderr, "%s: %s: %s\n",
7282 programName, message, strerror(error));
7283 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7286 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7287 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7293 void DisplayInformation(message)
7297 ErrorPopUp(_("Information"), message, TRUE);
7300 void DisplayNote(message)
7304 ErrorPopUp(_("Note"), message, FALSE);
7308 NullXErrorCheck(dpy, error_event)
7310 XErrorEvent *error_event;
7315 void DisplayIcsInteractionTitle(message)
7318 if (oldICSInteractionTitle == NULL) {
7319 /* Magic to find the old window title, adapted from vim */
7320 char *wina = getenv("WINDOWID");
7322 Window win = (Window) atoi(wina);
7323 Window root, parent, *children;
7324 unsigned int nchildren;
7325 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7327 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7328 if (!XQueryTree(xDisplay, win, &root, &parent,
7329 &children, &nchildren)) break;
7330 if (children) XFree((void *)children);
7331 if (parent == root || parent == 0) break;
7334 XSetErrorHandler(oldHandler);
7336 if (oldICSInteractionTitle == NULL) {
7337 oldICSInteractionTitle = "xterm";
7340 printf("\033]0;%s\007", message);
7344 char pendingReplyPrefix[MSG_SIZ];
7345 ProcRef pendingReplyPR;
7347 void AskQuestionProc(w, event, prms, nprms)
7354 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7358 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7361 void AskQuestionPopDown()
7363 if (!askQuestionUp) return;
7364 XtPopdown(askQuestionShell);
7365 XtDestroyWidget(askQuestionShell);
7366 askQuestionUp = False;
7369 void AskQuestionReplyAction(w, event, prms, nprms)
7379 reply = XawDialogGetValueString(w = XtParent(w));
7380 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
7381 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
7382 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
7383 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
7384 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7385 AskQuestionPopDown();
7387 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7390 void AskQuestionCallback(w, client_data, call_data)
7392 XtPointer client_data, call_data;
7397 XtSetArg(args[0], XtNlabel, &name);
7398 XtGetValues(w, args, 1);
7400 if (strcmp(name, _("cancel")) == 0) {
7401 AskQuestionPopDown();
7403 AskQuestionReplyAction(w, NULL, NULL, NULL);
7407 void AskQuestion(title, question, replyPrefix, pr)
7408 char *title, *question, *replyPrefix;
7412 Widget popup, layout, dialog, edit;
7418 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
7419 pendingReplyPR = pr;
7422 XtSetArg(args[i], XtNresizable, True); i++;
7423 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7424 askQuestionShell = popup =
7425 XtCreatePopupShell(title, transientShellWidgetClass,
7426 shellWidget, args, i);
7429 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7430 layoutArgs, XtNumber(layoutArgs));
7433 XtSetArg(args[i], XtNlabel, question); i++;
7434 XtSetArg(args[i], XtNvalue, ""); i++;
7435 XtSetArg(args[i], XtNborderWidth, 0); i++;
7436 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7439 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7440 (XtPointer) dialog);
7441 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7442 (XtPointer) dialog);
7444 XtRealizeWidget(popup);
7445 CatchDeleteWindow(popup, "AskQuestionPopDown");
7447 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7448 &x, &y, &win_x, &win_y, &mask);
7450 XtSetArg(args[0], XtNx, x - 10);
7451 XtSetArg(args[1], XtNy, y - 30);
7452 XtSetValues(popup, args, 2);
7454 XtPopup(popup, XtGrabExclusive);
7455 askQuestionUp = True;
7457 edit = XtNameToWidget(dialog, "*value");
7458 XtSetKeyboardFocus(popup, edit);
7466 if (*name == NULLCHAR) {
7468 } else if (strcmp(name, "$") == 0) {
7469 putc(BELLCHAR, stderr);
7472 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7480 PlaySound(appData.soundMove);
7486 PlaySound(appData.soundIcsWin);
7492 PlaySound(appData.soundIcsLoss);
7498 PlaySound(appData.soundIcsDraw);
7502 PlayIcsUnfinishedSound()
7504 PlaySound(appData.soundIcsUnfinished);
7510 PlaySound(appData.soundIcsAlarm);
7516 system("stty echo");
7522 system("stty -echo");
7526 Colorize(cc, continuation)
7531 int count, outCount, error;
7533 if (textColors[(int)cc].bg > 0) {
7534 if (textColors[(int)cc].fg > 0) {
7535 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7536 textColors[(int)cc].fg, textColors[(int)cc].bg);
7538 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7539 textColors[(int)cc].bg);
7542 if (textColors[(int)cc].fg > 0) {
7543 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7544 textColors[(int)cc].fg);
7546 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7549 count = strlen(buf);
7550 outCount = OutputToProcess(NoProc, buf, count, &error);
7551 if (outCount < count) {
7552 DisplayFatalError(_("Error writing to display"), error, 1);
7555 if (continuation) return;
7558 PlaySound(appData.soundShout);
7561 PlaySound(appData.soundSShout);
7564 PlaySound(appData.soundChannel1);
7567 PlaySound(appData.soundChannel);
7570 PlaySound(appData.soundKibitz);
7573 PlaySound(appData.soundTell);
7575 case ColorChallenge:
7576 PlaySound(appData.soundChallenge);
7579 PlaySound(appData.soundRequest);
7582 PlaySound(appData.soundSeek);
7593 return getpwuid(getuid())->pw_name;
7597 ExpandPathName(path)
7600 static char static_buf[4*MSG_SIZ];
7601 char *d, *s, buf[4*MSG_SIZ];
7607 while (*s && isspace(*s))
7616 if (*(s+1) == '/') {
7617 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7621 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7622 { char *p; if(p = strchr(buf, '/')) *p = 0; }
7623 pwd = getpwnam(buf);
7626 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7630 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7631 strcat(d, strchr(s+1, '/'));
7635 safeStrCpy(d, s, 4*MSG_SIZ );
7642 static char host_name[MSG_SIZ];
7644 #if HAVE_GETHOSTNAME
7645 gethostname(host_name, MSG_SIZ);
7647 #else /* not HAVE_GETHOSTNAME */
7648 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7649 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7651 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7653 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7654 #endif /* not HAVE_GETHOSTNAME */
7657 XtIntervalId delayedEventTimerXID = 0;
7658 DelayedEventCallback delayedEventCallback = 0;
7663 delayedEventTimerXID = 0;
7664 delayedEventCallback();
7668 ScheduleDelayedEvent(cb, millisec)
7669 DelayedEventCallback cb; long millisec;
7671 if(delayedEventTimerXID && delayedEventCallback == cb)
7672 // [HGM] alive: replace, rather than add or flush identical event
7673 XtRemoveTimeOut(delayedEventTimerXID);
7674 delayedEventCallback = cb;
7675 delayedEventTimerXID =
7676 XtAppAddTimeOut(appContext, millisec,
7677 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7680 DelayedEventCallback
7683 if (delayedEventTimerXID) {
7684 return delayedEventCallback;
7691 CancelDelayedEvent()
7693 if (delayedEventTimerXID) {
7694 XtRemoveTimeOut(delayedEventTimerXID);
7695 delayedEventTimerXID = 0;
7699 XtIntervalId loadGameTimerXID = 0;
7701 int LoadGameTimerRunning()
7703 return loadGameTimerXID != 0;
7706 int StopLoadGameTimer()
7708 if (loadGameTimerXID != 0) {
7709 XtRemoveTimeOut(loadGameTimerXID);
7710 loadGameTimerXID = 0;
7718 LoadGameTimerCallback(arg, id)
7722 loadGameTimerXID = 0;
7727 StartLoadGameTimer(millisec)
7731 XtAppAddTimeOut(appContext, millisec,
7732 (XtTimerCallbackProc) LoadGameTimerCallback,
7736 XtIntervalId analysisClockXID = 0;
7739 AnalysisClockCallback(arg, id)
7743 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7744 || appData.icsEngineAnalyze) { // [DM]
7745 AnalysisPeriodicEvent(0);
7746 StartAnalysisClock();
7751 StartAnalysisClock()
7754 XtAppAddTimeOut(appContext, 2000,
7755 (XtTimerCallbackProc) AnalysisClockCallback,
7759 XtIntervalId clockTimerXID = 0;
7761 int ClockTimerRunning()
7763 return clockTimerXID != 0;
7766 int StopClockTimer()
7768 if (clockTimerXID != 0) {
7769 XtRemoveTimeOut(clockTimerXID);
7778 ClockTimerCallback(arg, id)
7787 StartClockTimer(millisec)
7791 XtAppAddTimeOut(appContext, millisec,
7792 (XtTimerCallbackProc) ClockTimerCallback,
7797 DisplayTimerLabel(w, color, timer, highlight)
7806 /* check for low time warning */
7807 Pixel foregroundOrWarningColor = timerForegroundPixel;
7810 appData.lowTimeWarning &&
7811 (timer / 1000) < appData.icsAlarmTime)
7812 foregroundOrWarningColor = lowTimeWarningColor;
7814 if (appData.clockMode) {
7815 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7816 XtSetArg(args[0], XtNlabel, buf);
7818 snprintf(buf, MSG_SIZ, "%s ", color);
7819 XtSetArg(args[0], XtNlabel, buf);
7824 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7825 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7827 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7828 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7831 XtSetValues(w, args, 3);
7835 DisplayWhiteClock(timeRemaining, highlight)
7841 if(appData.noGUI) return;
7842 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7843 if (highlight && iconPixmap == bIconPixmap) {
7844 iconPixmap = wIconPixmap;
7845 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7846 XtSetValues(shellWidget, args, 1);
7851 DisplayBlackClock(timeRemaining, highlight)
7857 if(appData.noGUI) return;
7858 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7859 if (highlight && iconPixmap == wIconPixmap) {
7860 iconPixmap = bIconPixmap;
7861 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7862 XtSetValues(shellWidget, args, 1);
7880 int StartChildProcess(cmdLine, dir, pr)
7887 int to_prog[2], from_prog[2];
7891 if (appData.debugMode) {
7892 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7895 /* We do NOT feed the cmdLine to the shell; we just
7896 parse it into blank-separated arguments in the
7897 most simple-minded way possible.
7900 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7903 while(*p == ' ') p++;
7905 if(*p == '"' || *p == '\'')
7906 p = strchr(++argv[i-1], *p);
7907 else p = strchr(p, ' ');
7908 if (p == NULL) break;
7913 SetUpChildIO(to_prog, from_prog);
7915 if ((pid = fork()) == 0) {
7917 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7918 close(to_prog[1]); // first close the unused pipe ends
7919 close(from_prog[0]);
7920 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7921 dup2(from_prog[1], 1);
7922 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7923 close(from_prog[1]); // and closing again loses one of the pipes!
7924 if(fileno(stderr) >= 2) // better safe than sorry...
7925 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7927 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7932 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7934 execvp(argv[0], argv);
7936 /* If we get here, exec failed */
7941 /* Parent process */
7943 close(from_prog[1]);
7945 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7948 cp->fdFrom = from_prog[0];
7949 cp->fdTo = to_prog[1];
7954 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7955 static RETSIGTYPE AlarmCallBack(int n)
7961 DestroyChildProcess(pr, signalType)
7965 ChildProc *cp = (ChildProc *) pr;
7967 if (cp->kind != CPReal) return;
7969 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7970 signal(SIGALRM, AlarmCallBack);
7972 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7973 kill(cp->pid, SIGKILL); // kill it forcefully
7974 wait((int *) 0); // and wait again
7978 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7980 /* Process is exiting either because of the kill or because of
7981 a quit command sent by the backend; either way, wait for it to die.
7990 InterruptChildProcess(pr)
7993 ChildProc *cp = (ChildProc *) pr;
7995 if (cp->kind != CPReal) return;
7996 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7999 int OpenTelnet(host, port, pr)
8004 char cmdLine[MSG_SIZ];
8006 if (port[0] == NULLCHAR) {
8007 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
8009 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
8011 return StartChildProcess(cmdLine, "", pr);
8014 int OpenTCP(host, port, pr)
8020 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
8021 #else /* !OMIT_SOCKETS */
8023 struct sockaddr_in sa;
8025 unsigned short uport;
8028 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
8032 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
8033 sa.sin_family = AF_INET;
8034 sa.sin_addr.s_addr = INADDR_ANY;
8035 uport = (unsigned short) 0;
8036 sa.sin_port = htons(uport);
8037 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
8041 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
8042 if (!(hp = gethostbyname(host))) {
8044 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
8045 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
8046 hp->h_addrtype = AF_INET;
8048 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
8049 hp->h_addr_list[0] = (char *) malloc(4);
8050 hp->h_addr_list[0][0] = b0;
8051 hp->h_addr_list[0][1] = b1;
8052 hp->h_addr_list[0][2] = b2;
8053 hp->h_addr_list[0][3] = b3;
8058 sa.sin_family = hp->h_addrtype;
8059 uport = (unsigned short) atoi(port);
8060 sa.sin_port = htons(uport);
8061 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
8063 if (connect(s, (struct sockaddr *) &sa,
8064 sizeof(struct sockaddr_in)) < 0) {
8068 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8075 #endif /* !OMIT_SOCKETS */
8080 int OpenCommPort(name, pr)
8087 fd = open(name, 2, 0);
8088 if (fd < 0) return errno;
8090 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8100 int OpenLoopback(pr)
8106 SetUpChildIO(to, from);
8108 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8111 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
8118 int OpenRcmd(host, user, cmd, pr)
8119 char *host, *user, *cmd;
8122 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
8126 #define INPUT_SOURCE_BUF_SIZE 8192
8135 char buf[INPUT_SOURCE_BUF_SIZE];
8140 DoInputCallback(closure, source, xid)
8145 InputSource *is = (InputSource *) closure;
8150 if (is->lineByLine) {
8151 count = read(is->fd, is->unused,
8152 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
8154 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
8157 is->unused += count;
8159 while (p < is->unused) {
8160 q = memchr(p, '\n', is->unused - p);
8161 if (q == NULL) break;
8163 (is->func)(is, is->closure, p, q - p, 0);
8167 while (p < is->unused) {
8172 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8177 (is->func)(is, is->closure, is->buf, count, error);
8181 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8188 ChildProc *cp = (ChildProc *) pr;
8190 is = (InputSource *) calloc(1, sizeof(InputSource));
8191 is->lineByLine = lineByLine;
8195 is->fd = fileno(stdin);
8197 is->kind = cp->kind;
8198 is->fd = cp->fdFrom;
8201 is->unused = is->buf;
8204 is->xid = XtAppAddInput(appContext, is->fd,
8205 (XtPointer) (XtInputReadMask),
8206 (XtInputCallbackProc) DoInputCallback,
8208 is->closure = closure;
8209 return (InputSourceRef) is;
8213 RemoveInputSource(isr)
8216 InputSource *is = (InputSource *) isr;
8218 if (is->xid == 0) return;
8219 XtRemoveInput(is->xid);
8223 int OutputToProcess(pr, message, count, outError)
8229 static int line = 0;
8230 ChildProc *cp = (ChildProc *) pr;
8235 if (appData.noJoin || !appData.useInternalWrap)
8236 outCount = fwrite(message, 1, count, stdout);
8239 int width = get_term_width();
8240 int len = wrap(NULL, message, count, width, &line);
8241 char *msg = malloc(len);
8245 outCount = fwrite(message, 1, count, stdout);
8248 dbgchk = wrap(msg, message, count, width, &line);
8249 if (dbgchk != len && appData.debugMode)
8250 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8251 outCount = fwrite(msg, 1, dbgchk, stdout);
8257 outCount = write(cp->fdTo, message, count);
8267 /* Output message to process, with "ms" milliseconds of delay
8268 between each character. This is needed when sending the logon
8269 script to ICC, which for some reason doesn't like the
8270 instantaneous send. */
8271 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8278 ChildProc *cp = (ChildProc *) pr;
8283 r = write(cp->fdTo, message++, 1);
8296 /**** Animation code by Hugh Fisher, DCS, ANU.
8298 Known problem: if a window overlapping the board is
8299 moved away while a piece is being animated underneath,
8300 the newly exposed area won't be updated properly.
8301 I can live with this.
8303 Known problem: if you look carefully at the animation
8304 of pieces in mono mode, they are being drawn as solid
8305 shapes without interior detail while moving. Fixing
8306 this would be a major complication for minimal return.
8309 /* Masks for XPM pieces. Black and white pieces can have
8310 different shapes, but in the interest of retaining my
8311 sanity pieces must have the same outline on both light
8312 and dark squares, and all pieces must use the same
8313 background square colors/images. */
8315 static int xpmDone = 0;
8318 CreateAnimMasks (pieceDepth)
8325 unsigned long plane;
8328 /* Need a bitmap just to get a GC with right depth */
8329 buf = XCreatePixmap(xDisplay, xBoardWindow,
8331 values.foreground = 1;
8332 values.background = 0;
8333 /* Don't use XtGetGC, not read only */
8334 maskGC = XCreateGC(xDisplay, buf,
8335 GCForeground | GCBackground, &values);
8336 XFreePixmap(xDisplay, buf);
8338 buf = XCreatePixmap(xDisplay, xBoardWindow,
8339 squareSize, squareSize, pieceDepth);
8340 values.foreground = XBlackPixel(xDisplay, xScreen);
8341 values.background = XWhitePixel(xDisplay, xScreen);
8342 bufGC = XCreateGC(xDisplay, buf,
8343 GCForeground | GCBackground, &values);
8345 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8346 /* Begin with empty mask */
8347 if(!xpmDone) // [HGM] pieces: keep using existing
8348 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8349 squareSize, squareSize, 1);
8350 XSetFunction(xDisplay, maskGC, GXclear);
8351 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8352 0, 0, squareSize, squareSize);
8354 /* Take a copy of the piece */
8359 XSetFunction(xDisplay, bufGC, GXcopy);
8360 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8362 0, 0, squareSize, squareSize, 0, 0);
8364 /* XOR the background (light) over the piece */
8365 XSetFunction(xDisplay, bufGC, GXxor);
8367 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8368 0, 0, squareSize, squareSize, 0, 0);
8370 XSetForeground(xDisplay, bufGC, lightSquareColor);
8371 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8374 /* We now have an inverted piece image with the background
8375 erased. Construct mask by just selecting all the non-zero
8376 pixels - no need to reconstruct the original image. */
8377 XSetFunction(xDisplay, maskGC, GXor);
8379 /* Might be quicker to download an XImage and create bitmap
8380 data from it rather than this N copies per piece, but it
8381 only takes a fraction of a second and there is a much
8382 longer delay for loading the pieces. */
8383 for (n = 0; n < pieceDepth; n ++) {
8384 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8385 0, 0, squareSize, squareSize,
8391 XFreePixmap(xDisplay, buf);
8392 XFreeGC(xDisplay, bufGC);
8393 XFreeGC(xDisplay, maskGC);
8397 InitAnimState (anim, info)
8399 XWindowAttributes * info;
8404 /* Each buffer is square size, same depth as window */
8405 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8406 squareSize, squareSize, info->depth);
8407 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8408 squareSize, squareSize, info->depth);
8410 /* Create a plain GC for blitting */
8411 mask = GCForeground | GCBackground | GCFunction |
8412 GCPlaneMask | GCGraphicsExposures;
8413 values.foreground = XBlackPixel(xDisplay, xScreen);
8414 values.background = XWhitePixel(xDisplay, xScreen);
8415 values.function = GXcopy;
8416 values.plane_mask = AllPlanes;
8417 values.graphics_exposures = False;
8418 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8420 /* Piece will be copied from an existing context at
8421 the start of each new animation/drag. */
8422 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8424 /* Outline will be a read-only copy of an existing */
8425 anim->outlineGC = None;
8431 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8432 XWindowAttributes info;
8434 if (xpmDone && gameInfo.variant == old) return;
8435 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8436 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8438 InitAnimState(&game, &info);
8439 InitAnimState(&player, &info);
8441 /* For XPM pieces, we need bitmaps to use as masks. */
8443 CreateAnimMasks(info.depth);
8449 static Boolean frameWaiting;
8451 static RETSIGTYPE FrameAlarm (sig)
8454 frameWaiting = False;
8455 /* In case System-V style signals. Needed?? */
8456 signal(SIGALRM, FrameAlarm);
8463 struct itimerval delay;
8465 XSync(xDisplay, False);
8468 frameWaiting = True;
8469 signal(SIGALRM, FrameAlarm);
8470 delay.it_interval.tv_sec =
8471 delay.it_value.tv_sec = time / 1000;
8472 delay.it_interval.tv_usec =
8473 delay.it_value.tv_usec = (time % 1000) * 1000;
8474 setitimer(ITIMER_REAL, &delay, NULL);
8475 while (frameWaiting) pause();
8476 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8477 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8478 setitimer(ITIMER_REAL, &delay, NULL);
8488 XSync(xDisplay, False);
8490 usleep(time * 1000);
8495 /* Convert board position to corner of screen rect and color */
8498 ScreenSquare(column, row, pt, color)
8499 int column; int row; XPoint * pt; int * color;
8502 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8503 pt->y = lineGap + row * (squareSize + lineGap);
8505 pt->x = lineGap + column * (squareSize + lineGap);
8506 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8508 *color = SquareColor(row, column);
8511 /* Convert window coords to square */
8514 BoardSquare(x, y, column, row)
8515 int x; int y; int * column; int * row;
8517 *column = EventToSquare(x, BOARD_WIDTH);
8518 if (flipView && *column >= 0)
8519 *column = BOARD_WIDTH - 1 - *column;
8520 *row = EventToSquare(y, BOARD_HEIGHT);
8521 if (!flipView && *row >= 0)
8522 *row = BOARD_HEIGHT - 1 - *row;
8527 #undef Max /* just in case */
8529 #define Max(a, b) ((a) > (b) ? (a) : (b))
8530 #define Min(a, b) ((a) < (b) ? (a) : (b))
8533 SetRect(rect, x, y, width, height)
8534 XRectangle * rect; int x; int y; int width; int height;
8538 rect->width = width;
8539 rect->height = height;
8542 /* Test if two frames overlap. If they do, return
8543 intersection rect within old and location of
8544 that rect within new. */
8547 Intersect(old, new, size, area, pt)
8548 XPoint * old; XPoint * new;
8549 int size; XRectangle * area; XPoint * pt;
8551 if (old->x > new->x + size || new->x > old->x + size ||
8552 old->y > new->y + size || new->y > old->y + size) {
8555 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8556 size - abs(old->x - new->x), size - abs(old->y - new->y));
8557 pt->x = Max(old->x - new->x, 0);
8558 pt->y = Max(old->y - new->y, 0);
8563 /* For two overlapping frames, return the rect(s)
8564 in the old that do not intersect with the new. */
8567 CalcUpdateRects(old, new, size, update, nUpdates)
8568 XPoint * old; XPoint * new; int size;
8569 XRectangle update[]; int * nUpdates;
8573 /* If old = new (shouldn't happen) then nothing to draw */
8574 if (old->x == new->x && old->y == new->y) {
8578 /* Work out what bits overlap. Since we know the rects
8579 are the same size we don't need a full intersect calc. */
8581 /* Top or bottom edge? */
8582 if (new->y > old->y) {
8583 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8585 } else if (old->y > new->y) {
8586 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8587 size, old->y - new->y);
8590 /* Left or right edge - don't overlap any update calculated above. */
8591 if (new->x > old->x) {
8592 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8593 new->x - old->x, size - abs(new->y - old->y));
8595 } else if (old->x > new->x) {
8596 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8597 old->x - new->x, size - abs(new->y - old->y));
8604 /* Generate a series of frame coords from start->mid->finish.
8605 The movement rate doubles until the half way point is
8606 reached, then halves back down to the final destination,
8607 which gives a nice slow in/out effect. The algorithmn
8608 may seem to generate too many intermediates for short
8609 moves, but remember that the purpose is to attract the
8610 viewers attention to the piece about to be moved and
8611 then to where it ends up. Too few frames would be less
8615 Tween(start, mid, finish, factor, frames, nFrames)
8616 XPoint * start; XPoint * mid;
8617 XPoint * finish; int factor;
8618 XPoint frames[]; int * nFrames;
8620 int fraction, n, count;
8624 /* Slow in, stepping 1/16th, then 1/8th, ... */
8626 for (n = 0; n < factor; n++)
8628 for (n = 0; n < factor; n++) {
8629 frames[count].x = start->x + (mid->x - start->x) / fraction;
8630 frames[count].y = start->y + (mid->y - start->y) / fraction;
8632 fraction = fraction / 2;
8636 frames[count] = *mid;
8639 /* Slow out, stepping 1/2, then 1/4, ... */
8641 for (n = 0; n < factor; n++) {
8642 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8643 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8645 fraction = fraction * 2;
8650 /* Draw a piece on the screen without disturbing what's there */
8653 SelectGCMask(piece, clip, outline, mask)
8654 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8658 /* Bitmap for piece being moved. */
8659 if (appData.monoMode) {
8660 *mask = *pieceToSolid(piece);
8661 } else if (useImages) {
8663 *mask = xpmMask[piece];
8665 *mask = ximMaskPm[piece];
8668 *mask = *pieceToSolid(piece);
8671 /* GC for piece being moved. Square color doesn't matter, but
8672 since it gets modified we make a copy of the original. */
8674 if (appData.monoMode)
8679 if (appData.monoMode)
8684 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8686 /* Outline only used in mono mode and is not modified */
8688 *outline = bwPieceGC;
8690 *outline = wbPieceGC;
8694 OverlayPiece(piece, clip, outline, dest)
8695 ChessSquare piece; GC clip; GC outline; Drawable dest;
8700 /* Draw solid rectangle which will be clipped to shape of piece */
8701 XFillRectangle(xDisplay, dest, clip,
8702 0, 0, squareSize, squareSize);
8703 if (appData.monoMode)
8704 /* Also draw outline in contrasting color for black
8705 on black / white on white cases */
8706 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8707 0, 0, squareSize, squareSize, 0, 0, 1);
8709 /* Copy the piece */
8714 if(appData.upsideDown && flipView) kind ^= 2;
8715 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8717 0, 0, squareSize, squareSize,
8722 /* Animate the movement of a single piece */
8725 BeginAnimation(anim, piece, startColor, start)
8733 /* The old buffer is initialised with the start square (empty) */
8734 BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0);
8735 anim->prevFrame = *start;
8737 /* The piece will be drawn using its own bitmap as a matte */
8738 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8739 XSetClipMask(xDisplay, anim->pieceGC, mask);
8743 AnimationFrame(anim, frame, piece)
8748 XRectangle updates[4];
8753 /* Save what we are about to draw into the new buffer */
8754 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8755 frame->x, frame->y, squareSize, squareSize,
8758 /* Erase bits of the previous frame */
8759 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8760 /* Where the new frame overlapped the previous,
8761 the contents in newBuf are wrong. */
8762 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8763 overlap.x, overlap.y,
8764 overlap.width, overlap.height,
8766 /* Repaint the areas in the old that don't overlap new */
8767 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8768 for (i = 0; i < count; i++)
8769 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8770 updates[i].x - anim->prevFrame.x,
8771 updates[i].y - anim->prevFrame.y,
8772 updates[i].width, updates[i].height,
8773 updates[i].x, updates[i].y);
8775 /* Easy when no overlap */
8776 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8777 0, 0, squareSize, squareSize,
8778 anim->prevFrame.x, anim->prevFrame.y);
8781 /* Save this frame for next time round */
8782 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8783 0, 0, squareSize, squareSize,
8785 anim->prevFrame = *frame;
8787 /* Draw piece over original screen contents, not current,
8788 and copy entire rect. Wipes out overlapping piece images. */
8789 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8790 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8791 0, 0, squareSize, squareSize,
8792 frame->x, frame->y);
8796 EndAnimation (anim, finish)
8800 XRectangle updates[4];
8805 /* The main code will redraw the final square, so we
8806 only need to erase the bits that don't overlap. */
8807 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8808 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8809 for (i = 0; i < count; i++)
8810 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8811 updates[i].x - anim->prevFrame.x,
8812 updates[i].y - anim->prevFrame.y,
8813 updates[i].width, updates[i].height,
8814 updates[i].x, updates[i].y);
8816 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8817 0, 0, squareSize, squareSize,
8818 anim->prevFrame.x, anim->prevFrame.y);
8823 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8825 ChessSquare piece; int startColor;
8826 XPoint * start; XPoint * finish;
8827 XPoint frames[]; int nFrames;
8831 BeginAnimation(anim, piece, startColor, start);
8832 for (n = 0; n < nFrames; n++) {
8833 AnimationFrame(anim, &(frames[n]), piece);
8834 FrameDelay(appData.animSpeed);
8836 EndAnimation(anim, finish);
8840 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
8843 ChessSquare piece = board[fromY][toY];
8844 board[fromY][toY] = EmptySquare;
8845 DrawPosition(FALSE, board);
8847 x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap);
8848 y = lineGap + toY * (squareSize + lineGap);
8850 x = lineGap + toX * (squareSize + lineGap);
8851 y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap);
8853 for(i=1; i<4*kFactor; i++) {
8854 int r = squareSize * 9 * i/(20*kFactor - 5);
8855 XFillArc(xDisplay, xBoardWindow, highlineGC,
8856 x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360);
8857 FrameDelay(appData.animSpeed);
8859 board[fromY][toY] = piece;
8862 /* Main control logic for deciding what to animate and how */
8865 AnimateMove(board, fromX, fromY, toX, toY)
8874 XPoint start, finish, mid;
8875 XPoint frames[kFactor * 2 + 1];
8876 int nFrames, startColor, endColor;
8878 /* Are we animating? */
8879 if (!appData.animate || appData.blindfold)
8882 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8883 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8884 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8886 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8887 piece = board[fromY][fromX];
8888 if (piece >= EmptySquare) return;
8893 hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1;
8896 if (appData.debugMode) {
8897 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8898 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8899 piece, fromX, fromY, toX, toY); }
8901 ScreenSquare(fromX, fromY, &start, &startColor);
8902 ScreenSquare(toX, toY, &finish, &endColor);
8905 /* Knight: make straight movement then diagonal */
8906 if (abs(toY - fromY) < abs(toX - fromX)) {
8907 mid.x = start.x + (finish.x - start.x) / 2;
8911 mid.y = start.y + (finish.y - start.y) / 2;
8914 mid.x = start.x + (finish.x - start.x) / 2;
8915 mid.y = start.y + (finish.y - start.y) / 2;
8918 /* Don't use as many frames for very short moves */
8919 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8920 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8922 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8923 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8924 if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
8926 for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
8927 if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
8930 /* Be sure end square is redrawn */
8931 damage[0][toY][toX] = True;
8935 DragPieceBegin(x, y)
8938 int boardX, boardY, color;
8941 /* Are we animating? */
8942 if (!appData.animateDragging || appData.blindfold)
8945 /* Figure out which square we start in and the
8946 mouse position relative to top left corner. */
8947 BoardSquare(x, y, &boardX, &boardY);
8948 player.startBoardX = boardX;
8949 player.startBoardY = boardY;
8950 ScreenSquare(boardX, boardY, &corner, &color);
8951 player.startSquare = corner;
8952 player.startColor = color;
8953 /* As soon as we start dragging, the piece will jump slightly to
8954 be centered over the mouse pointer. */
8955 player.mouseDelta.x = squareSize/2;
8956 player.mouseDelta.y = squareSize/2;
8957 /* Initialise animation */
8958 player.dragPiece = PieceForSquare(boardX, boardY);
8960 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8961 player.dragActive = True;
8962 BeginAnimation(&player, player.dragPiece, color, &corner);
8963 /* Mark this square as needing to be redrawn. Note that
8964 we don't remove the piece though, since logically (ie
8965 as seen by opponent) the move hasn't been made yet. */
8966 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8967 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8968 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8969 corner.x, corner.y, squareSize, squareSize,
8970 0, 0); // [HGM] zh: unstack in stead of grab
8971 if(gatingPiece != EmptySquare) {
8972 /* Kludge alert: When gating we want the introduced
8973 piece to appear on the from square. To generate an
8974 image of it, we draw it on the board, copy the image,
8975 and draw the original piece again. */
8976 ChessSquare piece = boards[currentMove][boardY][boardX];
8977 DrawSquare(boardY, boardX, gatingPiece, 0);
8978 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8979 corner.x, corner.y, squareSize, squareSize, 0, 0);
8980 DrawSquare(boardY, boardX, piece, 0);
8982 damage[0][boardY][boardX] = True;
8984 player.dragActive = False;
8994 /* Are we animating? */
8995 if (!appData.animateDragging || appData.blindfold)
8999 if (! player.dragActive)
9001 /* Move piece, maintaining same relative position
9002 of mouse within square */
9003 corner.x = x - player.mouseDelta.x;
9004 corner.y = y - player.mouseDelta.y;
9005 AnimationFrame(&player, &corner, player.dragPiece);
9007 if (appData.highlightDragging) {
9009 BoardSquare(x, y, &boardX, &boardY);
9010 SetHighlights(fromX, fromY, boardX, boardY);
9019 int boardX, boardY, color;
9022 /* Are we animating? */
9023 if (!appData.animateDragging || appData.blindfold)
9027 if (! player.dragActive)
9029 /* Last frame in sequence is square piece is
9030 placed on, which may not match mouse exactly. */
9031 BoardSquare(x, y, &boardX, &boardY);
9032 ScreenSquare(boardX, boardY, &corner, &color);
9033 EndAnimation(&player, &corner);
9035 /* Be sure end square is redrawn */
9036 damage[0][boardY][boardX] = True;
9038 /* This prevents weird things happening with fast successive
9039 clicks which on my Sun at least can cause motion events
9040 without corresponding press/release. */
9041 player.dragActive = False;
9044 /* Handle expose event while piece being dragged */
9049 if (!player.dragActive || appData.blindfold)
9052 /* What we're doing: logically, the move hasn't been made yet,
9053 so the piece is still in it's original square. But visually
9054 it's being dragged around the board. So we erase the square
9055 that the piece is on and draw it at the last known drag point. */
9056 BlankSquare(player.startSquare.x, player.startSquare.y,
9057 player.startColor, EmptySquare, xBoardWindow, 1);
9058 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
9059 damage[0][player.startBoardY][player.startBoardX] = TRUE;
9062 #include <sys/ioctl.h>
9063 int get_term_width()
9065 int fd, default_width;
9068 default_width = 79; // this is FICS default anyway...
9070 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
9072 if (!ioctl(fd, TIOCGSIZE, &win))
9073 default_width = win.ts_cols;
9074 #elif defined(TIOCGWINSZ)
9076 if (!ioctl(fd, TIOCGWINSZ, &win))
9077 default_width = win.ws_col;
9079 return default_width;
9085 static int old_width = 0;
9086 int new_width = get_term_width();
9088 if (old_width != new_width)
9089 ics_printf("set width %d\n", new_width);
9090 old_width = new_width;
9093 void NotifyFrontendLogin()