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 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"
197 #include "xgamelist.h"
198 #include "xhistory.h"
199 #include "xedittags.h"
202 // must be moved to xengineoutput.h
204 void EngineOutputProc P((Widget w, XEvent *event,
205 String *prms, Cardinal *nprms));
206 void EvalGraphProc P((Widget w, XEvent *event,
207 String *prms, Cardinal *nprms));
214 #define usleep(t) _sleep2(((t)+500)/1000)
218 # define _(s) gettext (s)
219 # define N_(s) gettext_noop (s)
235 int main P((int argc, char **argv));
236 RETSIGTYPE CmailSigHandler P((int sig));
237 RETSIGTYPE IntSigHandler P((int sig));
238 RETSIGTYPE TermSizeSigHandler P((int sig));
239 void CreateGCs P((void));
240 void CreateXIMPieces P((void));
241 void CreateXPMPieces P((void));
242 void CreatePieces P((void));
243 void CreatePieceMenus P((void));
244 Widget CreateMenuBar P((Menu *mb));
245 Widget CreateButtonBar P ((MenuItem *mi));
246 char *FindFont P((char *pattern, int targetPxlSize));
247 void PieceMenuPopup P((Widget w, XEvent *event,
248 String *params, Cardinal *num_params));
249 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
250 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
251 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
252 u_int wreq, u_int hreq));
253 void CreateGrid P((void));
254 int EventToSquare P((int x, int limit));
255 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
256 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
257 void HandleUserMove P((Widget w, XEvent *event,
258 String *prms, Cardinal *nprms));
259 void AnimateUserMove P((Widget w, XEvent * event,
260 String * params, Cardinal * nParams));
261 void HandlePV P((Widget w, XEvent * event,
262 String * params, Cardinal * nParams));
263 void WhiteClock P((Widget w, XEvent *event,
264 String *prms, Cardinal *nprms));
265 void BlackClock P((Widget w, XEvent *event,
266 String *prms, Cardinal *nprms));
267 void DrawPositionProc P((Widget w, XEvent *event,
268 String *prms, Cardinal *nprms));
269 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
271 void CommentPopUp P((char *title, char *label));
272 void CommentPopDown P((void));
273 void CommentCallback P((Widget w, XtPointer client_data,
274 XtPointer call_data));
275 void ICSInputBoxPopUp P((void));
276 void ICSInputBoxPopDown P((void));
277 void FileNamePopUp P((char *label, char *def,
278 FileProc proc, char *openMode));
279 void FileNamePopDown P((void));
280 void FileNameCallback P((Widget w, XtPointer client_data,
281 XtPointer call_data));
282 void FileNameAction P((Widget w, XEvent *event,
283 String *prms, Cardinal *nprms));
284 void AskQuestionReplyAction P((Widget w, XEvent *event,
285 String *prms, Cardinal *nprms));
286 void AskQuestionProc P((Widget w, XEvent *event,
287 String *prms, Cardinal *nprms));
288 void AskQuestionPopDown P((void));
289 void PromotionPopDown P((void));
290 void PromotionCallback P((Widget w, XtPointer client_data,
291 XtPointer call_data));
292 void EditCommentPopDown P((void));
293 void EditCommentCallback P((Widget w, XtPointer client_data,
294 XtPointer call_data));
295 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
296 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
297 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
298 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
300 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
302 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
304 void LoadPositionProc P((Widget w, XEvent *event,
305 String *prms, Cardinal *nprms));
306 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
308 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
310 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
312 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
314 void PastePositionProc P((Widget w, XEvent *event, String *prms,
316 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
317 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
318 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
319 void SavePositionProc P((Widget w, XEvent *event,
320 String *prms, Cardinal *nprms));
321 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
322 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
324 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
325 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
326 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
328 void MachineWhiteProc P((Widget w, XEvent *event,
329 String *prms, Cardinal *nprms));
330 void AnalyzeModeProc P((Widget w, XEvent *event,
331 String *prms, Cardinal *nprms));
332 void AnalyzeFileProc P((Widget w, XEvent *event,
333 String *prms, Cardinal *nprms));
334 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
336 void IcsClientProc P((Widget w, XEvent *event, String *prms,
338 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
339 void EditPositionProc P((Widget w, XEvent *event,
340 String *prms, Cardinal *nprms));
341 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
342 void EditCommentProc P((Widget w, XEvent *event,
343 String *prms, Cardinal *nprms));
344 void IcsInputBoxProc P((Widget w, XEvent *event,
345 String *prms, Cardinal *nprms));
346 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
347 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
348 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
349 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
350 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
351 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
352 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
353 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
354 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
355 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
356 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
357 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
358 void StopObservingProc P((Widget w, XEvent *event, String *prms,
360 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
362 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
365 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
369 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
371 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
372 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
374 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
376 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
378 void AutocommProc P((Widget w, XEvent *event, String *prms,
380 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void AutobsProc P((Widget w, XEvent *event, String *prms,
384 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
385 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
386 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
387 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
389 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
390 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
392 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
394 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
396 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
397 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
398 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
400 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
402 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
404 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
406 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
408 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
409 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
410 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
412 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
414 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
416 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
418 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
419 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
420 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
421 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
422 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
423 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
424 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
425 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
426 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
427 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
428 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
429 void DisplayMove P((int moveNumber));
430 void DisplayTitle P((char *title));
431 void ICSInitScript P((void));
432 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
433 void ErrorPopUp P((char *title, char *text, int modal));
434 void ErrorPopDown P((void));
435 static char *ExpandPathName P((char *path));
436 static void CreateAnimVars P((void));
437 static void DragPieceMove P((int x, int y));
438 static void DrawDragPiece P((void));
439 char *ModeToWidgetName P((GameMode mode));
440 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
442 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
443 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
444 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
445 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
446 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
447 void ShufflePopDown P(());
448 void EnginePopDown P(());
449 void UciPopDown P(());
450 void TimeControlPopDown P(());
451 void NewVariantPopDown P(());
452 void SettingsPopDown P(());
453 void update_ics_width P(());
454 int get_term_width P(());
455 int CopyMemoProc P(());
457 * XBoard depends on Xt R4 or higher
459 int xtVersion = XtSpecificationRelease;
464 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
465 jailSquareColor, highlightSquareColor, premoveHighlightColor;
466 Pixel lowTimeWarningColor;
467 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
468 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
469 wjPieceGC, bjPieceGC, prelineGC, countGC;
470 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
471 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
472 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
473 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
474 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
475 ICSInputShell, fileNameShell, askQuestionShell;
476 Widget historyShell, evalGraphShell, gameListShell;
477 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
478 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
479 Font clockFontID, coordFontID, countFontID;
480 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
481 XtAppContext appContext;
483 char *oldICSInteractionTitle;
487 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
489 Position commentX = -1, commentY = -1;
490 Dimension commentW, commentH;
491 typedef unsigned int BoardSize;
493 Boolean chessProgram;
495 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
496 int squareSize, smallLayout = 0, tinyLayout = 0,
497 marginW, marginH, // [HGM] for run-time resizing
498 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
499 ICSInputBoxUp = False, askQuestionUp = False,
500 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
501 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
502 Pixel timerForegroundPixel, timerBackgroundPixel;
503 Pixel buttonForegroundPixel, buttonBackgroundPixel;
504 char *chessDir, *programName, *programVersion,
505 *gameCopyFilename, *gamePasteFilename;
506 Boolean alwaysOnTop = False;
507 Boolean saveSettingsOnExit;
508 char *settingsFileName;
509 char *icsTextMenuString;
511 char *firstChessProgramNames;
512 char *secondChessProgramNames;
514 WindowPlacement wpMain;
515 WindowPlacement wpConsole;
516 WindowPlacement wpComment;
517 WindowPlacement wpMoveHistory;
518 WindowPlacement wpEvalGraph;
519 WindowPlacement wpEngineOutput;
520 WindowPlacement wpGameList;
521 WindowPlacement wpTags;
525 Pixmap pieceBitmap[2][(int)BlackPawn];
526 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
527 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
528 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
529 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
530 int useImages, useImageSqs;
531 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
532 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
533 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
534 XImage *ximLightSquare, *ximDarkSquare;
537 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
538 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
540 #define White(piece) ((int)(piece) < (int)BlackPawn)
542 /* Variables for doing smooth animation. This whole thing
543 would be much easier if the board was double-buffered,
544 but that would require a fairly major rewrite. */
549 GC blitGC, pieceGC, outlineGC;
550 XPoint startSquare, prevFrame, mouseDelta;
554 int startBoardX, startBoardY;
557 /* There can be two pieces being animated at once: a player
558 can begin dragging a piece before the remote opponent has moved. */
560 static AnimState game, player;
562 /* Bitmaps for use as masks when drawing XPM pieces.
563 Need one for each black and white piece. */
564 static Pixmap xpmMask[BlackKing + 1];
566 /* This magic number is the number of intermediate frames used
567 in each half of the animation. For short moves it's reduced
568 by 1. The total number of frames will be factor * 2 + 1. */
571 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
573 MenuItem fileMenu[] = {
574 {N_("New Game"), ResetProc},
575 {N_("New Shuffle Game ..."), ShuffleMenuProc},
576 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
577 {"----", NothingProc},
578 {N_("Load Game"), LoadGameProc},
579 {N_("Load Next Game"), LoadNextGameProc},
580 {N_("Load Previous Game"), LoadPrevGameProc},
581 {N_("Reload Same Game"), ReloadGameProc},
582 {N_("Save Game"), SaveGameProc},
583 {"----", NothingProc},
584 {N_("Copy Game"), CopyGameProc},
585 {N_("Paste Game"), PasteGameProc},
586 {"----", NothingProc},
587 {N_("Load Position"), LoadPositionProc},
588 {N_("Load Next Position"), LoadNextPositionProc},
589 {N_("Load Previous Position"), LoadPrevPositionProc},
590 {N_("Reload Same Position"), ReloadPositionProc},
591 {N_("Save Position"), SavePositionProc},
592 {"----", NothingProc},
593 {N_("Copy Position"), CopyPositionProc},
594 {N_("Paste Position"), PastePositionProc},
595 {"----", NothingProc},
596 {N_("Mail Move"), MailMoveProc},
597 {N_("Reload CMail Message"), ReloadCmailMsgProc},
598 {"----", NothingProc},
599 {N_("Exit"), QuitProc},
603 MenuItem modeMenu[] = {
604 {N_("Machine White"), MachineWhiteProc},
605 {N_("Machine Black"), MachineBlackProc},
606 {N_("Two Machines"), TwoMachinesProc},
607 {N_("Analysis Mode"), AnalyzeModeProc},
608 {N_("Analyze File"), AnalyzeFileProc },
609 {N_("ICS Client"), IcsClientProc},
610 {N_("Edit Game"), EditGameProc},
611 {N_("Edit Position"), EditPositionProc},
612 {N_("Training"), TrainingProc},
613 {"----", NothingProc},
614 {N_("Show Engine Output"), EngineOutputProc},
615 {N_("Show Evaluation Graph"), EvalGraphProc},
616 {N_("Show Game List"), ShowGameListProc},
617 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
618 {"----", NothingProc},
619 {N_("Edit Tags"), EditTagsProc},
620 {N_("Edit Comment"), EditCommentProc},
621 {N_("ICS Input Box"), IcsInputBoxProc},
622 {N_("Pause"), PauseProc},
626 MenuItem actionMenu[] = {
627 {N_("Accept"), AcceptProc},
628 {N_("Decline"), DeclineProc},
629 {N_("Rematch"), RematchProc},
630 {"----", NothingProc},
631 {N_("Call Flag"), CallFlagProc},
632 {N_("Draw"), DrawProc},
633 {N_("Adjourn"), AdjournProc},
634 {N_("Abort"), AbortProc},
635 {N_("Resign"), ResignProc},
636 {"----", NothingProc},
637 {N_("Stop Observing"), StopObservingProc},
638 {N_("Stop Examining"), StopExaminingProc},
639 {"----", NothingProc},
640 {N_("Adjudicate to White"), AdjuWhiteProc},
641 {N_("Adjudicate to Black"), AdjuBlackProc},
642 {N_("Adjudicate Draw"), AdjuDrawProc},
646 MenuItem stepMenu[] = {
647 {N_("Backward"), BackwardProc},
648 {N_("Forward"), ForwardProc},
649 {N_("Back to Start"), ToStartProc},
650 {N_("Forward to End"), ToEndProc},
651 {N_("Revert"), RevertProc},
652 {N_("Truncate Game"), TruncateGameProc},
653 {"----", NothingProc},
654 {N_("Move Now"), MoveNowProc},
655 {N_("Retract Move"), RetractMoveProc},
659 MenuItem optionsMenu[] = {
660 {N_("Flip View"), FlipViewProc},
661 {"----", NothingProc},
662 {N_("Adjudications ..."), EngineMenuProc},
663 {N_("General Settings ..."), UciMenuProc},
664 {N_("Engine #1 Settings ..."), FirstSettingsProc},
665 {N_("Engine #2 Settings ..."), SecondSettingsProc},
666 {N_("Time Control ..."), TimeControlProc},
667 {"----", NothingProc},
668 {N_("Always Queen"), AlwaysQueenProc},
669 {N_("Animate Dragging"), AnimateDraggingProc},
670 {N_("Animate Moving"), AnimateMovingProc},
671 {N_("Auto Comment"), AutocommProc},
672 {N_("Auto Flag"), AutoflagProc},
673 {N_("Auto Flip View"), AutoflipProc},
674 {N_("Auto Observe"), AutobsProc},
675 {N_("Auto Raise Board"), AutoraiseProc},
676 {N_("Auto Save"), AutosaveProc},
677 {N_("Blindfold"), BlindfoldProc},
678 {N_("Flash Moves"), FlashMovesProc},
679 {N_("Get Move List"), GetMoveListProc},
681 {N_("Highlight Dragging"), HighlightDraggingProc},
683 {N_("Highlight Last Move"), HighlightLastMoveProc},
684 {N_("Move Sound"), MoveSoundProc},
685 {N_("ICS Alarm"), IcsAlarmProc},
686 {N_("Old Save Style"), OldSaveStyleProc},
687 {N_("Periodic Updates"), PeriodicUpdatesProc},
688 {N_("Ponder Next Move"), PonderNextMoveProc},
689 {N_("Popup Exit Message"), PopupExitMessageProc},
690 {N_("Popup Move Errors"), PopupMoveErrorsProc},
691 {N_("Premove"), PremoveProc},
692 {N_("Quiet Play"), QuietPlayProc},
693 {N_("Show Coords"), ShowCoordsProc},
694 {N_("Hide Thinking"), HideThinkingProc},
695 {N_("Test Legality"), TestLegalityProc},
696 {"----", NothingProc},
697 {N_("Save Settings Now"), SaveSettingsProc},
698 {N_("Save Settings on Exit"), SaveOnExitProc},
702 MenuItem helpMenu[] = {
703 {N_("Info XBoard"), InfoProc},
704 {N_("Man XBoard"), ManProc},
705 {"----", NothingProc},
706 {N_("Hint"), HintProc},
707 {N_("Book"), BookProc},
708 {"----", NothingProc},
709 {N_("About XBoard"), AboutProc},
714 {N_("File"), fileMenu},
715 {N_("Mode"), modeMenu},
716 {N_("Action"), actionMenu},
717 {N_("Step"), stepMenu},
718 {N_("Options"), optionsMenu},
719 {N_("Help"), helpMenu},
723 #define PAUSE_BUTTON N_("P")
724 MenuItem buttonBar[] = {
727 {PAUSE_BUTTON, PauseProc},
733 #define PIECE_MENU_SIZE 18
734 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
735 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
736 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
737 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
738 N_("Empty square"), N_("Clear board") },
739 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
740 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
741 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
742 N_("Empty square"), N_("Clear board") }
744 /* must be in same order as PieceMenuStrings! */
745 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
746 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
747 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
748 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
749 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
750 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
751 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
752 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
753 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
756 #define DROP_MENU_SIZE 6
757 String dropMenuStrings[DROP_MENU_SIZE] = {
758 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
760 /* must be in same order as PieceMenuStrings! */
761 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
762 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
763 WhiteRook, WhiteQueen
771 DropMenuEnables dmEnables[] = {
789 { XtNborderWidth, 0 },
790 { XtNdefaultDistance, 0 },
794 { XtNborderWidth, 0 },
795 { XtNresizable, (XtArgVal) True },
799 { XtNborderWidth, 0 },
805 { XtNjustify, (XtArgVal) XtJustifyRight },
806 { XtNlabel, (XtArgVal) "..." },
807 { XtNresizable, (XtArgVal) True },
808 { XtNresize, (XtArgVal) False }
811 Arg messageArgs[] = {
812 { XtNjustify, (XtArgVal) XtJustifyLeft },
813 { XtNlabel, (XtArgVal) "..." },
814 { XtNresizable, (XtArgVal) True },
815 { XtNresize, (XtArgVal) False }
819 { XtNborderWidth, 0 },
820 { XtNjustify, (XtArgVal) XtJustifyLeft }
823 XtResource clientResources[] = {
824 { "flashCount", "flashCount", XtRInt, sizeof(int),
825 XtOffset(AppDataPtr, flashCount), XtRImmediate,
826 (XtPointer) FLASH_COUNT },
829 XrmOptionDescRec shellOptions[] = {
830 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
831 { "-flash", "flashCount", XrmoptionNoArg, "3" },
832 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
835 XtActionsRec boardActions[] = {
836 { "DrawPosition", DrawPositionProc },
837 { "HandleUserMove", HandleUserMove },
838 { "AnimateUserMove", AnimateUserMove },
839 { "HandlePV", HandlePV },
840 { "UnLoadPV", UnLoadPV },
841 { "FileNameAction", FileNameAction },
842 { "AskQuestionProc", AskQuestionProc },
843 { "AskQuestionReplyAction", AskQuestionReplyAction },
844 { "PieceMenuPopup", PieceMenuPopup },
845 { "WhiteClock", WhiteClock },
846 { "BlackClock", BlackClock },
847 { "Iconify", Iconify },
848 { "ResetProc", ResetProc },
849 { "LoadGameProc", LoadGameProc },
850 { "LoadNextGameProc", LoadNextGameProc },
851 { "LoadPrevGameProc", LoadPrevGameProc },
852 { "LoadSelectedProc", LoadSelectedProc },
853 { "SetFilterProc", SetFilterProc },
854 { "ReloadGameProc", ReloadGameProc },
855 { "LoadPositionProc", LoadPositionProc },
856 { "LoadNextPositionProc", LoadNextPositionProc },
857 { "LoadPrevPositionProc", LoadPrevPositionProc },
858 { "ReloadPositionProc", ReloadPositionProc },
859 { "CopyPositionProc", CopyPositionProc },
860 { "PastePositionProc", PastePositionProc },
861 { "CopyGameProc", CopyGameProc },
862 { "PasteGameProc", PasteGameProc },
863 { "SaveGameProc", SaveGameProc },
864 { "SavePositionProc", SavePositionProc },
865 { "MailMoveProc", MailMoveProc },
866 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
867 { "QuitProc", QuitProc },
868 { "MachineWhiteProc", MachineWhiteProc },
869 { "MachineBlackProc", MachineBlackProc },
870 { "AnalysisModeProc", AnalyzeModeProc },
871 { "AnalyzeFileProc", AnalyzeFileProc },
872 { "TwoMachinesProc", TwoMachinesProc },
873 { "IcsClientProc", IcsClientProc },
874 { "EditGameProc", EditGameProc },
875 { "EditPositionProc", EditPositionProc },
876 { "TrainingProc", EditPositionProc },
877 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
878 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
879 { "ShowGameListProc", ShowGameListProc },
880 { "ShowMoveListProc", HistoryShowProc},
881 { "EditTagsProc", EditCommentProc },
882 { "EditCommentProc", EditCommentProc },
883 { "IcsAlarmProc", IcsAlarmProc },
884 { "IcsInputBoxProc", IcsInputBoxProc },
885 { "PauseProc", PauseProc },
886 { "AcceptProc", AcceptProc },
887 { "DeclineProc", DeclineProc },
888 { "RematchProc", RematchProc },
889 { "CallFlagProc", CallFlagProc },
890 { "DrawProc", DrawProc },
891 { "AdjournProc", AdjournProc },
892 { "AbortProc", AbortProc },
893 { "ResignProc", ResignProc },
894 { "AdjuWhiteProc", AdjuWhiteProc },
895 { "AdjuBlackProc", AdjuBlackProc },
896 { "AdjuDrawProc", AdjuDrawProc },
897 { "EnterKeyProc", EnterKeyProc },
898 { "StopObservingProc", StopObservingProc },
899 { "StopExaminingProc", StopExaminingProc },
900 { "BackwardProc", BackwardProc },
901 { "ForwardProc", ForwardProc },
902 { "ToStartProc", ToStartProc },
903 { "ToEndProc", ToEndProc },
904 { "RevertProc", RevertProc },
905 { "TruncateGameProc", TruncateGameProc },
906 { "MoveNowProc", MoveNowProc },
907 { "RetractMoveProc", RetractMoveProc },
908 { "AlwaysQueenProc", AlwaysQueenProc },
909 { "AnimateDraggingProc", AnimateDraggingProc },
910 { "AnimateMovingProc", AnimateMovingProc },
911 { "AutoflagProc", AutoflagProc },
912 { "AutoflipProc", AutoflipProc },
913 { "AutobsProc", AutobsProc },
914 { "AutoraiseProc", AutoraiseProc },
915 { "AutosaveProc", AutosaveProc },
916 { "BlindfoldProc", BlindfoldProc },
917 { "FlashMovesProc", FlashMovesProc },
918 { "FlipViewProc", FlipViewProc },
919 { "GetMoveListProc", GetMoveListProc },
921 { "HighlightDraggingProc", HighlightDraggingProc },
923 { "HighlightLastMoveProc", HighlightLastMoveProc },
924 { "IcsAlarmProc", IcsAlarmProc },
925 { "MoveSoundProc", MoveSoundProc },
926 { "OldSaveStyleProc", OldSaveStyleProc },
927 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
928 { "PonderNextMoveProc", PonderNextMoveProc },
929 { "PopupExitMessageProc", PopupExitMessageProc },
930 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
931 { "PremoveProc", PremoveProc },
932 { "QuietPlayProc", QuietPlayProc },
933 { "ShowCoordsProc", ShowCoordsProc },
934 { "ShowThinkingProc", ShowThinkingProc },
935 { "HideThinkingProc", HideThinkingProc },
936 { "TestLegalityProc", TestLegalityProc },
937 { "SaveSettingsProc", SaveSettingsProc },
938 { "SaveOnExitProc", SaveOnExitProc },
939 { "InfoProc", InfoProc },
940 { "ManProc", ManProc },
941 { "HintProc", HintProc },
942 { "BookProc", BookProc },
943 { "AboutGameProc", AboutGameProc },
944 { "AboutProc", AboutProc },
945 { "DebugProc", DebugProc },
946 { "NothingProc", NothingProc },
947 { "CommentPopDown", (XtActionProc) CommentPopDown },
948 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
949 { "TagsPopDown", (XtActionProc) TagsPopDown },
950 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
951 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
952 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
953 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
954 { "GameListPopDown", (XtActionProc) GameListPopDown },
955 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
956 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
957 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
958 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
959 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
960 { "EnginePopDown", (XtActionProc) EnginePopDown },
961 { "UciPopDown", (XtActionProc) UciPopDown },
962 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
963 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
964 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
965 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
968 char globalTranslations[] =
969 ":<Key>R: ResignProc() \n \
970 :<Key>r: ResetProc() \n \
971 :<Key>g: LoadGameProc() \n \
972 :<Key>N: LoadNextGameProc() \n \
973 :<Key>P: LoadPrevGameProc() \n \
974 :<Key>Q: QuitProc() \n \
975 :<Key>F: ToEndProc() \n \
976 :<Key>f: ForwardProc() \n \
977 :<Key>B: ToStartProc() \n \
978 :<Key>b: BackwardProc() \n \
979 :<Key>p: PauseProc() \n \
980 :<Key>d: DrawProc() \n \
981 :<Key>t: CallFlagProc() \n \
982 :<Key>i: Iconify() \n \
983 :<Key>c: Iconify() \n \
984 :<Key>v: FlipViewProc() \n \
985 <KeyDown>Control_L: BackwardProc() \n \
986 <KeyUp>Control_L: ForwardProc() \n \
987 <KeyDown>Control_R: BackwardProc() \n \
988 <KeyUp>Control_R: ForwardProc() \n \
989 Shift<Key>1: AskQuestionProc(\"Direct command\",\
990 \"Send to chess program:\",,1) \n \
991 Shift<Key>2: AskQuestionProc(\"Direct command\",\
992 \"Send to second chess program:\",,2) \n";
994 char boardTranslations[] =
995 "<Btn1Down>: HandleUserMove() \n \
996 <Btn1Up>: HandleUserMove() \n \
997 <Btn1Motion>: AnimateUserMove() \n \
998 <Btn3Motion>: HandlePV() \n \
999 <Btn3Up>: UnLoadPV() \n \
1000 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1001 PieceMenuPopup(menuB) \n \
1002 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1003 PieceMenuPopup(menuW) \n \
1004 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1005 PieceMenuPopup(menuW) \n \
1006 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1007 PieceMenuPopup(menuB) \n";
1009 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1010 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1012 char ICSInputTranslations[] =
1013 "<Key>Return: EnterKeyProc() \n";
1015 String xboardResources[] = {
1016 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1017 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1018 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1023 /* Max possible square size */
1024 #define MAXSQSIZE 256
1026 static int xpm_avail[MAXSQSIZE];
1028 #ifdef HAVE_DIR_STRUCT
1030 /* Extract piece size from filename */
1032 xpm_getsize(name, len, ext)
1043 if ((p=strchr(name, '.')) == NULL ||
1044 StrCaseCmp(p+1, ext) != 0)
1050 while (*p && isdigit(*p))
1057 /* Setup xpm_avail */
1059 xpm_getavail(dirname, ext)
1067 for (i=0; i<MAXSQSIZE; ++i)
1070 if (appData.debugMode)
1071 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1073 dir = opendir(dirname);
1076 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1077 programName, dirname);
1081 while ((ent=readdir(dir)) != NULL) {
1082 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1083 if (i > 0 && i < MAXSQSIZE)
1093 xpm_print_avail(fp, ext)
1099 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1100 for (i=1; i<MAXSQSIZE; ++i) {
1106 /* Return XPM piecesize closest to size */
1108 xpm_closest_to(dirname, size, ext)
1114 int sm_diff = MAXSQSIZE;
1118 xpm_getavail(dirname, ext);
1120 if (appData.debugMode)
1121 xpm_print_avail(stderr, ext);
1123 for (i=1; i<MAXSQSIZE; ++i) {
1126 diff = (diff<0) ? -diff : diff;
1127 if (diff < sm_diff) {
1135 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1141 #else /* !HAVE_DIR_STRUCT */
1142 /* If we are on a system without a DIR struct, we can't
1143 read the directory, so we can't collect a list of
1144 filenames, etc., so we can't do any size-fitting. */
1146 xpm_closest_to(dirname, size, ext)
1151 fprintf(stderr, _("\
1152 Warning: No DIR structure found on this system --\n\
1153 Unable to autosize for XPM/XIM pieces.\n\
1154 Please report this error to frankm@hiwaay.net.\n\
1155 Include system type & operating system in message.\n"));
1158 #endif /* HAVE_DIR_STRUCT */
1160 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1161 "magenta", "cyan", "white" };
1165 TextColors textColors[(int)NColorClasses];
1167 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1169 parse_color(str, which)
1173 char *p, buf[100], *d;
1176 if (strlen(str) > 99) /* watch bounds on buf */
1181 for (i=0; i<which; ++i) {
1188 /* Could be looking at something like:
1190 .. in which case we want to stop on a comma also */
1191 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1195 return -1; /* Use default for empty field */
1198 if (which == 2 || isdigit(*p))
1201 while (*p && isalpha(*p))
1206 for (i=0; i<8; ++i) {
1207 if (!StrCaseCmp(buf, cnames[i]))
1208 return which? (i+40) : (i+30);
1210 if (!StrCaseCmp(buf, "default")) return -1;
1212 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1217 parse_cpair(cc, str)
1221 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1222 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1227 /* bg and attr are optional */
1228 textColors[(int)cc].bg = parse_color(str, 1);
1229 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1230 textColors[(int)cc].attr = 0;
1236 /* Arrange to catch delete-window events */
1237 Atom wm_delete_window;
1239 CatchDeleteWindow(Widget w, String procname)
1242 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1243 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1244 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1251 XtSetArg(args[0], XtNiconic, False);
1252 XtSetValues(shellWidget, args, 1);
1254 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1257 //---------------------------------------------------------------------------------------------------------
1258 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1261 #define CW_USEDEFAULT (1<<31)
1262 #define ICS_TEXT_MENU_SIZE 90
1263 #define DEBUG_FILE "xboard.debug"
1264 #define SetCurrentDirectory chdir
1265 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1269 // these two must some day move to frontend.h, when they are implemented
1270 Boolean GameListIsUp();
1272 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1275 // front-end part of option handling
1277 // [HGM] This platform-dependent table provides the location for storing the color info
1278 extern char *crWhite, * crBlack;
1282 &appData.whitePieceColor,
1283 &appData.blackPieceColor,
1284 &appData.lightSquareColor,
1285 &appData.darkSquareColor,
1286 &appData.highlightSquareColor,
1287 &appData.premoveHighlightColor,
1288 &appData.lowTimeWarningColor,
1300 ParseFont(char *name, int number)
1301 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1303 case 0: // CLOCK_FONT
1304 appData.clockFont = strdup(name);
1306 case 1: // MESSAGE_FONT
1307 appData.font = strdup(name);
1309 case 2: // COORD_FONT
1310 appData.coordFont = strdup(name);
1319 { // only 2 fonts currently
1320 appData.clockFont = CLOCK_FONT_NAME;
1321 appData.coordFont = COORD_FONT_NAME;
1322 appData.font = DEFAULT_FONT_NAME;
1327 { // no-op, until we identify the code for this already in XBoard and move it here
1331 ParseColor(int n, char *name)
1332 { // in XBoard, just copy the color-name string
1333 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1337 ParseTextAttribs(ColorClass cc, char *s)
1339 (&appData.colorShout)[cc] = strdup(s);
1343 ParseBoardSize(void *addr, char *name)
1345 appData.boardSize = strdup(name);
1350 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1354 SetCommPortDefaults()
1355 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1358 // [HGM] args: these three cases taken out to stay in front-end
1360 SaveFontArg(FILE *f, ArgDescriptor *ad)
1363 switch((int)ad->argLoc) {
1364 case 0: // CLOCK_FONT
1365 name = appData.clockFont;
1367 case 1: // MESSAGE_FONT
1368 name = appData.font;
1370 case 2: // COORD_FONT
1371 name = appData.coordFont;
1376 // Do not save fonts for now, as the saved font would be board-size specific
1377 // and not suitable for a re-start at another board size
1378 // fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, name);
1383 { // nothing to do, as the sounds are at all times represented by their text-string names already
1387 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1388 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1389 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1393 SaveColor(FILE *f, ArgDescriptor *ad)
1394 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1395 if(colorVariable[(int)ad->argLoc])
1396 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1400 SaveBoardSize(FILE *f, char *name, void *addr)
1401 { // wrapper to shield back-end from BoardSize & sizeInfo
1402 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1406 ParseCommPortSettings(char *s)
1407 { // no such option in XBoard (yet)
1410 extern Widget engineOutputShell;
1411 extern Widget tagsShell, editTagsShell;
1413 GetActualPlacement(Widget wg, WindowPlacement *wp)
1423 XtSetArg(args[i], XtNx, &x); i++;
1424 XtSetArg(args[i], XtNy, &y); i++;
1425 XtSetArg(args[i], XtNwidth, &w); i++;
1426 XtSetArg(args[i], XtNheight, &h); i++;
1427 XtGetValues(wg, args, i);
1436 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1437 // In XBoard this will have to wait until awareness of window parameters is implemented
1438 GetActualPlacement(shellWidget, &wpMain);
1439 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1440 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1441 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1442 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1443 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1444 else GetActualPlacement(editShell, &wpComment);
1445 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1446 else GetActualPlacement(editTagsShell, &wpTags);
1450 PrintCommPortSettings(FILE *f, char *name)
1451 { // This option does not exist in XBoard
1455 MySearchPath(char *installDir, char *name, char *fullname)
1456 { // just append installDir and name. Perhaps ExpandPath should be used here?
1457 name = ExpandPathName(name);
1458 if(name && name[0] == '/') strcpy(fullname, name); else {
1459 sprintf(fullname, "%s%c%s", installDir, '/', name);
1465 MyGetFullPathName(char *name, char *fullname)
1466 { // should use ExpandPath?
1467 name = ExpandPathName(name);
1468 strcpy(fullname, name);
1473 EnsureOnScreen(int *x, int *y, int minX, int minY)
1480 { // [HGM] args: allows testing if main window is realized from back-end
1481 return xBoardWindow != 0;
1485 PopUpStartupDialog()
1486 { // start menu not implemented in XBoard
1489 ConvertToLine(int argc, char **argv)
1491 static char line[128*1024], buf[1024];
1495 for(i=1; i<argc; i++) {
1496 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1497 && argv[i][0] != '{' )
1498 sprintf(buf, "{%s} ", argv[i]);
1499 else sprintf(buf, "%s ", argv[i]);
1502 line[strlen(line)-1] = NULLCHAR;
1506 //--------------------------------------------------------------------------------------------
1509 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1511 #define BoardSize int
1512 void InitDrawingSizes(BoardSize boardSize, int flags)
1513 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1514 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1516 XtGeometryResult gres;
1519 if(!formWidget) return;
1522 * Enable shell resizing.
1524 shellArgs[0].value = (XtArgVal) &w;
1525 shellArgs[1].value = (XtArgVal) &h;
1526 XtGetValues(shellWidget, shellArgs, 2);
1528 shellArgs[4].value = 2*w; shellArgs[2].value = 10;
1529 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1530 XtSetValues(shellWidget, &shellArgs[2], 4);
1532 XtSetArg(args[0], XtNdefaultDistance, &sep);
1533 XtGetValues(formWidget, args, 1);
1535 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1536 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1539 XtSetArg(args[0], XtNwidth, boardWidth);
1540 XtSetArg(args[1], XtNheight, boardHeight);
1541 XtSetValues(boardWidget, args, 2);
1543 timerWidth = (boardWidth - sep) / 2;
1544 XtSetArg(args[0], XtNwidth, timerWidth);
1545 XtSetValues(whiteTimerWidget, args, 1);
1546 XtSetValues(blackTimerWidget, args, 1);
1548 XawFormDoLayout(formWidget, False);
1550 if (appData.titleInWindow) {
1552 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1553 XtSetArg(args[i], XtNheight, &h); i++;
1554 XtGetValues(titleWidget, args, i);
1556 w = boardWidth - 2*bor;
1558 XtSetArg(args[0], XtNwidth, &w);
1559 XtGetValues(menuBarWidget, args, 1);
1560 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1563 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1564 if (gres != XtGeometryYes && appData.debugMode) {
1566 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1567 programName, gres, w, h, wr, hr);
1571 XawFormDoLayout(formWidget, True);
1574 * Inhibit shell resizing.
1576 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW;
1577 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1578 shellArgs[4].value = shellArgs[2].value = w;
1579 shellArgs[5].value = shellArgs[3].value = h;
1580 XtSetValues(shellWidget, &shellArgs[0], 6);
1582 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1585 for(i=0; i<4; i++) {
1587 for(p=0; p<=(int)WhiteKing; p++)
1588 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1589 if(gameInfo.variant == VariantShogi) {
1590 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1591 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1592 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1593 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1594 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1597 if(gameInfo.variant == VariantGothic) {
1598 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1602 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1603 for(p=0; p<=(int)WhiteKing; p++)
1604 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1605 if(gameInfo.variant == VariantShogi) {
1606 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1607 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1608 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1609 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1610 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1613 if(gameInfo.variant == VariantGothic) {
1614 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1620 for(i=0; i<2; i++) {
1622 for(p=0; p<=(int)WhiteKing; p++)
1623 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1624 if(gameInfo.variant == VariantShogi) {
1625 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1626 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1627 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1628 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1629 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1632 if(gameInfo.variant == VariantGothic) {
1633 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1644 void EscapeExpand(char *p, char *q)
1645 { // [HGM] initstring: routine to shape up string arguments
1646 while(*p++ = *q++) if(p[-1] == '\\')
1648 case 'n': p[-1] = '\n'; break;
1649 case 'r': p[-1] = '\r'; break;
1650 case 't': p[-1] = '\t'; break;
1651 case '\\': p[-1] = '\\'; break;
1652 case 0: *p = 0; return;
1653 default: p[-1] = q[-1]; break;
1662 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1663 XSetWindowAttributes window_attributes;
1665 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1666 XrmValue vFrom, vTo;
1667 XtGeometryResult gres;
1670 int forceMono = False;
1672 srandom(time(0)); // [HGM] book: make random truly random
1674 setbuf(stdout, NULL);
1675 setbuf(stderr, NULL);
1678 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1679 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1683 programName = strrchr(argv[0], '/');
1684 if (programName == NULL)
1685 programName = argv[0];
1690 XtSetLanguageProc(NULL, NULL, NULL);
1691 bindtextdomain(PACKAGE, LOCALEDIR);
1692 textdomain(PACKAGE);
1696 XtAppInitialize(&appContext, "XBoard", shellOptions,
1697 XtNumber(shellOptions),
1698 &argc, argv, xboardResources, NULL, 0);
1699 appData.boardSize = "";
1700 InitAppData(ConvertToLine(argc, argv));
1702 if (p == NULL) p = "/tmp";
1703 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1704 gameCopyFilename = (char*) malloc(i);
1705 gamePasteFilename = (char*) malloc(i);
1706 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1707 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1709 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1710 clientResources, XtNumber(clientResources),
1713 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1714 static char buf[MSG_SIZ];
1715 EscapeExpand(buf, appData.initString);
1716 appData.initString = strdup(buf);
1717 EscapeExpand(buf, appData.secondInitString);
1718 appData.secondInitString = strdup(buf);
1719 EscapeExpand(buf, appData.firstComputerString);
1720 appData.firstComputerString = strdup(buf);
1721 EscapeExpand(buf, appData.secondComputerString);
1722 appData.secondComputerString = strdup(buf);
1725 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1728 if (chdir(chessDir) != 0) {
1729 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1735 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1736 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1737 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1738 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1741 setbuf(debugFP, NULL);
1744 /* [HGM,HR] make sure board size is acceptable */
1745 if(appData.NrFiles > BOARD_FILES ||
1746 appData.NrRanks > BOARD_RANKS )
1747 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1750 /* This feature does not work; animation needs a rewrite */
1751 appData.highlightDragging = FALSE;
1755 xDisplay = XtDisplay(shellWidget);
1756 xScreen = DefaultScreen(xDisplay);
1757 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1759 gameInfo.variant = StringToVariant(appData.variant);
1760 InitPosition(FALSE);
1763 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1765 if (isdigit(appData.boardSize[0])) {
1766 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1767 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1768 &fontPxlSize, &smallLayout, &tinyLayout);
1770 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1771 programName, appData.boardSize);
1775 /* Find some defaults; use the nearest known size */
1776 SizeDefaults *szd, *nearest;
1777 int distance = 99999;
1778 nearest = szd = sizeDefaults;
1779 while (szd->name != NULL) {
1780 if (abs(szd->squareSize - squareSize) < distance) {
1782 distance = abs(szd->squareSize - squareSize);
1783 if (distance == 0) break;
1787 if (i < 2) lineGap = nearest->lineGap;
1788 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1789 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1790 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1791 if (i < 6) smallLayout = nearest->smallLayout;
1792 if (i < 7) tinyLayout = nearest->tinyLayout;
1795 SizeDefaults *szd = sizeDefaults;
1796 if (*appData.boardSize == NULLCHAR) {
1797 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1798 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1801 if (szd->name == NULL) szd--;
1802 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1804 while (szd->name != NULL &&
1805 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1806 if (szd->name == NULL) {
1807 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1808 programName, appData.boardSize);
1812 squareSize = szd->squareSize;
1813 lineGap = szd->lineGap;
1814 clockFontPxlSize = szd->clockFontPxlSize;
1815 coordFontPxlSize = szd->coordFontPxlSize;
1816 fontPxlSize = szd->fontPxlSize;
1817 smallLayout = szd->smallLayout;
1818 tinyLayout = szd->tinyLayout;
1821 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1822 if (strlen(appData.pixmapDirectory) > 0) {
1823 p = ExpandPathName(appData.pixmapDirectory);
1825 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1826 appData.pixmapDirectory);
1829 if (appData.debugMode) {
1830 fprintf(stderr, _("\
1831 XBoard square size (hint): %d\n\
1832 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1834 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1835 if (appData.debugMode) {
1836 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1840 /* [HR] height treated separately (hacked) */
1841 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1842 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1843 if (appData.showJail == 1) {
1844 /* Jail on top and bottom */
1845 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1846 XtSetArg(boardArgs[2], XtNheight,
1847 boardHeight + 2*(lineGap + squareSize));
1848 } else if (appData.showJail == 2) {
1850 XtSetArg(boardArgs[1], XtNwidth,
1851 boardWidth + 2*(lineGap + squareSize));
1852 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1855 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1856 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1860 * Determine what fonts to use.
1862 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1863 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1864 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1865 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1866 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1867 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1868 appData.font = FindFont(appData.font, fontPxlSize);
1869 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1870 countFontStruct = XQueryFont(xDisplay, countFontID);
1871 // appData.font = FindFont(appData.font, fontPxlSize);
1873 xdb = XtDatabase(xDisplay);
1874 XrmPutStringResource(&xdb, "*font", appData.font);
1877 * Detect if there are not enough colors available and adapt.
1879 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1880 appData.monoMode = True;
1883 if (!appData.monoMode) {
1884 vFrom.addr = (caddr_t) appData.lightSquareColor;
1885 vFrom.size = strlen(appData.lightSquareColor);
1886 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1887 if (vTo.addr == NULL) {
1888 appData.monoMode = True;
1891 lightSquareColor = *(Pixel *) vTo.addr;
1894 if (!appData.monoMode) {
1895 vFrom.addr = (caddr_t) appData.darkSquareColor;
1896 vFrom.size = strlen(appData.darkSquareColor);
1897 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1898 if (vTo.addr == NULL) {
1899 appData.monoMode = True;
1902 darkSquareColor = *(Pixel *) vTo.addr;
1905 if (!appData.monoMode) {
1906 vFrom.addr = (caddr_t) appData.whitePieceColor;
1907 vFrom.size = strlen(appData.whitePieceColor);
1908 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1909 if (vTo.addr == NULL) {
1910 appData.monoMode = True;
1913 whitePieceColor = *(Pixel *) vTo.addr;
1916 if (!appData.monoMode) {
1917 vFrom.addr = (caddr_t) appData.blackPieceColor;
1918 vFrom.size = strlen(appData.blackPieceColor);
1919 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1920 if (vTo.addr == NULL) {
1921 appData.monoMode = True;
1924 blackPieceColor = *(Pixel *) vTo.addr;
1928 if (!appData.monoMode) {
1929 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1930 vFrom.size = strlen(appData.highlightSquareColor);
1931 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1932 if (vTo.addr == NULL) {
1933 appData.monoMode = True;
1936 highlightSquareColor = *(Pixel *) vTo.addr;
1940 if (!appData.monoMode) {
1941 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1942 vFrom.size = strlen(appData.premoveHighlightColor);
1943 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1944 if (vTo.addr == NULL) {
1945 appData.monoMode = True;
1948 premoveHighlightColor = *(Pixel *) vTo.addr;
1953 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1956 if (appData.bitmapDirectory == NULL ||
1957 appData.bitmapDirectory[0] == NULLCHAR)
1958 appData.bitmapDirectory = DEF_BITMAP_DIR;
1961 if (appData.lowTimeWarning && !appData.monoMode) {
1962 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
1963 vFrom.size = strlen(appData.lowTimeWarningColor);
1964 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1965 if (vTo.addr == NULL)
1966 appData.monoMode = True;
1968 lowTimeWarningColor = *(Pixel *) vTo.addr;
1971 if (appData.monoMode && appData.debugMode) {
1972 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1973 (unsigned long) XWhitePixel(xDisplay, xScreen),
1974 (unsigned long) XBlackPixel(xDisplay, xScreen));
1977 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1978 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1979 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1980 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1981 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1982 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1983 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1984 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1985 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1986 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1988 if (appData.colorize) {
1990 _("%s: can't parse color names; disabling colorization\n"),
1993 appData.colorize = FALSE;
1995 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
1996 textColors[ColorNone].attr = 0;
1998 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2004 layoutName = "tinyLayout";
2005 } else if (smallLayout) {
2006 layoutName = "smallLayout";
2008 layoutName = "normalLayout";
2010 /* Outer layoutWidget is there only to provide a name for use in
2011 resources that depend on the layout style */
2013 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2014 layoutArgs, XtNumber(layoutArgs));
2016 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2017 formArgs, XtNumber(formArgs));
2018 XtSetArg(args[0], XtNdefaultDistance, &sep);
2019 XtGetValues(formWidget, args, 1);
2022 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2023 XtSetArg(args[0], XtNtop, XtChainTop);
2024 XtSetArg(args[1], XtNbottom, XtChainTop);
2025 XtSetArg(args[2], XtNright, XtChainLeft);
2026 XtSetValues(menuBarWidget, args, 3);
2028 widgetList[j++] = whiteTimerWidget =
2029 XtCreateWidget("whiteTime", labelWidgetClass,
2030 formWidget, timerArgs, XtNumber(timerArgs));
2031 XtSetArg(args[0], XtNfont, clockFontStruct);
2032 XtSetArg(args[1], XtNtop, XtChainTop);
2033 XtSetArg(args[2], XtNbottom, XtChainTop);
2034 XtSetValues(whiteTimerWidget, args, 3);
2036 widgetList[j++] = blackTimerWidget =
2037 XtCreateWidget("blackTime", labelWidgetClass,
2038 formWidget, timerArgs, XtNumber(timerArgs));
2039 XtSetArg(args[0], XtNfont, clockFontStruct);
2040 XtSetArg(args[1], XtNtop, XtChainTop);
2041 XtSetArg(args[2], XtNbottom, XtChainTop);
2042 XtSetValues(blackTimerWidget, args, 3);
2044 if (appData.titleInWindow) {
2045 widgetList[j++] = titleWidget =
2046 XtCreateWidget("title", labelWidgetClass, formWidget,
2047 titleArgs, XtNumber(titleArgs));
2048 XtSetArg(args[0], XtNtop, XtChainTop);
2049 XtSetArg(args[1], XtNbottom, XtChainTop);
2050 XtSetValues(titleWidget, args, 2);
2053 if (appData.showButtonBar) {
2054 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2055 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2056 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2057 XtSetArg(args[2], XtNtop, XtChainTop);
2058 XtSetArg(args[3], XtNbottom, XtChainTop);
2059 XtSetValues(buttonBarWidget, args, 4);
2062 widgetList[j++] = messageWidget =
2063 XtCreateWidget("message", labelWidgetClass, formWidget,
2064 messageArgs, XtNumber(messageArgs));
2065 XtSetArg(args[0], XtNtop, XtChainTop);
2066 XtSetArg(args[1], XtNbottom, XtChainTop);
2067 XtSetValues(messageWidget, args, 2);
2069 widgetList[j++] = boardWidget =
2070 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2071 XtNumber(boardArgs));
2073 XtManageChildren(widgetList, j);
2075 timerWidth = (boardWidth - sep) / 2;
2076 XtSetArg(args[0], XtNwidth, timerWidth);
2077 XtSetValues(whiteTimerWidget, args, 1);
2078 XtSetValues(blackTimerWidget, args, 1);
2080 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2081 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2082 XtGetValues(whiteTimerWidget, args, 2);
2084 if (appData.showButtonBar) {
2085 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2086 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2087 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2091 * formWidget uses these constraints but they are stored
2095 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2096 XtSetValues(menuBarWidget, args, i);
2097 if (appData.titleInWindow) {
2100 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2101 XtSetValues(whiteTimerWidget, args, i);
2103 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2104 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2105 XtSetValues(blackTimerWidget, args, i);
2107 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2108 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2109 XtSetValues(titleWidget, args, i);
2111 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2112 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2113 XtSetValues(messageWidget, args, i);
2114 if (appData.showButtonBar) {
2116 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2117 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2118 XtSetValues(buttonBarWidget, args, i);
2122 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2123 XtSetValues(whiteTimerWidget, args, i);
2125 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2126 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2127 XtSetValues(blackTimerWidget, args, i);
2129 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2130 XtSetValues(titleWidget, args, i);
2132 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2133 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2134 XtSetValues(messageWidget, args, i);
2135 if (appData.showButtonBar) {
2137 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2138 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2139 XtSetValues(buttonBarWidget, args, i);
2144 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2145 XtSetValues(whiteTimerWidget, args, i);
2147 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2148 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2149 XtSetValues(blackTimerWidget, args, i);
2151 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2152 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2153 XtSetValues(messageWidget, args, i);
2154 if (appData.showButtonBar) {
2156 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2157 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2158 XtSetValues(buttonBarWidget, args, i);
2162 XtSetArg(args[0], XtNfromVert, messageWidget);
2163 XtSetArg(args[1], XtNtop, XtChainTop);
2164 XtSetArg(args[2], XtNbottom, XtChainBottom);
2165 XtSetArg(args[3], XtNleft, XtChainLeft);
2166 XtSetArg(args[4], XtNright, XtChainRight);
2167 XtSetValues(boardWidget, args, 5);
2169 XtRealizeWidget(shellWidget);
2172 XtSetArg(args[0], XtNx, wpMain.x);
2173 XtSetArg(args[1], XtNy, wpMain.y);
2174 XtSetValues(shellWidget, args, 2);
2178 * Correct the width of the message and title widgets.
2179 * It is not known why some systems need the extra fudge term.
2180 * The value "2" is probably larger than needed.
2182 XawFormDoLayout(formWidget, False);
2184 #define WIDTH_FUDGE 2
2186 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2187 XtSetArg(args[i], XtNheight, &h); i++;
2188 XtGetValues(messageWidget, args, i);
2189 if (appData.showButtonBar) {
2191 XtSetArg(args[i], XtNwidth, &w); i++;
2192 XtGetValues(buttonBarWidget, args, i);
2193 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2195 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2198 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2199 if (gres != XtGeometryYes && appData.debugMode) {
2200 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2201 programName, gres, w, h, wr, hr);
2204 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2205 /* The size used for the child widget in layout lags one resize behind
2206 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2208 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2209 if (gres != XtGeometryYes && appData.debugMode) {
2210 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2211 programName, gres, w, h, wr, hr);
2214 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2215 XtSetArg(args[1], XtNright, XtChainRight);
2216 XtSetValues(messageWidget, args, 2);
2218 if (appData.titleInWindow) {
2220 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2221 XtSetArg(args[i], XtNheight, &h); i++;
2222 XtGetValues(titleWidget, args, i);
2224 w = boardWidth - 2*bor;
2226 XtSetArg(args[0], XtNwidth, &w);
2227 XtGetValues(menuBarWidget, args, 1);
2228 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2231 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2232 if (gres != XtGeometryYes && appData.debugMode) {
2234 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2235 programName, gres, w, h, wr, hr);
2238 XawFormDoLayout(formWidget, True);
2240 xBoardWindow = XtWindow(boardWidget);
2242 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2243 // not need to go into InitDrawingSizes().
2247 * Create X checkmark bitmap and initialize option menu checks.
2249 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2250 checkmark_bits, checkmark_width, checkmark_height);
2251 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2252 if (appData.alwaysPromoteToQueen) {
2253 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2256 if (appData.animateDragging) {
2257 XtSetValues(XtNameToWidget(menuBarWidget,
2258 "menuOptions.Animate Dragging"),
2261 if (appData.animate) {
2262 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2265 if (appData.autoComment) {
2266 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2269 if (appData.autoCallFlag) {
2270 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2273 if (appData.autoFlipView) {
2274 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2277 if (appData.autoObserve) {
2278 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2281 if (appData.autoRaiseBoard) {
2282 XtSetValues(XtNameToWidget(menuBarWidget,
2283 "menuOptions.Auto Raise Board"), args, 1);
2285 if (appData.autoSaveGames) {
2286 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2289 if (appData.saveGameFile[0] != NULLCHAR) {
2290 /* Can't turn this off from menu */
2291 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2293 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2297 if (appData.blindfold) {
2298 XtSetValues(XtNameToWidget(menuBarWidget,
2299 "menuOptions.Blindfold"), args, 1);
2301 if (appData.flashCount > 0) {
2302 XtSetValues(XtNameToWidget(menuBarWidget,
2303 "menuOptions.Flash Moves"),
2306 if (appData.getMoveList) {
2307 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2311 if (appData.highlightDragging) {
2312 XtSetValues(XtNameToWidget(menuBarWidget,
2313 "menuOptions.Highlight Dragging"),
2317 if (appData.highlightLastMove) {
2318 XtSetValues(XtNameToWidget(menuBarWidget,
2319 "menuOptions.Highlight Last Move"),
2322 if (appData.icsAlarm) {
2323 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2326 if (appData.ringBellAfterMoves) {
2327 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2330 if (appData.oldSaveStyle) {
2331 XtSetValues(XtNameToWidget(menuBarWidget,
2332 "menuOptions.Old Save Style"), args, 1);
2334 if (appData.periodicUpdates) {
2335 XtSetValues(XtNameToWidget(menuBarWidget,
2336 "menuOptions.Periodic Updates"), args, 1);
2338 if (appData.ponderNextMove) {
2339 XtSetValues(XtNameToWidget(menuBarWidget,
2340 "menuOptions.Ponder Next Move"), args, 1);
2342 if (appData.popupExitMessage) {
2343 XtSetValues(XtNameToWidget(menuBarWidget,
2344 "menuOptions.Popup Exit Message"), args, 1);
2346 if (appData.popupMoveErrors) {
2347 XtSetValues(XtNameToWidget(menuBarWidget,
2348 "menuOptions.Popup Move Errors"), args, 1);
2350 if (appData.premove) {
2351 XtSetValues(XtNameToWidget(menuBarWidget,
2352 "menuOptions.Premove"), args, 1);
2354 if (appData.quietPlay) {
2355 XtSetValues(XtNameToWidget(menuBarWidget,
2356 "menuOptions.Quiet Play"), args, 1);
2358 if (appData.showCoords) {
2359 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2362 if (appData.hideThinkingFromHuman) {
2363 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2366 if (appData.testLegality) {
2367 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2370 if (saveSettingsOnExit) {
2371 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2378 ReadBitmap(&wIconPixmap, "icon_white.bm",
2379 icon_white_bits, icon_white_width, icon_white_height);
2380 ReadBitmap(&bIconPixmap, "icon_black.bm",
2381 icon_black_bits, icon_black_width, icon_black_height);
2382 iconPixmap = wIconPixmap;
2384 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2385 XtSetValues(shellWidget, args, i);
2388 * Create a cursor for the board widget.
2390 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2391 XChangeWindowAttributes(xDisplay, xBoardWindow,
2392 CWCursor, &window_attributes);
2395 * Inhibit shell resizing.
2397 shellArgs[0].value = (XtArgVal) &w;
2398 shellArgs[1].value = (XtArgVal) &h;
2399 XtGetValues(shellWidget, shellArgs, 2);
2400 shellArgs[4].value = shellArgs[2].value = w;
2401 shellArgs[5].value = shellArgs[3].value = h;
2402 XtSetValues(shellWidget, &shellArgs[2], 4);
2403 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2404 marginH = h - boardHeight;
2406 CatchDeleteWindow(shellWidget, "QuitProc");
2411 if (appData.bitmapDirectory[0] != NULLCHAR) {
2418 /* Create regular pieces */
2419 if (!useImages) CreatePieces();
2424 if (appData.animate || appData.animateDragging)
2427 XtAugmentTranslations(formWidget,
2428 XtParseTranslationTable(globalTranslations));
2429 XtAugmentTranslations(boardWidget,
2430 XtParseTranslationTable(boardTranslations));
2431 XtAugmentTranslations(whiteTimerWidget,
2432 XtParseTranslationTable(whiteTranslations));
2433 XtAugmentTranslations(blackTimerWidget,
2434 XtParseTranslationTable(blackTranslations));
2436 /* Why is the following needed on some versions of X instead
2437 * of a translation? */
2438 XtAddEventHandler(boardWidget, ExposureMask, False,
2439 (XtEventHandler) EventProc, NULL);
2442 /* [AS] Restore layout */
2443 if( wpMoveHistory.visible ) {
2447 if( wpEvalGraph.visible )
2452 if( wpEngineOutput.visible ) {
2453 EngineOutputPopUp();
2458 if (errorExitStatus == -1) {
2459 if (appData.icsActive) {
2460 /* We now wait until we see "login:" from the ICS before
2461 sending the logon script (problems with timestamp otherwise) */
2462 /*ICSInitScript();*/
2463 if (appData.icsInputBox) ICSInputBoxPopUp();
2467 signal(SIGWINCH, TermSizeSigHandler);
2469 signal(SIGINT, IntSigHandler);
2470 signal(SIGTERM, IntSigHandler);
2471 if (*appData.cmailGameName != NULLCHAR) {
2472 signal(SIGUSR1, CmailSigHandler);
2475 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2478 XtAppMainLoop(appContext);
2479 if (appData.debugMode) fclose(debugFP); // [DM] debug
2486 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2487 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2489 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2490 unlink(gameCopyFilename);
2491 unlink(gamePasteFilename);
2494 RETSIGTYPE TermSizeSigHandler(int sig)
2507 CmailSigHandler(sig)
2513 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2515 /* Activate call-back function CmailSigHandlerCallBack() */
2516 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2518 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2522 CmailSigHandlerCallBack(isr, closure, message, count, error)
2530 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2532 /**** end signal code ****/
2542 f = fopen(appData.icsLogon, "r");
2548 strcat(buf, appData.icsLogon);
2549 f = fopen(buf, "r");
2553 ProcessICSInitScript(f);
2560 EditCommentPopDown();
2575 if (!menuBarWidget) return;
2576 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2578 DisplayError("menuStep.Revert", 0);
2580 XtSetSensitive(w, !grey);
2585 SetMenuEnables(enab)
2589 if (!menuBarWidget) return;
2590 while (enab->name != NULL) {
2591 w = XtNameToWidget(menuBarWidget, enab->name);
2593 DisplayError(enab->name, 0);
2595 XtSetSensitive(w, enab->value);
2601 Enables icsEnables[] = {
2602 { "menuFile.Mail Move", False },
2603 { "menuFile.Reload CMail Message", False },
2604 { "menuMode.Machine Black", False },
2605 { "menuMode.Machine White", False },
2606 { "menuMode.Analysis Mode", False },
2607 { "menuMode.Analyze File", False },
2608 { "menuMode.Two Machines", False },
2610 { "menuHelp.Hint", False },
2611 { "menuHelp.Book", False },
2612 { "menuStep.Move Now", False },
2613 { "menuOptions.Periodic Updates", False },
2614 { "menuOptions.Hide Thinking", False },
2615 { "menuOptions.Ponder Next Move", False },
2620 Enables ncpEnables[] = {
2621 { "menuFile.Mail Move", False },
2622 { "menuFile.Reload CMail Message", False },
2623 { "menuMode.Machine White", False },
2624 { "menuMode.Machine Black", False },
2625 { "menuMode.Analysis Mode", False },
2626 { "menuMode.Analyze File", False },
2627 { "menuMode.Two Machines", False },
2628 { "menuMode.ICS Client", False },
2629 { "menuMode.ICS Input Box", False },
2630 { "Action", False },
2631 { "menuStep.Revert", False },
2632 { "menuStep.Move Now", False },
2633 { "menuStep.Retract Move", False },
2634 { "menuOptions.Auto Comment", False },
2635 { "menuOptions.Auto Flag", False },
2636 { "menuOptions.Auto Flip View", False },
2637 { "menuOptions.Auto Observe", False },
2638 { "menuOptions.Auto Raise Board", False },
2639 { "menuOptions.Get Move List", False },
2640 { "menuOptions.ICS Alarm", False },
2641 { "menuOptions.Move Sound", False },
2642 { "menuOptions.Quiet Play", False },
2643 { "menuOptions.Hide Thinking", False },
2644 { "menuOptions.Periodic Updates", False },
2645 { "menuOptions.Ponder Next Move", False },
2646 { "menuHelp.Hint", False },
2647 { "menuHelp.Book", False },
2651 Enables gnuEnables[] = {
2652 { "menuMode.ICS Client", False },
2653 { "menuMode.ICS Input Box", False },
2654 { "menuAction.Accept", False },
2655 { "menuAction.Decline", False },
2656 { "menuAction.Rematch", False },
2657 { "menuAction.Adjourn", False },
2658 { "menuAction.Stop Examining", False },
2659 { "menuAction.Stop Observing", False },
2660 { "menuStep.Revert", False },
2661 { "menuOptions.Auto Comment", False },
2662 { "menuOptions.Auto Observe", False },
2663 { "menuOptions.Auto Raise Board", False },
2664 { "menuOptions.Get Move List", False },
2665 { "menuOptions.Premove", False },
2666 { "menuOptions.Quiet Play", False },
2668 /* The next two options rely on SetCmailMode being called *after* */
2669 /* SetGNUMode so that when GNU is being used to give hints these */
2670 /* menu options are still available */
2672 { "menuFile.Mail Move", False },
2673 { "menuFile.Reload CMail Message", False },
2677 Enables cmailEnables[] = {
2679 { "menuAction.Call Flag", False },
2680 { "menuAction.Draw", True },
2681 { "menuAction.Adjourn", False },
2682 { "menuAction.Abort", False },
2683 { "menuAction.Stop Observing", False },
2684 { "menuAction.Stop Examining", False },
2685 { "menuFile.Mail Move", True },
2686 { "menuFile.Reload CMail Message", True },
2690 Enables trainingOnEnables[] = {
2691 { "menuMode.Edit Comment", False },
2692 { "menuMode.Pause", False },
2693 { "menuStep.Forward", False },
2694 { "menuStep.Backward", False },
2695 { "menuStep.Forward to End", False },
2696 { "menuStep.Back to Start", False },
2697 { "menuStep.Move Now", False },
2698 { "menuStep.Truncate Game", False },
2702 Enables trainingOffEnables[] = {
2703 { "menuMode.Edit Comment", True },
2704 { "menuMode.Pause", True },
2705 { "menuStep.Forward", True },
2706 { "menuStep.Backward", True },
2707 { "menuStep.Forward to End", True },
2708 { "menuStep.Back to Start", True },
2709 { "menuStep.Move Now", True },
2710 { "menuStep.Truncate Game", True },
2714 Enables machineThinkingEnables[] = {
2715 { "menuFile.Load Game", False },
2716 { "menuFile.Load Next Game", False },
2717 { "menuFile.Load Previous Game", False },
2718 { "menuFile.Reload Same Game", False },
2719 { "menuFile.Paste Game", False },
2720 { "menuFile.Load Position", False },
2721 { "menuFile.Load Next Position", False },
2722 { "menuFile.Load Previous Position", False },
2723 { "menuFile.Reload Same Position", False },
2724 { "menuFile.Paste Position", False },
2725 { "menuMode.Machine White", False },
2726 { "menuMode.Machine Black", False },
2727 { "menuMode.Two Machines", False },
2728 { "menuStep.Retract Move", False },
2732 Enables userThinkingEnables[] = {
2733 { "menuFile.Load Game", True },
2734 { "menuFile.Load Next Game", True },
2735 { "menuFile.Load Previous Game", True },
2736 { "menuFile.Reload Same Game", True },
2737 { "menuFile.Paste Game", True },
2738 { "menuFile.Load Position", True },
2739 { "menuFile.Load Next Position", True },
2740 { "menuFile.Load Previous Position", True },
2741 { "menuFile.Reload Same Position", True },
2742 { "menuFile.Paste Position", True },
2743 { "menuMode.Machine White", True },
2744 { "menuMode.Machine Black", True },
2745 { "menuMode.Two Machines", True },
2746 { "menuStep.Retract Move", True },
2752 SetMenuEnables(icsEnables);
2755 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2756 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2763 SetMenuEnables(ncpEnables);
2769 SetMenuEnables(gnuEnables);
2775 SetMenuEnables(cmailEnables);
2781 SetMenuEnables(trainingOnEnables);
2782 if (appData.showButtonBar) {
2783 XtSetSensitive(buttonBarWidget, False);
2789 SetTrainingModeOff()
2791 SetMenuEnables(trainingOffEnables);
2792 if (appData.showButtonBar) {
2793 XtSetSensitive(buttonBarWidget, True);
2798 SetUserThinkingEnables()
2800 if (appData.noChessProgram) return;
2801 SetMenuEnables(userThinkingEnables);
2805 SetMachineThinkingEnables()
2807 if (appData.noChessProgram) return;
2808 SetMenuEnables(machineThinkingEnables);
2810 case MachinePlaysBlack:
2811 case MachinePlaysWhite:
2812 case TwoMachinesPlay:
2813 XtSetSensitive(XtNameToWidget(menuBarWidget,
2814 ModeToWidgetName(gameMode)), True);
2821 #define Abs(n) ((n)<0 ? -(n) : (n))
2824 * Find a font that matches "pattern" that is as close as
2825 * possible to the targetPxlSize. Prefer fonts that are k
2826 * pixels smaller to fonts that are k pixels larger. The
2827 * pattern must be in the X Consortium standard format,
2828 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2829 * The return value should be freed with XtFree when no
2832 char *FindFont(pattern, targetPxlSize)
2836 char **fonts, *p, *best, *scalable, *scalableTail;
2837 int i, j, nfonts, minerr, err, pxlSize;
2840 char **missing_list;
2842 char *def_string, *base_fnt_lst, strInt[3];
2844 XFontStruct **fnt_list;
2846 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2847 sprintf(strInt, "%d", targetPxlSize);
2848 p = strstr(pattern, "--");
2849 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2850 strcat(base_fnt_lst, strInt);
2851 strcat(base_fnt_lst, strchr(p + 2, '-'));
2853 if ((fntSet = XCreateFontSet(xDisplay,
2857 &def_string)) == NULL) {
2859 fprintf(stderr, _("Unable to create font set.\n"));
2863 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2865 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2867 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2868 programName, pattern);
2876 for (i=0; i<nfonts; i++) {
2879 if (*p != '-') continue;
2881 if (*p == NULLCHAR) break;
2882 if (*p++ == '-') j++;
2884 if (j < 7) continue;
2887 scalable = fonts[i];
2890 err = pxlSize - targetPxlSize;
2891 if (Abs(err) < Abs(minerr) ||
2892 (minerr > 0 && err < 0 && -err == minerr)) {
2898 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
2899 /* If the error is too big and there is a scalable font,
2900 use the scalable font. */
2901 int headlen = scalableTail - scalable;
2902 p = (char *) XtMalloc(strlen(scalable) + 10);
2903 while (isdigit(*scalableTail)) scalableTail++;
2904 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
2906 p = (char *) XtMalloc(strlen(best) + 1);
2909 if (appData.debugMode) {
2910 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
2911 pattern, targetPxlSize, p);
2914 if (missing_count > 0)
2915 XFreeStringList(missing_list);
2916 XFreeFontSet(xDisplay, fntSet);
2918 XFreeFontNames(fonts);
2925 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
2926 | GCBackground | GCFunction | GCPlaneMask;
2927 XGCValues gc_values;
2930 gc_values.plane_mask = AllPlanes;
2931 gc_values.line_width = lineGap;
2932 gc_values.line_style = LineSolid;
2933 gc_values.function = GXcopy;
2935 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2936 gc_values.background = XBlackPixel(xDisplay, xScreen);
2937 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2939 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2940 gc_values.background = XWhitePixel(xDisplay, xScreen);
2941 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
2942 XSetFont(xDisplay, coordGC, coordFontID);
2944 // [HGM] make font for holdings counts (white on black0
2945 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2946 gc_values.background = XBlackPixel(xDisplay, xScreen);
2947 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
2948 XSetFont(xDisplay, countGC, countFontID);
2950 if (appData.monoMode) {
2951 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2952 gc_values.background = XWhitePixel(xDisplay, xScreen);
2953 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2955 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2956 gc_values.background = XBlackPixel(xDisplay, xScreen);
2957 lightSquareGC = wbPieceGC
2958 = XtGetGC(shellWidget, value_mask, &gc_values);
2960 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2961 gc_values.background = XWhitePixel(xDisplay, xScreen);
2962 darkSquareGC = bwPieceGC
2963 = XtGetGC(shellWidget, value_mask, &gc_values);
2965 if (DefaultDepth(xDisplay, xScreen) == 1) {
2966 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
2967 gc_values.function = GXcopyInverted;
2968 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
2969 gc_values.function = GXcopy;
2970 if (XBlackPixel(xDisplay, xScreen) == 1) {
2971 bwPieceGC = darkSquareGC;
2972 wbPieceGC = copyInvertedGC;
2974 bwPieceGC = copyInvertedGC;
2975 wbPieceGC = lightSquareGC;
2979 gc_values.foreground = highlightSquareColor;
2980 gc_values.background = highlightSquareColor;
2981 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2983 gc_values.foreground = premoveHighlightColor;
2984 gc_values.background = premoveHighlightColor;
2985 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2987 gc_values.foreground = lightSquareColor;
2988 gc_values.background = darkSquareColor;
2989 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2991 gc_values.foreground = darkSquareColor;
2992 gc_values.background = lightSquareColor;
2993 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2995 gc_values.foreground = jailSquareColor;
2996 gc_values.background = jailSquareColor;
2997 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2999 gc_values.foreground = whitePieceColor;
3000 gc_values.background = darkSquareColor;
3001 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3003 gc_values.foreground = whitePieceColor;
3004 gc_values.background = lightSquareColor;
3005 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3007 gc_values.foreground = whitePieceColor;
3008 gc_values.background = jailSquareColor;
3009 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3011 gc_values.foreground = blackPieceColor;
3012 gc_values.background = darkSquareColor;
3013 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3015 gc_values.foreground = blackPieceColor;
3016 gc_values.background = lightSquareColor;
3017 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3019 gc_values.foreground = blackPieceColor;
3020 gc_values.background = jailSquareColor;
3021 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3025 void loadXIM(xim, xmask, filename, dest, mask)
3038 fp = fopen(filename, "rb");
3040 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3047 for (y=0; y<h; ++y) {
3048 for (x=0; x<h; ++x) {
3053 XPutPixel(xim, x, y, blackPieceColor);
3055 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3058 XPutPixel(xim, x, y, darkSquareColor);
3060 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3063 XPutPixel(xim, x, y, whitePieceColor);
3065 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3068 XPutPixel(xim, x, y, lightSquareColor);
3070 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3076 /* create Pixmap of piece */
3077 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3079 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3082 /* create Pixmap of clipmask
3083 Note: We assume the white/black pieces have the same
3084 outline, so we make only 6 masks. This is okay
3085 since the XPM clipmask routines do the same. */
3087 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3089 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3092 /* now create the 1-bit version */
3093 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3096 values.foreground = 1;
3097 values.background = 0;
3099 /* Don't use XtGetGC, not read only */
3100 maskGC = XCreateGC(xDisplay, *mask,
3101 GCForeground | GCBackground, &values);
3102 XCopyPlane(xDisplay, temp, *mask, maskGC,
3103 0, 0, squareSize, squareSize, 0, 0, 1);
3104 XFreePixmap(xDisplay, temp);
3109 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3111 void CreateXIMPieces()
3116 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3121 /* The XSynchronize calls were copied from CreatePieces.
3122 Not sure if needed, but can't hurt */
3123 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3126 /* temp needed by loadXIM() */
3127 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3128 0, 0, ss, ss, AllPlanes, XYPixmap);
3130 if (strlen(appData.pixmapDirectory) == 0) {
3134 if (appData.monoMode) {
3135 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3139 fprintf(stderr, _("\nLoading XIMs...\n"));
3141 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3142 fprintf(stderr, "%d", piece+1);
3143 for (kind=0; kind<4; kind++) {
3144 fprintf(stderr, ".");
3145 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3146 ExpandPathName(appData.pixmapDirectory),
3147 piece <= (int) WhiteKing ? "" : "w",
3148 pieceBitmapNames[piece],
3150 ximPieceBitmap[kind][piece] =
3151 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3152 0, 0, ss, ss, AllPlanes, XYPixmap);
3153 if (appData.debugMode)
3154 fprintf(stderr, _("(File:%s:) "), buf);
3155 loadXIM(ximPieceBitmap[kind][piece],
3157 &(xpmPieceBitmap2[kind][piece]),
3158 &(ximMaskPm2[piece]));
3159 if(piece <= (int)WhiteKing)
3160 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3162 fprintf(stderr," ");
3164 /* Load light and dark squares */
3165 /* If the LSQ and DSQ pieces don't exist, we will
3166 draw them with solid squares. */
3167 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3168 if (access(buf, 0) != 0) {
3172 fprintf(stderr, _("light square "));
3174 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3175 0, 0, ss, ss, AllPlanes, XYPixmap);
3176 if (appData.debugMode)
3177 fprintf(stderr, _("(File:%s:) "), buf);
3179 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3180 fprintf(stderr, _("dark square "));
3181 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3182 ExpandPathName(appData.pixmapDirectory), ss);
3183 if (appData.debugMode)
3184 fprintf(stderr, _("(File:%s:) "), buf);
3186 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3187 0, 0, ss, ss, AllPlanes, XYPixmap);
3188 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3189 xpmJailSquare = xpmLightSquare;
3191 fprintf(stderr, _("Done.\n"));
3193 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3197 void CreateXPMPieces()
3201 u_int ss = squareSize;
3203 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3204 XpmColorSymbol symbols[4];
3206 /* The XSynchronize calls were copied from CreatePieces.
3207 Not sure if needed, but can't hurt */
3208 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3210 /* Setup translations so piece colors match square colors */
3211 symbols[0].name = "light_piece";
3212 symbols[0].value = appData.whitePieceColor;
3213 symbols[1].name = "dark_piece";
3214 symbols[1].value = appData.blackPieceColor;
3215 symbols[2].name = "light_square";
3216 symbols[2].value = appData.lightSquareColor;
3217 symbols[3].name = "dark_square";
3218 symbols[3].value = appData.darkSquareColor;
3220 attr.valuemask = XpmColorSymbols;
3221 attr.colorsymbols = symbols;
3222 attr.numsymbols = 4;
3224 if (appData.monoMode) {
3225 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3229 if (strlen(appData.pixmapDirectory) == 0) {
3230 XpmPieces* pieces = builtInXpms;
3233 while (pieces->size != squareSize && pieces->size) pieces++;
3234 if (!pieces->size) {
3235 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3238 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3239 for (kind=0; kind<4; kind++) {
3241 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3242 pieces->xpm[piece][kind],
3243 &(xpmPieceBitmap2[kind][piece]),
3244 NULL, &attr)) != 0) {
3245 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3249 if(piece <= (int) WhiteKing)
3250 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3254 xpmJailSquare = xpmLightSquare;
3258 fprintf(stderr, _("\nLoading XPMs...\n"));
3261 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3262 fprintf(stderr, "%d ", piece+1);
3263 for (kind=0; kind<4; kind++) {
3264 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3265 ExpandPathName(appData.pixmapDirectory),
3266 piece > (int) WhiteKing ? "w" : "",
3267 pieceBitmapNames[piece],
3269 if (appData.debugMode) {
3270 fprintf(stderr, _("(File:%s:) "), buf);
3272 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3273 &(xpmPieceBitmap2[kind][piece]),
3274 NULL, &attr)) != 0) {
3275 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3276 // [HGM] missing: read of unorthodox piece failed; substitute King.
3277 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3278 ExpandPathName(appData.pixmapDirectory),
3280 if (appData.debugMode) {
3281 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3283 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3284 &(xpmPieceBitmap2[kind][piece]),
3288 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3293 if(piece <= (int) WhiteKing)
3294 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3297 /* Load light and dark squares */
3298 /* If the LSQ and DSQ pieces don't exist, we will
3299 draw them with solid squares. */
3300 fprintf(stderr, _("light square "));
3301 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3302 if (access(buf, 0) != 0) {
3306 if (appData.debugMode)
3307 fprintf(stderr, _("(File:%s:) "), buf);
3309 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3310 &xpmLightSquare, NULL, &attr)) != 0) {
3311 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3314 fprintf(stderr, _("dark square "));
3315 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3316 ExpandPathName(appData.pixmapDirectory), ss);
3317 if (appData.debugMode) {
3318 fprintf(stderr, _("(File:%s:) "), buf);
3320 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3321 &xpmDarkSquare, NULL, &attr)) != 0) {
3322 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3326 xpmJailSquare = xpmLightSquare;
3327 fprintf(stderr, _("Done.\n"));
3329 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3332 #endif /* HAVE_LIBXPM */
3335 /* No built-in bitmaps */
3340 u_int ss = squareSize;
3342 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3345 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3346 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3347 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3348 pieceBitmapNames[piece],
3349 ss, kind == SOLID ? 's' : 'o');
3350 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3351 if(piece <= (int)WhiteKing)
3352 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3356 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3360 /* With built-in bitmaps */
3363 BuiltInBits* bib = builtInBits;
3366 u_int ss = squareSize;
3368 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3371 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3373 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3374 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3375 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3376 pieceBitmapNames[piece],
3377 ss, kind == SOLID ? 's' : 'o');
3378 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3379 bib->bits[kind][piece], ss, ss);
3380 if(piece <= (int)WhiteKing)
3381 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3385 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3390 void ReadBitmap(pm, name, bits, wreq, hreq)
3393 unsigned char bits[];
3399 char msg[MSG_SIZ], fullname[MSG_SIZ];
3401 if (*appData.bitmapDirectory != NULLCHAR) {
3402 strcpy(fullname, appData.bitmapDirectory);
3403 strcat(fullname, "/");
3404 strcat(fullname, name);
3405 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3406 &w, &h, pm, &x_hot, &y_hot);
3407 fprintf(stderr, "load %s\n", name);
3408 if (errcode != BitmapSuccess) {
3410 case BitmapOpenFailed:
3411 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3413 case BitmapFileInvalid:
3414 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3416 case BitmapNoMemory:
3417 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3421 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3425 fprintf(stderr, _("%s: %s...using built-in\n"),
3427 } else if (w != wreq || h != hreq) {
3429 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3430 programName, fullname, w, h, wreq, hreq);
3436 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3445 if (lineGap == 0) return;
3447 /* [HR] Split this into 2 loops for non-square boards. */
3449 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3450 gridSegments[i].x1 = 0;
3451 gridSegments[i].x2 =
3452 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3453 gridSegments[i].y1 = gridSegments[i].y2
3454 = lineGap / 2 + (i * (squareSize + lineGap));
3457 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3458 gridSegments[j + i].y1 = 0;
3459 gridSegments[j + i].y2 =
3460 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3461 gridSegments[j + i].x1 = gridSegments[j + i].x2
3462 = lineGap / 2 + (j * (squareSize + lineGap));
3466 static void MenuBarSelect(w, addr, index)
3471 XtActionProc proc = (XtActionProc) addr;
3473 (proc)(NULL, NULL, NULL, NULL);
3476 void CreateMenuBarPopup(parent, name, mb)
3486 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3489 XtSetArg(args[j], XtNleftMargin, 20); j++;
3490 XtSetArg(args[j], XtNrightMargin, 20); j++;
3492 while (mi->string != NULL) {
3493 if (strcmp(mi->string, "----") == 0) {
3494 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3497 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3498 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3500 XtAddCallback(entry, XtNcallback,
3501 (XtCallbackProc) MenuBarSelect,
3502 (caddr_t) mi->proc);
3508 Widget CreateMenuBar(mb)
3512 Widget anchor, menuBar;
3514 char menuName[MSG_SIZ];
3517 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3518 XtSetArg(args[j], XtNvSpace, 0); j++;
3519 XtSetArg(args[j], XtNborderWidth, 0); j++;
3520 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3521 formWidget, args, j);
3523 while (mb->name != NULL) {
3524 strcpy(menuName, "menu");
3525 strcat(menuName, mb->name);
3527 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3530 shortName[0] = _(mb->name)[0];
3531 shortName[1] = NULLCHAR;
3532 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3535 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3538 XtSetArg(args[j], XtNborderWidth, 0); j++;
3539 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3541 CreateMenuBarPopup(menuBar, menuName, mb);
3547 Widget CreateButtonBar(mi)
3551 Widget button, buttonBar;
3555 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3557 XtSetArg(args[j], XtNhSpace, 0); j++;
3559 XtSetArg(args[j], XtNborderWidth, 0); j++;
3560 XtSetArg(args[j], XtNvSpace, 0); j++;
3561 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3562 formWidget, args, j);
3564 while (mi->string != NULL) {
3567 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3568 XtSetArg(args[j], XtNborderWidth, 0); j++;
3570 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3571 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3572 buttonBar, args, j);
3573 XtAddCallback(button, XtNcallback,
3574 (XtCallbackProc) MenuBarSelect,
3575 (caddr_t) mi->proc);
3582 CreatePieceMenu(name, color)
3589 ChessSquare selection;
3591 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3592 boardWidget, args, 0);
3594 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3595 String item = pieceMenuStrings[color][i];
3597 if (strcmp(item, "----") == 0) {
3598 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3601 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3602 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3604 selection = pieceMenuTranslation[color][i];
3605 XtAddCallback(entry, XtNcallback,
3606 (XtCallbackProc) PieceMenuSelect,
3607 (caddr_t) selection);
3608 if (selection == WhitePawn || selection == BlackPawn) {
3609 XtSetArg(args[0], XtNpopupOnEntry, entry);
3610 XtSetValues(menu, args, 1);
3623 ChessSquare selection;
3625 whitePieceMenu = CreatePieceMenu("menuW", 0);
3626 blackPieceMenu = CreatePieceMenu("menuB", 1);
3628 XtRegisterGrabAction(PieceMenuPopup, True,
3629 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3630 GrabModeAsync, GrabModeAsync);
3632 XtSetArg(args[0], XtNlabel, _("Drop"));
3633 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3634 boardWidget, args, 1);
3635 for (i = 0; i < DROP_MENU_SIZE; i++) {
3636 String item = dropMenuStrings[i];
3638 if (strcmp(item, "----") == 0) {
3639 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3642 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3643 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3645 selection = dropMenuTranslation[i];
3646 XtAddCallback(entry, XtNcallback,
3647 (XtCallbackProc) DropMenuSelect,
3648 (caddr_t) selection);
3653 void SetupDropMenu()
3661 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3662 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3663 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3664 dmEnables[i].piece);
3665 XtSetSensitive(entry, p != NULL || !appData.testLegality
3666 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3667 && !appData.icsActive));
3669 while (p && *p++ == dmEnables[i].piece) count++;
3670 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3672 XtSetArg(args[j], XtNlabel, label); j++;
3673 XtSetValues(entry, args, j);
3677 void PieceMenuPopup(w, event, params, num_params)
3681 Cardinal *num_params;
3685 if (event->type == ButtonRelease) UnLoadPV(); // [HGM] pv
3686 if (event->type != ButtonPress) return;
3687 if (errorUp) ErrorPopDown();
3691 whichMenu = params[0];
3694 if(!appData.icsEngineAnalyze) return;
3695 case IcsPlayingWhite:
3696 case IcsPlayingBlack:
3697 if(!appData.zippyPlay) goto noZip;
3700 case MachinePlaysWhite:
3701 case MachinePlaysBlack:
3702 case TwoMachinesPlay: // [HGM] pv: use for showing PV
3703 if (!appData.dropMenu) {
3704 LoadPV(event->xbutton.x, event->xbutton.y);
3707 if(gameMode == TwoMachinesPlay || gameMode == AnalyzeMode ||
3708 gameMode == AnalyzeFile || gameMode == IcsObserving) return;
3711 if (!appData.dropMenu || appData.testLegality &&
3712 gameInfo.variant != VariantBughouse &&
3713 gameInfo.variant != VariantCrazyhouse) return;
3715 whichMenu = "menuD";
3721 if (((pmFromX = EventToSquare(event->xbutton.x, BOARD_WIDTH)) < 0) ||
3722 ((pmFromY = EventToSquare(event->xbutton.y, BOARD_HEIGHT)) < 0)) {
3723 pmFromX = pmFromY = -1;
3727 pmFromX = BOARD_WIDTH - 1 - pmFromX;
3729 pmFromY = BOARD_HEIGHT - 1 - pmFromY;
3731 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3734 static void PieceMenuSelect(w, piece, junk)
3739 if (pmFromX < 0 || pmFromY < 0) return;
3740 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3743 static void DropMenuSelect(w, piece, junk)
3748 if (pmFromX < 0 || pmFromY < 0) return;
3749 DropMenuEvent(piece, pmFromX, pmFromY);
3752 void WhiteClock(w, event, prms, nprms)
3758 if (gameMode == EditPosition || gameMode == IcsExamining) {
3759 SetWhiteToPlayEvent();
3760 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3765 void BlackClock(w, event, prms, nprms)
3771 if (gameMode == EditPosition || gameMode == IcsExamining) {
3772 SetBlackToPlayEvent();
3773 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3780 * If the user selects on a border boundary, return -1; if off the board,
3781 * return -2. Otherwise map the event coordinate to the square.
3783 int EventToSquare(x, limit)
3791 if ((x % (squareSize + lineGap)) >= squareSize)
3793 x /= (squareSize + lineGap);
3799 static void do_flash_delay(msec)
3805 static void drawHighlight(file, rank, gc)
3811 if (lineGap == 0 || appData.blindfold) return;
3814 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3815 (squareSize + lineGap);
3816 y = lineGap/2 + rank * (squareSize + lineGap);
3818 x = lineGap/2 + file * (squareSize + lineGap);
3819 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3820 (squareSize + lineGap);
3823 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3824 squareSize+lineGap, squareSize+lineGap);
3827 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3828 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3831 SetHighlights(fromX, fromY, toX, toY)
3832 int fromX, fromY, toX, toY;
3834 if (hi1X != fromX || hi1Y != fromY) {
3835 if (hi1X >= 0 && hi1Y >= 0) {
3836 drawHighlight(hi1X, hi1Y, lineGC);
3838 if (fromX >= 0 && fromY >= 0) {
3839 drawHighlight(fromX, fromY, highlineGC);
3842 if (hi2X != toX || hi2Y != toY) {
3843 if (hi2X >= 0 && hi2Y >= 0) {
3844 drawHighlight(hi2X, hi2Y, lineGC);
3846 if (toX >= 0 && toY >= 0) {
3847 drawHighlight(toX, toY, highlineGC);
3859 SetHighlights(-1, -1, -1, -1);
3864 SetPremoveHighlights(fromX, fromY, toX, toY)
3865 int fromX, fromY, toX, toY;
3867 if (pm1X != fromX || pm1Y != fromY) {
3868 if (pm1X >= 0 && pm1Y >= 0) {
3869 drawHighlight(pm1X, pm1Y, lineGC);
3871 if (fromX >= 0 && fromY >= 0) {
3872 drawHighlight(fromX, fromY, prelineGC);
3875 if (pm2X != toX || pm2Y != toY) {
3876 if (pm2X >= 0 && pm2Y >= 0) {
3877 drawHighlight(pm2X, pm2Y, lineGC);
3879 if (toX >= 0 && toY >= 0) {
3880 drawHighlight(toX, toY, prelineGC);
3890 ClearPremoveHighlights()
3892 SetPremoveHighlights(-1, -1, -1, -1);
3895 static void BlankSquare(x, y, color, piece, dest)
3900 if (useImages && useImageSqs) {
3904 pm = xpmLightSquare;
3909 case 2: /* neutral */
3914 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
3915 squareSize, squareSize, x, y);
3925 case 2: /* neutral */
3930 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
3935 I split out the routines to draw a piece so that I could
3936 make a generic flash routine.
3938 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
3940 int square_color, x, y;
3943 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3944 switch (square_color) {
3946 case 2: /* neutral */
3948 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3949 ? *pieceToOutline(piece)
3950 : *pieceToSolid(piece),
3951 dest, bwPieceGC, 0, 0,
3952 squareSize, squareSize, x, y);
3955 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3956 ? *pieceToSolid(piece)
3957 : *pieceToOutline(piece),
3958 dest, wbPieceGC, 0, 0,
3959 squareSize, squareSize, x, y);
3964 static void monoDrawPiece(piece, square_color, x, y, dest)
3966 int square_color, x, y;
3969 switch (square_color) {
3971 case 2: /* neutral */
3973 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3974 ? *pieceToOutline(piece)
3975 : *pieceToSolid(piece),
3976 dest, bwPieceGC, 0, 0,
3977 squareSize, squareSize, x, y, 1);
3980 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3981 ? *pieceToSolid(piece)
3982 : *pieceToOutline(piece),
3983 dest, wbPieceGC, 0, 0,
3984 squareSize, squareSize, x, y, 1);
3989 static void colorDrawPiece(piece, square_color, x, y, dest)
3991 int square_color, x, y;
3994 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
3995 switch (square_color) {
3997 XCopyPlane(xDisplay, *pieceToSolid(piece),
3998 dest, (int) piece < (int) BlackPawn
3999 ? wlPieceGC : blPieceGC, 0, 0,
4000 squareSize, squareSize, x, y, 1);
4003 XCopyPlane(xDisplay, *pieceToSolid(piece),
4004 dest, (int) piece < (int) BlackPawn
4005 ? wdPieceGC : bdPieceGC, 0, 0,
4006 squareSize, squareSize, x, y, 1);
4008 case 2: /* neutral */
4010 XCopyPlane(xDisplay, *pieceToSolid(piece),
4011 dest, (int) piece < (int) BlackPawn
4012 ? wjPieceGC : bjPieceGC, 0, 0,
4013 squareSize, squareSize, x, y, 1);
4018 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4020 int square_color, x, y;
4025 switch (square_color) {
4027 case 2: /* neutral */
4029 if ((int)piece < (int) BlackPawn) {
4037 if ((int)piece < (int) BlackPawn) {
4045 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4046 dest, wlPieceGC, 0, 0,
4047 squareSize, squareSize, x, y);
4050 typedef void (*DrawFunc)();
4052 DrawFunc ChooseDrawFunc()
4054 if (appData.monoMode) {
4055 if (DefaultDepth(xDisplay, xScreen) == 1) {
4056 return monoDrawPiece_1bit;
4058 return monoDrawPiece;
4062 return colorDrawPieceImage;
4064 return colorDrawPiece;
4068 /* [HR] determine square color depending on chess variant. */
4069 static int SquareColor(row, column)
4074 if (gameInfo.variant == VariantXiangqi) {
4075 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4077 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4079 } else if (row <= 4) {
4085 square_color = ((column + row) % 2) == 1;
4088 /* [hgm] holdings: next line makes all holdings squares light */
4089 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4091 return square_color;
4094 void DrawSquare(row, column, piece, do_flash)
4095 int row, column, do_flash;
4098 int square_color, x, y, direction, font_ascent, font_descent;
4101 XCharStruct overall;
4105 /* Calculate delay in milliseconds (2-delays per complete flash) */
4106 flash_delay = 500 / appData.flashRate;
4109 x = lineGap + ((BOARD_WIDTH-1)-column) *
4110 (squareSize + lineGap);
4111 y = lineGap + row * (squareSize + lineGap);
4113 x = lineGap + column * (squareSize + lineGap);
4114 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4115 (squareSize + lineGap);
4118 square_color = SquareColor(row, column);
4120 if ( // [HGM] holdings: blank out area between board and holdings
4121 column == BOARD_LEFT-1 || column == BOARD_RGHT
4122 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4123 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4124 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4126 // [HGM] print piece counts next to holdings
4127 string[1] = NULLCHAR;
4128 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4129 string[0] = '0' + piece;
4130 XTextExtents(countFontStruct, string, 1, &direction,
4131 &font_ascent, &font_descent, &overall);
4132 if (appData.monoMode) {
4133 XDrawImageString(xDisplay, xBoardWindow, countGC,
4134 x + squareSize - overall.width - 2,
4135 y + font_ascent + 1, string, 1);
4137 XDrawString(xDisplay, xBoardWindow, countGC,
4138 x + squareSize - overall.width - 2,
4139 y + font_ascent + 1, string, 1);
4142 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4143 string[0] = '0' + piece;
4144 XTextExtents(countFontStruct, string, 1, &direction,
4145 &font_ascent, &font_descent, &overall);
4146 if (appData.monoMode) {
4147 XDrawImageString(xDisplay, xBoardWindow, countGC,
4148 x + 2, y + font_ascent + 1, string, 1);
4150 XDrawString(xDisplay, xBoardWindow, countGC,
4151 x + 2, y + font_ascent + 1, string, 1);
4155 if (piece == EmptySquare || appData.blindfold) {
4156 BlankSquare(x, y, square_color, piece, xBoardWindow);
4158 drawfunc = ChooseDrawFunc();
4159 if (do_flash && appData.flashCount > 0) {
4160 for (i=0; i<appData.flashCount; ++i) {
4162 drawfunc(piece, square_color, x, y, xBoardWindow);
4163 XSync(xDisplay, False);
4164 do_flash_delay(flash_delay);
4166 BlankSquare(x, y, square_color, piece, xBoardWindow);
4167 XSync(xDisplay, False);
4168 do_flash_delay(flash_delay);
4171 drawfunc(piece, square_color, x, y, xBoardWindow);
4175 string[1] = NULLCHAR;
4176 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4177 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4178 string[0] = 'a' + column - BOARD_LEFT;
4179 XTextExtents(coordFontStruct, string, 1, &direction,
4180 &font_ascent, &font_descent, &overall);
4181 if (appData.monoMode) {
4182 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4183 x + squareSize - overall.width - 2,
4184 y + squareSize - font_descent - 1, string, 1);
4186 XDrawString(xDisplay, xBoardWindow, coordGC,
4187 x + squareSize - overall.width - 2,
4188 y + squareSize - font_descent - 1, string, 1);
4191 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4192 string[0] = ONE + row;
4193 XTextExtents(coordFontStruct, string, 1, &direction,
4194 &font_ascent, &font_descent, &overall);
4195 if (appData.monoMode) {
4196 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4197 x + 2, y + font_ascent + 1, string, 1);
4199 XDrawString(xDisplay, xBoardWindow, coordGC,
4200 x + 2, y + font_ascent + 1, string, 1);
4203 if(marker[row][column]) {
4204 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4205 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4210 /* Why is this needed on some versions of X? */
4211 void EventProc(widget, unused, event)
4216 if (!XtIsRealized(widget))
4219 switch (event->type) {
4221 if (event->xexpose.count > 0) return; /* no clipping is done */
4222 XDrawPosition(widget, True, NULL);
4230 void DrawPosition(fullRedraw, board)
4231 /*Boolean*/int fullRedraw;
4234 XDrawPosition(boardWidget, fullRedraw, board);
4237 /* Returns 1 if there are "too many" differences between b1 and b2
4238 (i.e. more than 1 move was made) */
4239 static int too_many_diffs(b1, b2)
4245 for (i=0; i<BOARD_HEIGHT; ++i) {
4246 for (j=0; j<BOARD_WIDTH; ++j) {
4247 if (b1[i][j] != b2[i][j]) {
4248 if (++c > 4) /* Castling causes 4 diffs */
4257 /* Matrix describing castling maneuvers */
4258 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4259 static int castling_matrix[4][5] = {
4260 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4261 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4262 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4263 { 7, 7, 4, 5, 6 } /* 0-0, black */
4266 /* Checks whether castling occurred. If it did, *rrow and *rcol
4267 are set to the destination (row,col) of the rook that moved.
4269 Returns 1 if castling occurred, 0 if not.
4271 Note: Only handles a max of 1 castling move, so be sure
4272 to call too_many_diffs() first.
4274 static int check_castle_draw(newb, oldb, rrow, rcol)
4281 /* For each type of castling... */
4282 for (i=0; i<4; ++i) {
4283 r = castling_matrix[i];
4285 /* Check the 4 squares involved in the castling move */
4287 for (j=1; j<=4; ++j) {
4288 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4295 /* All 4 changed, so it must be a castling move */
4304 static int damage[BOARD_RANKS][BOARD_FILES];
4307 * event handler for redrawing the board
4309 void XDrawPosition(w, repaint, board)
4311 /*Boolean*/int repaint;
4315 static int lastFlipView = 0;
4316 static int lastBoardValid = 0;
4317 static Board lastBoard;
4321 if (board == NULL) {
4322 if (!lastBoardValid) return;
4325 if (!lastBoardValid || lastFlipView != flipView) {
4326 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4327 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4332 * It would be simpler to clear the window with XClearWindow()
4333 * but this causes a very distracting flicker.
4336 if (!repaint && lastBoardValid && lastFlipView == flipView) {
4338 /* If too much changes (begin observing new game, etc.), don't
4340 do_flash = too_many_diffs(board, lastBoard) ? 0 : 1;
4342 /* Special check for castling so we don't flash both the king
4343 and the rook (just flash the king). */
4345 if (check_castle_draw(board, lastBoard, &rrow, &rcol)) {
4346 /* Draw rook with NO flashing. King will be drawn flashing later */
4347 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4348 lastBoard[rrow][rcol] = board[rrow][rcol];
4352 /* First pass -- Draw (newly) empty squares and repair damage.
4353 This prevents you from having a piece show up twice while it
4354 is flashing on its new square */
4355 for (i = 0; i < BOARD_HEIGHT; i++)
4356 for (j = 0; j < BOARD_WIDTH; j++)
4357 if ((board[i][j] != lastBoard[i][j] && board[i][j] == EmptySquare)
4359 DrawSquare(i, j, board[i][j], 0);
4360 damage[i][j] = False;
4363 /* Second pass -- Draw piece(s) in new position and flash them */
4364 for (i = 0; i < BOARD_HEIGHT; i++)
4365 for (j = 0; j < BOARD_WIDTH; j++)
4366 if (board[i][j] != lastBoard[i][j]) {
4367 DrawSquare(i, j, board[i][j], do_flash);
4371 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4372 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4374 for (i = 0; i < BOARD_HEIGHT; i++)
4375 for (j = 0; j < BOARD_WIDTH; j++) {
4376 DrawSquare(i, j, board[i][j], 0);
4377 damage[i][j] = False;
4381 CopyBoard(lastBoard, board);
4383 lastFlipView = flipView;
4385 /* Draw highlights */
4386 if (pm1X >= 0 && pm1Y >= 0) {
4387 drawHighlight(pm1X, pm1Y, prelineGC);
4389 if (pm2X >= 0 && pm2Y >= 0) {
4390 drawHighlight(pm2X, pm2Y, prelineGC);
4392 if (hi1X >= 0 && hi1Y >= 0) {
4393 drawHighlight(hi1X, hi1Y, highlineGC);
4395 if (hi2X >= 0 && hi2Y >= 0) {
4396 drawHighlight(hi2X, hi2Y, highlineGC);
4399 /* If piece being dragged around board, must redraw that too */
4402 XSync(xDisplay, False);
4407 * event handler for redrawing the board
4409 void DrawPositionProc(w, event, prms, nprms)
4415 XDrawPosition(w, True, NULL);
4420 * event handler for parsing user moves
4422 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4423 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4424 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4425 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4426 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4427 // and at the end FinishMove() to perform the move after optional promotion popups.
4428 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4429 void HandleUserMove(w, event, prms, nprms)
4435 if (w != boardWidget || errorExitStatus != -1) return;
4438 if (event->type == ButtonPress) {
4439 XtPopdown(promotionShell);
4440 XtDestroyWidget(promotionShell);
4441 promotionUp = False;
4449 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4450 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4451 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4454 void AnimateUserMove (Widget w, XEvent * event,
4455 String * params, Cardinal * nParams)
4457 DragPieceMove(event->xmotion.x, event->xmotion.y);
4460 void HandlePV (Widget w, XEvent * event,
4461 String * params, Cardinal * nParams)
4462 { // [HGM] pv: walk PV
4463 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4466 Widget CommentCreate(name, text, mutable, callback, lines)
4468 int /*Boolean*/ mutable;
4469 XtCallbackProc callback;
4473 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4478 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4479 XtGetValues(boardWidget, args, j);
4482 XtSetArg(args[j], XtNresizable, True); j++;
4485 XtCreatePopupShell(name, topLevelShellWidgetClass,
4486 shellWidget, args, j);
4489 XtCreatePopupShell(name, transientShellWidgetClass,
4490 shellWidget, args, j);
4493 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4494 layoutArgs, XtNumber(layoutArgs));
4496 XtCreateManagedWidget("form", formWidgetClass, layout,
4497 formArgs, XtNumber(formArgs));
4501 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4502 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4504 XtSetArg(args[j], XtNstring, text); j++;
4505 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4506 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4507 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4508 XtSetArg(args[j], XtNright, XtChainRight); j++;
4509 XtSetArg(args[j], XtNresizable, True); j++;
4510 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4511 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4512 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4513 XtSetArg(args[j], XtNautoFill, True); j++;
4514 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4516 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4520 XtSetArg(args[j], XtNfromVert, edit); j++;
4521 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4522 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4523 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4524 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4526 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4527 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4530 XtSetArg(args[j], XtNfromVert, edit); j++;
4531 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4532 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4533 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4534 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4535 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4537 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4538 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4541 XtSetArg(args[j], XtNfromVert, edit); j++;
4542 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4543 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4544 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4545 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4546 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4548 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4549 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4552 XtSetArg(args[j], XtNfromVert, edit); j++;
4553 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4554 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4555 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4556 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4558 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4559 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4562 XtSetArg(args[j], XtNfromVert, edit); j++;
4563 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4564 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4565 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4566 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4567 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4569 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4570 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4573 XtRealizeWidget(shell);
4575 if (commentX == -1) {
4578 Dimension pw_height;
4579 Dimension ew_height;
4582 XtSetArg(args[j], XtNheight, &ew_height); j++;
4583 XtGetValues(edit, args, j);
4586 XtSetArg(args[j], XtNheight, &pw_height); j++;
4587 XtGetValues(shell, args, j);
4588 commentH = pw_height + (lines - 1) * ew_height;
4589 commentW = bw_width - 16;
4591 XSync(xDisplay, False);
4593 /* This code seems to tickle an X bug if it is executed too soon
4594 after xboard starts up. The coordinates get transformed as if
4595 the main window was positioned at (0, 0).
4597 XtTranslateCoords(shellWidget,
4598 (bw_width - commentW) / 2, 0 - commentH / 2,
4599 &commentX, &commentY);
4601 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4602 RootWindowOfScreen(XtScreen(shellWidget)),
4603 (bw_width - commentW) / 2, 0 - commentH / 2,
4608 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4611 if(wpComment.width > 0) {
4612 commentX = wpComment.x;
4613 commentY = wpComment.y;
4614 commentW = wpComment.width;
4615 commentH = wpComment.height;
4619 XtSetArg(args[j], XtNheight, commentH); j++;
4620 XtSetArg(args[j], XtNwidth, commentW); j++;
4621 XtSetArg(args[j], XtNx, commentX); j++;
4622 XtSetArg(args[j], XtNy, commentY); j++;
4623 XtSetValues(shell, args, j);
4624 XtSetKeyboardFocus(shell, edit);
4629 /* Used for analysis window and ICS input window */
4630 Widget MiscCreate(name, text, mutable, callback, lines)
4632 int /*Boolean*/ mutable;
4633 XtCallbackProc callback;
4637 Widget shell, layout, form, edit;
4639 Dimension bw_width, pw_height, ew_height, w, h;
4645 XtSetArg(args[j], XtNresizable, True); j++;
4648 XtCreatePopupShell(name, topLevelShellWidgetClass,
4649 shellWidget, args, j);
4652 XtCreatePopupShell(name, transientShellWidgetClass,
4653 shellWidget, args, j);
4656 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4657 layoutArgs, XtNumber(layoutArgs));
4659 XtCreateManagedWidget("form", formWidgetClass, layout,
4660 formArgs, XtNumber(formArgs));
4664 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4665 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4667 XtSetArg(args[j], XtNstring, text); j++;
4668 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4669 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4670 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4671 XtSetArg(args[j], XtNright, XtChainRight); j++;
4672 XtSetArg(args[j], XtNresizable, True); j++;
4673 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4674 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4675 XtSetArg(args[j], XtNautoFill, True); j++;
4676 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4678 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4680 XtRealizeWidget(shell);
4683 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4684 XtGetValues(boardWidget, args, j);
4687 XtSetArg(args[j], XtNheight, &ew_height); j++;
4688 XtGetValues(edit, args, j);
4691 XtSetArg(args[j], XtNheight, &pw_height); j++;
4692 XtGetValues(shell, args, j);
4693 h = pw_height + (lines - 1) * ew_height;
4696 XSync(xDisplay, False);
4698 /* This code seems to tickle an X bug if it is executed too soon
4699 after xboard starts up. The coordinates get transformed as if
4700 the main window was positioned at (0, 0).
4702 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4704 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4705 RootWindowOfScreen(XtScreen(shellWidget)),
4706 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4710 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4713 XtSetArg(args[j], XtNheight, h); j++;
4714 XtSetArg(args[j], XtNwidth, w); j++;
4715 XtSetArg(args[j], XtNx, x); j++;
4716 XtSetArg(args[j], XtNy, y); j++;
4717 XtSetValues(shell, args, j);
4723 static int savedIndex; /* gross that this is global */
4725 void EditCommentPopUp(index, title, text)
4734 if (text == NULL) text = "";
4736 if (editShell == NULL) {
4738 CommentCreate(title, text, True, EditCommentCallback, 4);
4739 XtRealizeWidget(editShell);
4740 CatchDeleteWindow(editShell, "EditCommentPopDown");
4742 edit = XtNameToWidget(editShell, "*form.text");
4744 XtSetArg(args[j], XtNstring, text); j++;
4745 XtSetValues(edit, args, j);
4747 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4748 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4749 XtSetValues(editShell, args, j);
4752 XtPopup(editShell, XtGrabNone);
4756 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4757 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4761 void EditCommentCallback(w, client_data, call_data)
4763 XtPointer client_data, call_data;
4771 XtSetArg(args[j], XtNlabel, &name); j++;
4772 XtGetValues(w, args, j);
4774 if (strcmp(name, _("ok")) == 0) {
4775 edit = XtNameToWidget(editShell, "*form.text");
4777 XtSetArg(args[j], XtNstring, &val); j++;
4778 XtGetValues(edit, args, j);
4779 ReplaceComment(savedIndex, val);
4780 EditCommentPopDown();
4781 } else if (strcmp(name, _("cancel")) == 0) {
4782 EditCommentPopDown();
4783 } else if (strcmp(name, _("clear")) == 0) {
4784 edit = XtNameToWidget(editShell, "*form.text");
4785 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4786 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4790 void EditCommentPopDown()
4795 if (!editUp) return;
4797 XtSetArg(args[j], XtNx, &commentX); j++;
4798 XtSetArg(args[j], XtNy, &commentY); j++;
4799 XtSetArg(args[j], XtNheight, &commentH); j++;
4800 XtSetArg(args[j], XtNwidth, &commentW); j++;
4801 XtGetValues(editShell, args, j);
4802 XtPopdown(editShell);
4805 XtSetArg(args[j], XtNleftBitmap, None); j++;
4806 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4810 void ICSInputBoxPopUp()
4815 char *title = _("ICS Input");
4818 if (ICSInputShell == NULL) {
4819 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
4820 tr = XtParseTranslationTable(ICSInputTranslations);
4821 edit = XtNameToWidget(ICSInputShell, "*form.text");
4822 XtOverrideTranslations(edit, tr);
4823 XtRealizeWidget(ICSInputShell);
4824 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
4827 edit = XtNameToWidget(ICSInputShell, "*form.text");
4829 XtSetArg(args[j], XtNstring, ""); j++;
4830 XtSetValues(edit, args, j);
4832 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4833 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4834 XtSetValues(ICSInputShell, args, j);
4837 XtPopup(ICSInputShell, XtGrabNone);
4838 XtSetKeyboardFocus(ICSInputShell, edit);
4840 ICSInputBoxUp = True;
4842 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4843 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4847 void ICSInputSendText()
4854 edit = XtNameToWidget(ICSInputShell, "*form.text");
4856 XtSetArg(args[j], XtNstring, &val); j++;
4857 XtGetValues(edit, args, j);
4858 SendMultiLineToICS(val);
4859 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4860 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4863 void ICSInputBoxPopDown()
4868 if (!ICSInputBoxUp) return;
4870 XtPopdown(ICSInputShell);
4871 ICSInputBoxUp = False;
4873 XtSetArg(args[j], XtNleftBitmap, None); j++;
4874 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4878 void CommentPopUp(title, text)
4885 if (commentShell == NULL) {
4887 CommentCreate(title, text, False, CommentCallback, 4);
4888 XtRealizeWidget(commentShell);
4889 CatchDeleteWindow(commentShell, "CommentPopDown");
4891 edit = XtNameToWidget(commentShell, "*form.text");
4893 XtSetArg(args[j], XtNstring, text); j++;
4894 XtSetValues(edit, args, j);
4896 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4897 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4898 XtSetValues(commentShell, args, j);
4901 XtPopup(commentShell, XtGrabNone);
4902 XSync(xDisplay, False);
4907 void CommentCallback(w, client_data, call_data)
4909 XtPointer client_data, call_data;
4916 XtSetArg(args[j], XtNlabel, &name); j++;
4917 XtGetValues(w, args, j);
4919 if (strcmp(name, _("close")) == 0) {
4921 } else if (strcmp(name, _("edit")) == 0) {
4928 void CommentPopDown()
4933 if (!commentUp) return;
4935 XtSetArg(args[j], XtNx, &commentX); j++;
4936 XtSetArg(args[j], XtNy, &commentY); j++;
4937 XtSetArg(args[j], XtNwidth, &commentW); j++;
4938 XtSetArg(args[j], XtNheight, &commentH); j++;
4939 XtGetValues(commentShell, args, j);
4940 XtPopdown(commentShell);
4941 XSync(xDisplay, False);
4945 void FileNamePopUp(label, def, proc, openMode)
4952 Widget popup, layout, dialog, edit;
4958 fileProc = proc; /* I can't see a way not */
4959 fileOpenMode = openMode; /* to use globals here */
4962 XtSetArg(args[i], XtNresizable, True); i++;
4963 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
4964 XtSetArg(args[i], XtNtitle, XtNewString(_("File name prompt"))); i++;
4965 fileNameShell = popup =
4966 XtCreatePopupShell("File name prompt", transientShellWidgetClass,
4967 shellWidget, args, i);
4970 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
4971 layoutArgs, XtNumber(layoutArgs));
4974 XtSetArg(args[i], XtNlabel, label); i++;
4975 XtSetArg(args[i], XtNvalue, def); i++;
4976 XtSetArg(args[i], XtNborderWidth, 0); i++;
4977 dialog = XtCreateManagedWidget("fileName", dialogWidgetClass,
4980 XawDialogAddButton(dialog, _("ok"), FileNameCallback, (XtPointer) dialog);
4981 XawDialogAddButton(dialog, _("cancel"), FileNameCallback,
4982 (XtPointer) dialog);
4984 XtRealizeWidget(popup);
4985 CatchDeleteWindow(popup, "FileNamePopDown");
4987 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
4988 &x, &y, &win_x, &win_y, &mask);
4990 XtSetArg(args[0], XtNx, x - 10);
4991 XtSetArg(args[1], XtNy, y - 30);
4992 XtSetValues(popup, args, 2);
4994 XtPopup(popup, XtGrabExclusive);
4997 edit = XtNameToWidget(dialog, "*value");
4998 XtSetKeyboardFocus(popup, edit);
5001 void FileNamePopDown()
5003 if (!filenameUp) return;
5004 XtPopdown(fileNameShell);
5005 XtDestroyWidget(fileNameShell);
5010 void FileNameCallback(w, client_data, call_data)
5012 XtPointer client_data, call_data;
5017 XtSetArg(args[0], XtNlabel, &name);
5018 XtGetValues(w, args, 1);
5020 if (strcmp(name, _("cancel")) == 0) {
5025 FileNameAction(w, NULL, NULL, NULL);
5028 void FileNameAction(w, event, prms, nprms)
5040 name = XawDialogGetValueString(w = XtParent(w));
5042 if ((name != NULL) && (*name != NULLCHAR)) {
5044 XtPopdown(w = XtParent(XtParent(w)));
5048 p = strrchr(buf, ' ');
5055 fullname = ExpandPathName(buf);
5057 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5060 f = fopen(fullname, fileOpenMode);
5062 DisplayError(_("Failed to open file"), errno);
5064 (void) (*fileProc)(f, index, buf);
5071 XtPopdown(w = XtParent(XtParent(w)));
5077 void PromotionPopUp()
5080 Widget dialog, layout;
5082 Dimension bw_width, pw_width;
5086 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5087 XtGetValues(boardWidget, args, j);
5090 XtSetArg(args[j], XtNresizable, True); j++;
5091 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5093 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5094 shellWidget, args, j);
5096 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5097 layoutArgs, XtNumber(layoutArgs));
5100 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5101 XtSetArg(args[j], XtNborderWidth, 0); j++;
5102 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5105 if(gameInfo.variant != VariantShogi) {
5106 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5107 (XtPointer) dialog);
5108 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5109 (XtPointer) dialog);
5110 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5111 (XtPointer) dialog);
5112 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5113 (XtPointer) dialog);
5114 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5115 gameInfo.variant == VariantGiveaway) {
5116 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5117 (XtPointer) dialog);
5119 if(gameInfo.variant == VariantCapablanca ||
5120 gameInfo.variant == VariantGothic ||
5121 gameInfo.variant == VariantCapaRandom) {
5122 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5123 (XtPointer) dialog);
5124 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5125 (XtPointer) dialog);
5127 } else // [HGM] shogi
5129 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5130 (XtPointer) dialog);
5131 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5132 (XtPointer) dialog);
5134 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5135 (XtPointer) dialog);
5137 XtRealizeWidget(promotionShell);
5138 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5141 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5142 XtGetValues(promotionShell, args, j);
5144 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5145 lineGap + squareSize/3 +
5146 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5147 0 : 6*(squareSize + lineGap)), &x, &y);
5150 XtSetArg(args[j], XtNx, x); j++;
5151 XtSetArg(args[j], XtNy, y); j++;
5152 XtSetValues(promotionShell, args, j);
5154 XtPopup(promotionShell, XtGrabNone);
5159 void PromotionPopDown()
5161 if (!promotionUp) return;
5162 XtPopdown(promotionShell);
5163 XtDestroyWidget(promotionShell);
5164 promotionUp = False;
5167 void PromotionCallback(w, client_data, call_data)
5169 XtPointer client_data, call_data;
5175 XtSetArg(args[0], XtNlabel, &name);
5176 XtGetValues(w, args, 1);
5180 if (fromX == -1) return;
5182 if (strcmp(name, _("cancel")) == 0) {
5186 } else if (strcmp(name, _("Knight")) == 0) {
5188 } else if (strcmp(name, _("Promote")) == 0) {
5190 } else if (strcmp(name, _("Defer")) == 0) {
5193 promoChar = ToLower(name[0]);
5196 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5198 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5199 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5204 void ErrorCallback(w, client_data, call_data)
5206 XtPointer client_data, call_data;
5209 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5211 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5217 if (!errorUp) return;
5219 XtPopdown(errorShell);
5220 XtDestroyWidget(errorShell);
5221 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5224 void ErrorPopUp(title, label, modal)
5225 char *title, *label;
5229 Widget dialog, layout;
5233 Dimension bw_width, pw_width;
5234 Dimension pw_height;
5238 XtSetArg(args[i], XtNresizable, True); i++;
5239 XtSetArg(args[i], XtNtitle, title); i++;
5241 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5242 shellWidget, args, i);
5244 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5245 layoutArgs, XtNumber(layoutArgs));
5248 XtSetArg(args[i], XtNlabel, label); i++;
5249 XtSetArg(args[i], XtNborderWidth, 0); i++;
5250 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5253 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5255 XtRealizeWidget(errorShell);
5256 CatchDeleteWindow(errorShell, "ErrorPopDown");
5259 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5260 XtGetValues(boardWidget, args, i);
5262 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5263 XtSetArg(args[i], XtNheight, &pw_height); i++;
5264 XtGetValues(errorShell, args, i);
5267 /* This code seems to tickle an X bug if it is executed too soon
5268 after xboard starts up. The coordinates get transformed as if
5269 the main window was positioned at (0, 0).
5271 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5272 0 - pw_height + squareSize / 3, &x, &y);
5274 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5275 RootWindowOfScreen(XtScreen(boardWidget)),
5276 (bw_width - pw_width) / 2,
5277 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5281 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5284 XtSetArg(args[i], XtNx, x); i++;
5285 XtSetArg(args[i], XtNy, y); i++;
5286 XtSetValues(errorShell, args, i);
5289 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5292 /* Disable all user input other than deleting the window */
5293 static int frozen = 0;
5297 /* Grab by a widget that doesn't accept input */
5298 XtAddGrab(messageWidget, TRUE, FALSE);
5302 /* Undo a FreezeUI */
5305 if (!frozen) return;
5306 XtRemoveGrab(messageWidget);
5310 char *ModeToWidgetName(mode)
5314 case BeginningOfGame:
5315 if (appData.icsActive)
5316 return "menuMode.ICS Client";
5317 else if (appData.noChessProgram ||
5318 *appData.cmailGameName != NULLCHAR)
5319 return "menuMode.Edit Game";
5321 return "menuMode.Machine Black";
5322 case MachinePlaysBlack:
5323 return "menuMode.Machine Black";
5324 case MachinePlaysWhite:
5325 return "menuMode.Machine White";
5327 return "menuMode.Analysis Mode";
5329 return "menuMode.Analyze File";
5330 case TwoMachinesPlay:
5331 return "menuMode.Two Machines";
5333 return "menuMode.Edit Game";
5334 case PlayFromGameFile:
5335 return "menuFile.Load Game";
5337 return "menuMode.Edit Position";
5339 return "menuMode.Training";
5340 case IcsPlayingWhite:
5341 case IcsPlayingBlack:
5345 return "menuMode.ICS Client";
5352 void ModeHighlight()
5355 static int oldPausing = FALSE;
5356 static GameMode oldmode = (GameMode) -1;
5359 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5361 if (pausing != oldPausing) {
5362 oldPausing = pausing;
5364 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5366 XtSetArg(args[0], XtNleftBitmap, None);
5368 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5371 if (appData.showButtonBar) {
5372 /* Always toggle, don't set. Previous code messes up when
5373 invoked while the button is pressed, as releasing it
5374 toggles the state again. */
5377 XtSetArg(args[0], XtNbackground, &oldbg);
5378 XtSetArg(args[1], XtNforeground, &oldfg);
5379 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5381 XtSetArg(args[0], XtNbackground, oldfg);
5382 XtSetArg(args[1], XtNforeground, oldbg);
5384 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5388 wname = ModeToWidgetName(oldmode);
5389 if (wname != NULL) {
5390 XtSetArg(args[0], XtNleftBitmap, None);
5391 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5393 wname = ModeToWidgetName(gameMode);
5394 if (wname != NULL) {
5395 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5396 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5400 /* Maybe all the enables should be handled here, not just this one */
5401 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5402 gameMode == Training || gameMode == PlayFromGameFile);
5407 * Button/menu procedures
5409 void ResetProc(w, event, prms, nprms)
5418 int LoadGamePopUp(f, gameNumber, title)
5423 cmailMsgLoaded = FALSE;
5424 if (gameNumber == 0) {
5425 int error = GameListBuild(f);
5427 DisplayError(_("Cannot build game list"), error);
5428 } else if (!ListEmpty(&gameList) &&
5429 ((ListGame *) gameList.tailPred)->number > 1) {
5430 GameListPopUp(f, title);
5436 return LoadGame(f, gameNumber, title, FALSE);
5439 void LoadGameProc(w, event, prms, nprms)
5445 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5448 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5451 void LoadNextGameProc(w, event, prms, nprms)
5460 void LoadPrevGameProc(w, event, prms, nprms)
5469 void ReloadGameProc(w, event, prms, nprms)
5478 void LoadNextPositionProc(w, event, prms, nprms)
5487 void LoadPrevPositionProc(w, event, prms, nprms)
5496 void ReloadPositionProc(w, event, prms, nprms)
5505 void LoadPositionProc(w, event, prms, nprms)
5511 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5514 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5517 void SaveGameProc(w, event, prms, nprms)
5523 FileNamePopUp(_("Save game file name?"),
5524 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5528 void SavePositionProc(w, event, prms, nprms)
5534 FileNamePopUp(_("Save position file name?"),
5535 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5539 void ReloadCmailMsgProc(w, event, prms, nprms)
5545 ReloadCmailMsgEvent(FALSE);
5548 void MailMoveProc(w, event, prms, nprms)
5557 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5558 char *selected_fen_position=NULL;
5561 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5562 Atom *type_return, XtPointer *value_return,
5563 unsigned long *length_return, int *format_return)
5565 char *selection_tmp;
5567 if (!selected_fen_position) return False; /* should never happen */
5568 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5569 /* note: since no XtSelectionDoneProc was registered, Xt will
5570 * automatically call XtFree on the value returned. So have to
5571 * make a copy of it allocated with XtMalloc */
5572 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5573 strcpy(selection_tmp, selected_fen_position);
5575 *value_return=selection_tmp;
5576 *length_return=strlen(selection_tmp);
5577 *type_return=*target;
5578 *format_return = 8; /* bits per byte */
5580 } else if (*target == XA_TARGETS(xDisplay)) {
5581 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5582 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5583 targets_tmp[1] = XA_STRING;
5584 *value_return = targets_tmp;
5585 *type_return = XA_ATOM;
5587 *format_return = 8 * sizeof(Atom);
5588 if (*format_return > 32) {
5589 *length_return *= *format_return / 32;
5590 *format_return = 32;
5598 /* note: when called from menu all parameters are NULL, so no clue what the
5599 * Widget which was clicked on was, or what the click event was
5601 void CopyPositionProc(w, event, prms, nprms)
5608 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5609 * have a notion of a position that is selected but not copied.
5610 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5612 if(gameMode == EditPosition) EditPositionDone(TRUE);
5613 if (selected_fen_position) free(selected_fen_position);
5614 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5615 if (!selected_fen_position) return;
5616 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5618 SendPositionSelection,
5619 NULL/* lose_ownership_proc */ ,
5620 NULL/* transfer_done_proc */);
5621 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5623 SendPositionSelection,
5624 NULL/* lose_ownership_proc */ ,
5625 NULL/* transfer_done_proc */);
5628 /* function called when the data to Paste is ready */
5630 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5631 Atom *type, XtPointer value, unsigned long *len, int *format)
5634 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5635 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5636 EditPositionPasteFEN(fenstr);
5640 /* called when Paste Position button is pressed,
5641 * all parameters will be NULL */
5642 void PastePositionProc(w, event, prms, nprms)
5648 XtGetSelectionValue(menuBarWidget,
5649 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5650 /* (XtSelectionCallbackProc) */ PastePositionCB,
5651 NULL, /* client_data passed to PastePositionCB */
5653 /* better to use the time field from the event that triggered the
5654 * call to this function, but that isn't trivial to get
5662 SendGameSelection(Widget w, Atom *selection, Atom *target,
5663 Atom *type_return, XtPointer *value_return,
5664 unsigned long *length_return, int *format_return)
5666 char *selection_tmp;
5668 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5669 FILE* f = fopen(gameCopyFilename, "r");
5672 if (f == NULL) return False;
5676 selection_tmp = XtMalloc(len + 1);
5677 count = fread(selection_tmp, 1, len, f);
5679 XtFree(selection_tmp);
5682 selection_tmp[len] = NULLCHAR;
5683 *value_return = selection_tmp;
5684 *length_return = len;
5685 *type_return = *target;
5686 *format_return = 8; /* bits per byte */
5688 } else if (*target == XA_TARGETS(xDisplay)) {
5689 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5690 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5691 targets_tmp[1] = XA_STRING;
5692 *value_return = targets_tmp;
5693 *type_return = XA_ATOM;
5695 *format_return = 8 * sizeof(Atom);
5696 if (*format_return > 32) {
5697 *length_return *= *format_return / 32;
5698 *format_return = 32;
5706 /* note: when called from menu all parameters are NULL, so no clue what the
5707 * Widget which was clicked on was, or what the click event was
5709 void CopyGameProc(w, event, prms, nprms)
5717 ret = SaveGameToFile(gameCopyFilename, FALSE);
5721 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5722 * have a notion of a game that is selected but not copied.
5723 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5725 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5728 NULL/* lose_ownership_proc */ ,
5729 NULL/* transfer_done_proc */);
5730 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5733 NULL/* lose_ownership_proc */ ,
5734 NULL/* transfer_done_proc */);
5737 /* function called when the data to Paste is ready */
5739 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5740 Atom *type, XtPointer value, unsigned long *len, int *format)
5743 if (value == NULL || *len == 0) {
5744 return; /* nothing had been selected to copy */
5746 f = fopen(gamePasteFilename, "w");
5748 DisplayError(_("Can't open temp file"), errno);
5751 fwrite(value, 1, *len, f);
5754 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5757 /* called when Paste Game button is pressed,
5758 * all parameters will be NULL */
5759 void PasteGameProc(w, event, prms, nprms)
5765 XtGetSelectionValue(menuBarWidget,
5766 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5767 /* (XtSelectionCallbackProc) */ PasteGameCB,
5768 NULL, /* client_data passed to PasteGameCB */
5770 /* better to use the time field from the event that triggered the
5771 * call to this function, but that isn't trivial to get
5781 SaveGameProc(NULL, NULL, NULL, NULL);
5785 void QuitProc(w, event, prms, nprms)
5794 void PauseProc(w, event, prms, nprms)
5804 void MachineBlackProc(w, event, prms, nprms)
5810 MachineBlackEvent();
5813 void MachineWhiteProc(w, event, prms, nprms)
5819 MachineWhiteEvent();
5822 void AnalyzeModeProc(w, event, prms, nprms)
5830 if (!first.analysisSupport) {
5831 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5832 DisplayError(buf, 0);
5835 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5836 if (appData.icsActive) {
5837 if (gameMode != IcsObserving) {
5838 sprintf(buf,_("You are not observing a game"));
5839 DisplayError(buf, 0);
5841 if (appData.icsEngineAnalyze) {
5842 if (appData.debugMode)
5843 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5849 /* if enable, use want disable icsEngineAnalyze */
5850 if (appData.icsEngineAnalyze) {
5855 appData.icsEngineAnalyze = TRUE;
5856 if (appData.debugMode)
5857 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5859 if (!appData.showThinking)
5860 ShowThinkingProc(w,event,prms,nprms);
5865 void AnalyzeFileProc(w, event, prms, nprms)
5871 if (!first.analysisSupport) {
5873 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5874 DisplayError(buf, 0);
5879 if (!appData.showThinking)
5880 ShowThinkingProc(w,event,prms,nprms);
5883 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
5884 AnalysisPeriodicEvent(1);
5887 void TwoMachinesProc(w, event, prms, nprms)
5896 void IcsClientProc(w, event, prms, nprms)
5905 void EditGameProc(w, event, prms, nprms)
5914 void EditPositionProc(w, event, prms, nprms)
5920 EditPositionEvent();
5923 void TrainingProc(w, event, prms, nprms)
5932 void EditCommentProc(w, event, prms, nprms)
5939 EditCommentPopDown();
5945 void IcsInputBoxProc(w, event, prms, nprms)
5951 if (ICSInputBoxUp) {
5952 ICSInputBoxPopDown();
5958 void AcceptProc(w, event, prms, nprms)
5967 void DeclineProc(w, event, prms, nprms)
5976 void RematchProc(w, event, prms, nprms)
5985 void CallFlagProc(w, event, prms, nprms)
5994 void DrawProc(w, event, prms, nprms)
6003 void AbortProc(w, event, prms, nprms)
6012 void AdjournProc(w, event, prms, nprms)
6021 void ResignProc(w, event, prms, nprms)
6030 void AdjuWhiteProc(w, event, prms, nprms)
6036 UserAdjudicationEvent(+1);
6039 void AdjuBlackProc(w, event, prms, nprms)
6045 UserAdjudicationEvent(-1);
6048 void AdjuDrawProc(w, event, prms, nprms)
6054 UserAdjudicationEvent(0);
6057 void EnterKeyProc(w, event, prms, nprms)
6063 if (ICSInputBoxUp == True)
6067 void StopObservingProc(w, event, prms, nprms)
6073 StopObservingEvent();
6076 void StopExaminingProc(w, event, prms, nprms)
6082 StopExaminingEvent();
6086 void ForwardProc(w, event, prms, nprms)
6096 void BackwardProc(w, event, prms, nprms)
6105 void ToStartProc(w, event, prms, nprms)
6114 void ToEndProc(w, event, prms, nprms)
6123 void RevertProc(w, event, prms, nprms)
6132 void TruncateGameProc(w, event, prms, nprms)
6138 TruncateGameEvent();
6140 void RetractMoveProc(w, event, prms, nprms)
6149 void MoveNowProc(w, event, prms, nprms)
6159 void AlwaysQueenProc(w, event, prms, nprms)
6167 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6169 if (appData.alwaysPromoteToQueen) {
6170 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6172 XtSetArg(args[0], XtNleftBitmap, None);
6174 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6178 void AnimateDraggingProc(w, event, prms, nprms)
6186 appData.animateDragging = !appData.animateDragging;
6188 if (appData.animateDragging) {
6189 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6192 XtSetArg(args[0], XtNleftBitmap, None);
6194 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6198 void AnimateMovingProc(w, event, prms, nprms)
6206 appData.animate = !appData.animate;
6208 if (appData.animate) {
6209 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6212 XtSetArg(args[0], XtNleftBitmap, None);
6214 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6218 void AutocommProc(w, event, prms, nprms)
6226 appData.autoComment = !appData.autoComment;
6228 if (appData.autoComment) {
6229 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6231 XtSetArg(args[0], XtNleftBitmap, None);
6233 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6238 void AutoflagProc(w, event, prms, nprms)
6246 appData.autoCallFlag = !appData.autoCallFlag;
6248 if (appData.autoCallFlag) {
6249 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6251 XtSetArg(args[0], XtNleftBitmap, None);
6253 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6257 void AutoflipProc(w, event, prms, nprms)
6265 appData.autoFlipView = !appData.autoFlipView;
6267 if (appData.autoFlipView) {
6268 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6270 XtSetArg(args[0], XtNleftBitmap, None);
6272 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6276 void AutobsProc(w, event, prms, nprms)
6284 appData.autoObserve = !appData.autoObserve;
6286 if (appData.autoObserve) {
6287 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6289 XtSetArg(args[0], XtNleftBitmap, None);
6291 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6295 void AutoraiseProc(w, event, prms, nprms)
6303 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6305 if (appData.autoRaiseBoard) {
6306 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6308 XtSetArg(args[0], XtNleftBitmap, None);
6310 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6314 void AutosaveProc(w, event, prms, nprms)
6322 appData.autoSaveGames = !appData.autoSaveGames;
6324 if (appData.autoSaveGames) {
6325 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6327 XtSetArg(args[0], XtNleftBitmap, None);
6329 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6333 void BlindfoldProc(w, event, prms, nprms)
6341 appData.blindfold = !appData.blindfold;
6343 if (appData.blindfold) {
6344 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6346 XtSetArg(args[0], XtNleftBitmap, None);
6348 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6351 DrawPosition(True, NULL);
6354 void TestLegalityProc(w, event, prms, nprms)
6362 appData.testLegality = !appData.testLegality;
6364 if (appData.testLegality) {
6365 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6367 XtSetArg(args[0], XtNleftBitmap, None);
6369 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6374 void FlashMovesProc(w, event, prms, nprms)
6382 if (appData.flashCount == 0) {
6383 appData.flashCount = 3;
6385 appData.flashCount = -appData.flashCount;
6388 if (appData.flashCount > 0) {
6389 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6391 XtSetArg(args[0], XtNleftBitmap, None);
6393 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6397 void FlipViewProc(w, event, prms, nprms)
6403 flipView = !flipView;
6404 DrawPosition(True, NULL);
6407 void GetMoveListProc(w, event, prms, nprms)
6415 appData.getMoveList = !appData.getMoveList;
6417 if (appData.getMoveList) {
6418 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6421 XtSetArg(args[0], XtNleftBitmap, None);
6423 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6428 void HighlightDraggingProc(w, event, prms, nprms)
6436 appData.highlightDragging = !appData.highlightDragging;
6438 if (appData.highlightDragging) {
6439 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6441 XtSetArg(args[0], XtNleftBitmap, None);
6443 XtSetValues(XtNameToWidget(menuBarWidget,
6444 "menuOptions.Highlight Dragging"), args, 1);
6448 void HighlightLastMoveProc(w, event, prms, nprms)
6456 appData.highlightLastMove = !appData.highlightLastMove;
6458 if (appData.highlightLastMove) {
6459 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6461 XtSetArg(args[0], XtNleftBitmap, None);
6463 XtSetValues(XtNameToWidget(menuBarWidget,
6464 "menuOptions.Highlight Last Move"), args, 1);
6467 void IcsAlarmProc(w, event, prms, nprms)
6475 appData.icsAlarm = !appData.icsAlarm;
6477 if (appData.icsAlarm) {
6478 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6480 XtSetArg(args[0], XtNleftBitmap, None);
6482 XtSetValues(XtNameToWidget(menuBarWidget,
6483 "menuOptions.ICS Alarm"), args, 1);
6486 void MoveSoundProc(w, event, prms, nprms)
6494 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6496 if (appData.ringBellAfterMoves) {
6497 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6499 XtSetArg(args[0], XtNleftBitmap, None);
6501 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6506 void OldSaveStyleProc(w, event, prms, nprms)
6514 appData.oldSaveStyle = !appData.oldSaveStyle;
6516 if (appData.oldSaveStyle) {
6517 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6519 XtSetArg(args[0], XtNleftBitmap, None);
6521 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6525 void PeriodicUpdatesProc(w, event, prms, nprms)
6533 PeriodicUpdatesEvent(!appData.periodicUpdates);
6535 if (appData.periodicUpdates) {
6536 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6538 XtSetArg(args[0], XtNleftBitmap, None);
6540 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6544 void PonderNextMoveProc(w, event, prms, nprms)
6552 PonderNextMoveEvent(!appData.ponderNextMove);
6554 if (appData.ponderNextMove) {
6555 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6557 XtSetArg(args[0], XtNleftBitmap, None);
6559 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6563 void PopupExitMessageProc(w, event, prms, nprms)
6571 appData.popupExitMessage = !appData.popupExitMessage;
6573 if (appData.popupExitMessage) {
6574 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6576 XtSetArg(args[0], XtNleftBitmap, None);
6578 XtSetValues(XtNameToWidget(menuBarWidget,
6579 "menuOptions.Popup Exit Message"), args, 1);
6582 void PopupMoveErrorsProc(w, event, prms, nprms)
6590 appData.popupMoveErrors = !appData.popupMoveErrors;
6592 if (appData.popupMoveErrors) {
6593 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6595 XtSetArg(args[0], XtNleftBitmap, None);
6597 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6601 void PremoveProc(w, event, prms, nprms)
6609 appData.premove = !appData.premove;
6611 if (appData.premove) {
6612 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6614 XtSetArg(args[0], XtNleftBitmap, None);
6616 XtSetValues(XtNameToWidget(menuBarWidget,
6617 "menuOptions.Premove"), args, 1);
6620 void QuietPlayProc(w, event, prms, nprms)
6628 appData.quietPlay = !appData.quietPlay;
6630 if (appData.quietPlay) {
6631 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6633 XtSetArg(args[0], XtNleftBitmap, None);
6635 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6639 void ShowCoordsProc(w, event, prms, nprms)
6647 appData.showCoords = !appData.showCoords;
6649 if (appData.showCoords) {
6650 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6652 XtSetArg(args[0], XtNleftBitmap, None);
6654 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6657 DrawPosition(True, NULL);
6660 void ShowThinkingProc(w, event, prms, nprms)
6666 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6667 ShowThinkingEvent();
6670 void HideThinkingProc(w, event, prms, nprms)
6678 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6679 ShowThinkingEvent();
6681 if (appData.hideThinkingFromHuman) {
6682 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6684 XtSetArg(args[0], XtNleftBitmap, None);
6686 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6690 void SaveOnExitProc(w, event, prms, nprms)
6698 saveSettingsOnExit = !saveSettingsOnExit;
6700 if (saveSettingsOnExit) {
6701 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6703 XtSetArg(args[0], XtNleftBitmap, None);
6705 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6709 void SaveSettingsProc(w, event, prms, nprms)
6715 SaveSettings(settingsFileName);
6718 void InfoProc(w, event, prms, nprms)
6725 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6730 void ManProc(w, event, prms, nprms)
6738 if (nprms && *nprms > 0)
6742 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6746 void HintProc(w, event, prms, nprms)
6755 void BookProc(w, event, prms, nprms)
6764 void AboutProc(w, event, prms, nprms)
6772 char *zippy = " (with Zippy code)";
6776 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6777 programVersion, zippy,
6778 "Copyright 1991 Digital Equipment Corporation",
6779 "Enhancements Copyright 1992-2009 Free Software Foundation",
6780 "Enhancements Copyright 2005 Alessandro Scotti",
6781 PACKAGE, " is free software and carries NO WARRANTY;",
6782 "see the file COPYING for more information.");
6783 ErrorPopUp(_("About XBoard"), buf, FALSE);
6786 void DebugProc(w, event, prms, nprms)
6792 appData.debugMode = !appData.debugMode;
6795 void AboutGameProc(w, event, prms, nprms)
6804 void NothingProc(w, event, prms, nprms)
6813 void Iconify(w, event, prms, nprms)
6822 XtSetArg(args[0], XtNiconic, True);
6823 XtSetValues(shellWidget, args, 1);
6826 void DisplayMessage(message, extMessage)
6827 char *message, *extMessage;
6829 /* display a message in the message widget */
6838 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
6843 message = extMessage;
6847 /* need to test if messageWidget already exists, since this function
6848 can also be called during the startup, if for example a Xresource
6849 is not set up correctly */
6852 XtSetArg(arg, XtNlabel, message);
6853 XtSetValues(messageWidget, &arg, 1);
6859 void DisplayTitle(text)
6864 char title[MSG_SIZ];
6867 if (text == NULL) text = "";
6869 if (appData.titleInWindow) {
6871 XtSetArg(args[i], XtNlabel, text); i++;
6872 XtSetValues(titleWidget, args, i);
6875 if (*text != NULLCHAR) {
6877 strcpy(title, text);
6878 } else if (appData.icsActive) {
6879 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
6880 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
6881 } else if (appData.cmailGameName[0] != NULLCHAR) {
6882 snprintf(icon, sizeof(icon), "%s", "CMail");
6883 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
6885 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
6886 } else if (gameInfo.variant == VariantGothic) {
6887 strcpy(icon, programName);
6888 strcpy(title, GOTHIC);
6891 } else if (gameInfo.variant == VariantFalcon) {
6892 strcpy(icon, programName);
6893 strcpy(title, FALCON);
6895 } else if (appData.noChessProgram) {
6896 strcpy(icon, programName);
6897 strcpy(title, programName);
6899 strcpy(icon, first.tidy);
6900 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
6903 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
6904 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
6905 XtSetValues(shellWidget, args, i);
6909 void DisplayError(message, error)
6916 if (appData.debugMode || appData.matchMode) {
6917 fprintf(stderr, "%s: %s\n", programName, message);
6920 if (appData.debugMode || appData.matchMode) {
6921 fprintf(stderr, "%s: %s: %s\n",
6922 programName, message, strerror(error));
6924 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6927 ErrorPopUp(_("Error"), message, FALSE);
6931 void DisplayMoveError(message)
6936 DrawPosition(FALSE, NULL);
6937 if (appData.debugMode || appData.matchMode) {
6938 fprintf(stderr, "%s: %s\n", programName, message);
6940 if (appData.popupMoveErrors) {
6941 ErrorPopUp(_("Error"), message, FALSE);
6943 DisplayMessage(message, "");
6948 void DisplayFatalError(message, error, status)
6954 errorExitStatus = status;
6956 fprintf(stderr, "%s: %s\n", programName, message);
6958 fprintf(stderr, "%s: %s: %s\n",
6959 programName, message, strerror(error));
6960 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6963 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
6964 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
6970 void DisplayInformation(message)
6974 ErrorPopUp(_("Information"), message, TRUE);
6977 void DisplayNote(message)
6981 ErrorPopUp(_("Note"), message, FALSE);
6985 NullXErrorCheck(dpy, error_event)
6987 XErrorEvent *error_event;
6992 void DisplayIcsInteractionTitle(message)
6995 if (oldICSInteractionTitle == NULL) {
6996 /* Magic to find the old window title, adapted from vim */
6997 char *wina = getenv("WINDOWID");
6999 Window win = (Window) atoi(wina);
7000 Window root, parent, *children;
7001 unsigned int nchildren;
7002 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7004 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7005 if (!XQueryTree(xDisplay, win, &root, &parent,
7006 &children, &nchildren)) break;
7007 if (children) XFree((void *)children);
7008 if (parent == root || parent == 0) break;
7011 XSetErrorHandler(oldHandler);
7013 if (oldICSInteractionTitle == NULL) {
7014 oldICSInteractionTitle = "xterm";
7017 printf("\033]0;%s\007", message);
7021 char pendingReplyPrefix[MSG_SIZ];
7022 ProcRef pendingReplyPR;
7024 void AskQuestionProc(w, event, prms, nprms)
7031 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7035 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7038 void AskQuestionPopDown()
7040 if (!askQuestionUp) return;
7041 XtPopdown(askQuestionShell);
7042 XtDestroyWidget(askQuestionShell);
7043 askQuestionUp = False;
7046 void AskQuestionReplyAction(w, event, prms, nprms)
7056 reply = XawDialogGetValueString(w = XtParent(w));
7057 strcpy(buf, pendingReplyPrefix);
7058 if (*buf) strcat(buf, " ");
7061 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7062 AskQuestionPopDown();
7064 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7067 void AskQuestionCallback(w, client_data, call_data)
7069 XtPointer client_data, call_data;
7074 XtSetArg(args[0], XtNlabel, &name);
7075 XtGetValues(w, args, 1);
7077 if (strcmp(name, _("cancel")) == 0) {
7078 AskQuestionPopDown();
7080 AskQuestionReplyAction(w, NULL, NULL, NULL);
7084 void AskQuestion(title, question, replyPrefix, pr)
7085 char *title, *question, *replyPrefix;
7089 Widget popup, layout, dialog, edit;
7095 strcpy(pendingReplyPrefix, replyPrefix);
7096 pendingReplyPR = pr;
7099 XtSetArg(args[i], XtNresizable, True); i++;
7100 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7101 askQuestionShell = popup =
7102 XtCreatePopupShell(title, transientShellWidgetClass,
7103 shellWidget, args, i);
7106 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7107 layoutArgs, XtNumber(layoutArgs));
7110 XtSetArg(args[i], XtNlabel, question); i++;
7111 XtSetArg(args[i], XtNvalue, ""); i++;
7112 XtSetArg(args[i], XtNborderWidth, 0); i++;
7113 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7116 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7117 (XtPointer) dialog);
7118 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7119 (XtPointer) dialog);
7121 XtRealizeWidget(popup);
7122 CatchDeleteWindow(popup, "AskQuestionPopDown");
7124 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7125 &x, &y, &win_x, &win_y, &mask);
7127 XtSetArg(args[0], XtNx, x - 10);
7128 XtSetArg(args[1], XtNy, y - 30);
7129 XtSetValues(popup, args, 2);
7131 XtPopup(popup, XtGrabExclusive);
7132 askQuestionUp = True;
7134 edit = XtNameToWidget(dialog, "*value");
7135 XtSetKeyboardFocus(popup, edit);
7143 if (*name == NULLCHAR) {
7145 } else if (strcmp(name, "$") == 0) {
7146 putc(BELLCHAR, stderr);
7149 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7157 PlaySound(appData.soundMove);
7163 PlaySound(appData.soundIcsWin);
7169 PlaySound(appData.soundIcsLoss);
7175 PlaySound(appData.soundIcsDraw);
7179 PlayIcsUnfinishedSound()
7181 PlaySound(appData.soundIcsUnfinished);
7187 PlaySound(appData.soundIcsAlarm);
7193 system("stty echo");
7199 system("stty -echo");
7203 Colorize(cc, continuation)
7208 int count, outCount, error;
7210 if (textColors[(int)cc].bg > 0) {
7211 if (textColors[(int)cc].fg > 0) {
7212 sprintf(buf, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7213 textColors[(int)cc].fg, textColors[(int)cc].bg);
7215 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7216 textColors[(int)cc].bg);
7219 if (textColors[(int)cc].fg > 0) {
7220 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7221 textColors[(int)cc].fg);
7223 sprintf(buf, "\033[0;%dm", textColors[(int)cc].attr);
7226 count = strlen(buf);
7227 outCount = OutputToProcess(NoProc, buf, count, &error);
7228 if (outCount < count) {
7229 DisplayFatalError(_("Error writing to display"), error, 1);
7232 if (continuation) return;
7235 PlaySound(appData.soundShout);
7238 PlaySound(appData.soundSShout);
7241 PlaySound(appData.soundChannel1);
7244 PlaySound(appData.soundChannel);
7247 PlaySound(appData.soundKibitz);
7250 PlaySound(appData.soundTell);
7252 case ColorChallenge:
7253 PlaySound(appData.soundChallenge);
7256 PlaySound(appData.soundRequest);
7259 PlaySound(appData.soundSeek);
7270 return getpwuid(getuid())->pw_name;
7273 static char *ExpandPathName(path)
7276 static char static_buf[2000];
7277 char *d, *s, buf[2000];
7283 while (*s && isspace(*s))
7292 if (*(s+1) == '/') {
7293 strcpy(d, getpwuid(getuid())->pw_dir);
7298 *strchr(buf, '/') = 0;
7299 pwd = getpwnam(buf);
7302 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7306 strcpy(d, pwd->pw_dir);
7307 strcat(d, strchr(s+1, '/'));
7318 static char host_name[MSG_SIZ];
7320 #if HAVE_GETHOSTNAME
7321 gethostname(host_name, MSG_SIZ);
7323 #else /* not HAVE_GETHOSTNAME */
7324 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7325 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7327 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7329 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7330 #endif /* not HAVE_GETHOSTNAME */
7333 XtIntervalId delayedEventTimerXID = 0;
7334 DelayedEventCallback delayedEventCallback = 0;
7339 delayedEventTimerXID = 0;
7340 delayedEventCallback();
7344 ScheduleDelayedEvent(cb, millisec)
7345 DelayedEventCallback cb; long millisec;
7347 if(delayedEventTimerXID && delayedEventCallback == cb)
7348 // [HGM] alive: replace, rather than add or flush identical event
7349 XtRemoveTimeOut(delayedEventTimerXID);
7350 delayedEventCallback = cb;
7351 delayedEventTimerXID =
7352 XtAppAddTimeOut(appContext, millisec,
7353 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7356 DelayedEventCallback
7359 if (delayedEventTimerXID) {
7360 return delayedEventCallback;
7367 CancelDelayedEvent()
7369 if (delayedEventTimerXID) {
7370 XtRemoveTimeOut(delayedEventTimerXID);
7371 delayedEventTimerXID = 0;
7375 XtIntervalId loadGameTimerXID = 0;
7377 int LoadGameTimerRunning()
7379 return loadGameTimerXID != 0;
7382 int StopLoadGameTimer()
7384 if (loadGameTimerXID != 0) {
7385 XtRemoveTimeOut(loadGameTimerXID);
7386 loadGameTimerXID = 0;
7394 LoadGameTimerCallback(arg, id)
7398 loadGameTimerXID = 0;
7403 StartLoadGameTimer(millisec)
7407 XtAppAddTimeOut(appContext, millisec,
7408 (XtTimerCallbackProc) LoadGameTimerCallback,
7412 XtIntervalId analysisClockXID = 0;
7415 AnalysisClockCallback(arg, id)
7419 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7420 || appData.icsEngineAnalyze) { // [DM]
7421 AnalysisPeriodicEvent(0);
7422 StartAnalysisClock();
7427 StartAnalysisClock()
7430 XtAppAddTimeOut(appContext, 2000,
7431 (XtTimerCallbackProc) AnalysisClockCallback,
7435 XtIntervalId clockTimerXID = 0;
7437 int ClockTimerRunning()
7439 return clockTimerXID != 0;
7442 int StopClockTimer()
7444 if (clockTimerXID != 0) {
7445 XtRemoveTimeOut(clockTimerXID);
7454 ClockTimerCallback(arg, id)
7463 StartClockTimer(millisec)
7467 XtAppAddTimeOut(appContext, millisec,
7468 (XtTimerCallbackProc) ClockTimerCallback,
7473 DisplayTimerLabel(w, color, timer, highlight)
7482 /* check for low time warning */
7483 Pixel foregroundOrWarningColor = timerForegroundPixel;
7486 appData.lowTimeWarning &&
7487 (timer / 1000) < appData.icsAlarmTime)
7488 foregroundOrWarningColor = lowTimeWarningColor;
7490 if (appData.clockMode) {
7491 sprintf(buf, "%s: %s", color, TimeString(timer));
7492 XtSetArg(args[0], XtNlabel, buf);
7494 sprintf(buf, "%s ", color);
7495 XtSetArg(args[0], XtNlabel, buf);
7500 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7501 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7503 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7504 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7507 XtSetValues(w, args, 3);
7511 DisplayWhiteClock(timeRemaining, highlight)
7517 if(appData.noGUI) return;
7518 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7519 if (highlight && iconPixmap == bIconPixmap) {
7520 iconPixmap = wIconPixmap;
7521 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7522 XtSetValues(shellWidget, args, 1);
7527 DisplayBlackClock(timeRemaining, highlight)
7533 if(appData.noGUI) return;
7534 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7535 if (highlight && iconPixmap == wIconPixmap) {
7536 iconPixmap = bIconPixmap;
7537 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7538 XtSetValues(shellWidget, args, 1);
7556 int StartChildProcess(cmdLine, dir, pr)
7563 int to_prog[2], from_prog[2];
7567 if (appData.debugMode) {
7568 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7571 /* We do NOT feed the cmdLine to the shell; we just
7572 parse it into blank-separated arguments in the
7573 most simple-minded way possible.
7576 strcpy(buf, cmdLine);
7579 while(*p == ' ') p++;
7581 if(*p == '"' || *p == '\'')
7582 p = strchr(++argv[i-1], *p);
7583 else p = strchr(p, ' ');
7584 if (p == NULL) break;
7589 SetUpChildIO(to_prog, from_prog);
7591 if ((pid = fork()) == 0) {
7593 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7594 close(to_prog[1]); // first close the unused pipe ends
7595 close(from_prog[0]);
7596 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7597 dup2(from_prog[1], 1);
7598 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7599 close(from_prog[1]); // and closing again loses one of the pipes!
7600 if(fileno(stderr) >= 2) // better safe than sorry...
7601 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7603 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7608 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7610 execvp(argv[0], argv);
7612 /* If we get here, exec failed */
7617 /* Parent process */
7619 close(from_prog[1]);
7621 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7624 cp->fdFrom = from_prog[0];
7625 cp->fdTo = to_prog[1];
7630 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7631 static RETSIGTYPE AlarmCallBack(int n)
7637 DestroyChildProcess(pr, signalType)
7641 ChildProc *cp = (ChildProc *) pr;
7643 if (cp->kind != CPReal) return;
7645 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7646 signal(SIGALRM, AlarmCallBack);
7648 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7649 kill(cp->pid, SIGKILL); // kill it forcefully
7650 wait((int *) 0); // and wait again
7654 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7656 /* Process is exiting either because of the kill or because of
7657 a quit command sent by the backend; either way, wait for it to die.
7666 InterruptChildProcess(pr)
7669 ChildProc *cp = (ChildProc *) pr;
7671 if (cp->kind != CPReal) return;
7672 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7675 int OpenTelnet(host, port, pr)
7680 char cmdLine[MSG_SIZ];
7682 if (port[0] == NULLCHAR) {
7683 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7685 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7687 return StartChildProcess(cmdLine, "", pr);
7690 int OpenTCP(host, port, pr)
7696 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7697 #else /* !OMIT_SOCKETS */
7699 struct sockaddr_in sa;
7701 unsigned short uport;
7704 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7708 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7709 sa.sin_family = AF_INET;
7710 sa.sin_addr.s_addr = INADDR_ANY;
7711 uport = (unsigned short) 0;
7712 sa.sin_port = htons(uport);
7713 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7717 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7718 if (!(hp = gethostbyname(host))) {
7720 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7721 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7722 hp->h_addrtype = AF_INET;
7724 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7725 hp->h_addr_list[0] = (char *) malloc(4);
7726 hp->h_addr_list[0][0] = b0;
7727 hp->h_addr_list[0][1] = b1;
7728 hp->h_addr_list[0][2] = b2;
7729 hp->h_addr_list[0][3] = b3;
7734 sa.sin_family = hp->h_addrtype;
7735 uport = (unsigned short) atoi(port);
7736 sa.sin_port = htons(uport);
7737 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7739 if (connect(s, (struct sockaddr *) &sa,
7740 sizeof(struct sockaddr_in)) < 0) {
7744 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7751 #endif /* !OMIT_SOCKETS */
7756 int OpenCommPort(name, pr)
7763 fd = open(name, 2, 0);
7764 if (fd < 0) return errno;
7766 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7776 int OpenLoopback(pr)
7782 SetUpChildIO(to, from);
7784 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7787 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7794 int OpenRcmd(host, user, cmd, pr)
7795 char *host, *user, *cmd;
7798 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7802 #define INPUT_SOURCE_BUF_SIZE 8192
7811 char buf[INPUT_SOURCE_BUF_SIZE];
7816 DoInputCallback(closure, source, xid)
7821 InputSource *is = (InputSource *) closure;
7826 if (is->lineByLine) {
7827 count = read(is->fd, is->unused,
7828 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7830 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7833 is->unused += count;
7835 while (p < is->unused) {
7836 q = memchr(p, '\n', is->unused - p);
7837 if (q == NULL) break;
7839 (is->func)(is, is->closure, p, q - p, 0);
7843 while (p < is->unused) {
7848 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
7853 (is->func)(is, is->closure, is->buf, count, error);
7857 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
7864 ChildProc *cp = (ChildProc *) pr;
7866 is = (InputSource *) calloc(1, sizeof(InputSource));
7867 is->lineByLine = lineByLine;
7871 is->fd = fileno(stdin);
7873 is->kind = cp->kind;
7874 is->fd = cp->fdFrom;
7877 is->unused = is->buf;
7880 is->xid = XtAppAddInput(appContext, is->fd,
7881 (XtPointer) (XtInputReadMask),
7882 (XtInputCallbackProc) DoInputCallback,
7884 is->closure = closure;
7885 return (InputSourceRef) is;
7889 RemoveInputSource(isr)
7892 InputSource *is = (InputSource *) isr;
7894 if (is->xid == 0) return;
7895 XtRemoveInput(is->xid);
7899 int OutputToProcess(pr, message, count, outError)
7905 static int line = 0;
7906 ChildProc *cp = (ChildProc *) pr;
7911 if (appData.noJoin || !appData.useInternalWrap)
7912 outCount = fwrite(message, 1, count, stdout);
7915 int width = get_term_width();
7916 int len = wrap(NULL, message, count, width, &line);
7917 char *msg = malloc(len);
7921 outCount = fwrite(message, 1, count, stdout);
7924 dbgchk = wrap(msg, message, count, width, &line);
7925 if (dbgchk != len && appData.debugMode)
7926 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
7927 outCount = fwrite(msg, 1, dbgchk, stdout);
7933 outCount = write(cp->fdTo, message, count);
7943 /* Output message to process, with "ms" milliseconds of delay
7944 between each character. This is needed when sending the logon
7945 script to ICC, which for some reason doesn't like the
7946 instantaneous send. */
7947 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
7954 ChildProc *cp = (ChildProc *) pr;
7959 r = write(cp->fdTo, message++, 1);
7972 /**** Animation code by Hugh Fisher, DCS, ANU.
7974 Known problem: if a window overlapping the board is
7975 moved away while a piece is being animated underneath,
7976 the newly exposed area won't be updated properly.
7977 I can live with this.
7979 Known problem: if you look carefully at the animation
7980 of pieces in mono mode, they are being drawn as solid
7981 shapes without interior detail while moving. Fixing
7982 this would be a major complication for minimal return.
7985 /* Masks for XPM pieces. Black and white pieces can have
7986 different shapes, but in the interest of retaining my
7987 sanity pieces must have the same outline on both light
7988 and dark squares, and all pieces must use the same
7989 background square colors/images. */
7991 static int xpmDone = 0;
7994 CreateAnimMasks (pieceDepth)
8001 unsigned long plane;
8004 /* Need a bitmap just to get a GC with right depth */
8005 buf = XCreatePixmap(xDisplay, xBoardWindow,
8007 values.foreground = 1;
8008 values.background = 0;
8009 /* Don't use XtGetGC, not read only */
8010 maskGC = XCreateGC(xDisplay, buf,
8011 GCForeground | GCBackground, &values);
8012 XFreePixmap(xDisplay, buf);
8014 buf = XCreatePixmap(xDisplay, xBoardWindow,
8015 squareSize, squareSize, pieceDepth);
8016 values.foreground = XBlackPixel(xDisplay, xScreen);
8017 values.background = XWhitePixel(xDisplay, xScreen);
8018 bufGC = XCreateGC(xDisplay, buf,
8019 GCForeground | GCBackground, &values);
8021 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8022 /* Begin with empty mask */
8023 if(!xpmDone) // [HGM] pieces: keep using existing
8024 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8025 squareSize, squareSize, 1);
8026 XSetFunction(xDisplay, maskGC, GXclear);
8027 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8028 0, 0, squareSize, squareSize);
8030 /* Take a copy of the piece */
8035 XSetFunction(xDisplay, bufGC, GXcopy);
8036 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8038 0, 0, squareSize, squareSize, 0, 0);
8040 /* XOR the background (light) over the piece */
8041 XSetFunction(xDisplay, bufGC, GXxor);
8043 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8044 0, 0, squareSize, squareSize, 0, 0);
8046 XSetForeground(xDisplay, bufGC, lightSquareColor);
8047 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8050 /* We now have an inverted piece image with the background
8051 erased. Construct mask by just selecting all the non-zero
8052 pixels - no need to reconstruct the original image. */
8053 XSetFunction(xDisplay, maskGC, GXor);
8055 /* Might be quicker to download an XImage and create bitmap
8056 data from it rather than this N copies per piece, but it
8057 only takes a fraction of a second and there is a much
8058 longer delay for loading the pieces. */
8059 for (n = 0; n < pieceDepth; n ++) {
8060 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8061 0, 0, squareSize, squareSize,
8067 XFreePixmap(xDisplay, buf);
8068 XFreeGC(xDisplay, bufGC);
8069 XFreeGC(xDisplay, maskGC);
8073 InitAnimState (anim, info)
8075 XWindowAttributes * info;
8080 /* Each buffer is square size, same depth as window */
8081 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8082 squareSize, squareSize, info->depth);
8083 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8084 squareSize, squareSize, info->depth);
8086 /* Create a plain GC for blitting */
8087 mask = GCForeground | GCBackground | GCFunction |
8088 GCPlaneMask | GCGraphicsExposures;
8089 values.foreground = XBlackPixel(xDisplay, xScreen);
8090 values.background = XWhitePixel(xDisplay, xScreen);
8091 values.function = GXcopy;
8092 values.plane_mask = AllPlanes;
8093 values.graphics_exposures = False;
8094 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8096 /* Piece will be copied from an existing context at
8097 the start of each new animation/drag. */
8098 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8100 /* Outline will be a read-only copy of an existing */
8101 anim->outlineGC = None;
8107 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8108 XWindowAttributes info;
8110 if (xpmDone && gameInfo.variant == old) return;
8111 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8112 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8114 InitAnimState(&game, &info);
8115 InitAnimState(&player, &info);
8117 /* For XPM pieces, we need bitmaps to use as masks. */
8119 CreateAnimMasks(info.depth);
8125 static Boolean frameWaiting;
8127 static RETSIGTYPE FrameAlarm (sig)
8130 frameWaiting = False;
8131 /* In case System-V style signals. Needed?? */
8132 signal(SIGALRM, FrameAlarm);
8139 struct itimerval delay;
8141 XSync(xDisplay, False);
8144 frameWaiting = True;
8145 signal(SIGALRM, FrameAlarm);
8146 delay.it_interval.tv_sec =
8147 delay.it_value.tv_sec = time / 1000;
8148 delay.it_interval.tv_usec =
8149 delay.it_value.tv_usec = (time % 1000) * 1000;
8150 setitimer(ITIMER_REAL, &delay, NULL);
8151 while (frameWaiting) pause();
8152 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8153 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8154 setitimer(ITIMER_REAL, &delay, NULL);
8164 XSync(xDisplay, False);
8166 usleep(time * 1000);
8171 /* Convert board position to corner of screen rect and color */
8174 ScreenSquare(column, row, pt, color)
8175 int column; int row; XPoint * pt; int * color;
8178 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8179 pt->y = lineGap + row * (squareSize + lineGap);
8181 pt->x = lineGap + column * (squareSize + lineGap);
8182 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8184 *color = SquareColor(row, column);
8187 /* Convert window coords to square */
8190 BoardSquare(x, y, column, row)
8191 int x; int y; int * column; int * row;
8193 *column = EventToSquare(x, BOARD_WIDTH);
8194 if (flipView && *column >= 0)
8195 *column = BOARD_WIDTH - 1 - *column;
8196 *row = EventToSquare(y, BOARD_HEIGHT);
8197 if (!flipView && *row >= 0)
8198 *row = BOARD_HEIGHT - 1 - *row;
8203 #undef Max /* just in case */
8205 #define Max(a, b) ((a) > (b) ? (a) : (b))
8206 #define Min(a, b) ((a) < (b) ? (a) : (b))
8209 SetRect(rect, x, y, width, height)
8210 XRectangle * rect; int x; int y; int width; int height;
8214 rect->width = width;
8215 rect->height = height;
8218 /* Test if two frames overlap. If they do, return
8219 intersection rect within old and location of
8220 that rect within new. */
8223 Intersect(old, new, size, area, pt)
8224 XPoint * old; XPoint * new;
8225 int size; XRectangle * area; XPoint * pt;
8227 if (old->x > new->x + size || new->x > old->x + size ||
8228 old->y > new->y + size || new->y > old->y + size) {
8231 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8232 size - abs(old->x - new->x), size - abs(old->y - new->y));
8233 pt->x = Max(old->x - new->x, 0);
8234 pt->y = Max(old->y - new->y, 0);
8239 /* For two overlapping frames, return the rect(s)
8240 in the old that do not intersect with the new. */
8243 CalcUpdateRects(old, new, size, update, nUpdates)
8244 XPoint * old; XPoint * new; int size;
8245 XRectangle update[]; int * nUpdates;
8249 /* If old = new (shouldn't happen) then nothing to draw */
8250 if (old->x == new->x && old->y == new->y) {
8254 /* Work out what bits overlap. Since we know the rects
8255 are the same size we don't need a full intersect calc. */
8257 /* Top or bottom edge? */
8258 if (new->y > old->y) {
8259 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8261 } else if (old->y > new->y) {
8262 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8263 size, old->y - new->y);
8266 /* Left or right edge - don't overlap any update calculated above. */
8267 if (new->x > old->x) {
8268 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8269 new->x - old->x, size - abs(new->y - old->y));
8271 } else if (old->x > new->x) {
8272 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8273 old->x - new->x, size - abs(new->y - old->y));
8280 /* Generate a series of frame coords from start->mid->finish.
8281 The movement rate doubles until the half way point is
8282 reached, then halves back down to the final destination,
8283 which gives a nice slow in/out effect. The algorithmn
8284 may seem to generate too many intermediates for short
8285 moves, but remember that the purpose is to attract the
8286 viewers attention to the piece about to be moved and
8287 then to where it ends up. Too few frames would be less
8291 Tween(start, mid, finish, factor, frames, nFrames)
8292 XPoint * start; XPoint * mid;
8293 XPoint * finish; int factor;
8294 XPoint frames[]; int * nFrames;
8296 int fraction, n, count;
8300 /* Slow in, stepping 1/16th, then 1/8th, ... */
8302 for (n = 0; n < factor; n++)
8304 for (n = 0; n < factor; n++) {
8305 frames[count].x = start->x + (mid->x - start->x) / fraction;
8306 frames[count].y = start->y + (mid->y - start->y) / fraction;
8308 fraction = fraction / 2;
8312 frames[count] = *mid;
8315 /* Slow out, stepping 1/2, then 1/4, ... */
8317 for (n = 0; n < factor; n++) {
8318 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8319 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8321 fraction = fraction * 2;
8326 /* Draw a piece on the screen without disturbing what's there */
8329 SelectGCMask(piece, clip, outline, mask)
8330 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8334 /* Bitmap for piece being moved. */
8335 if (appData.monoMode) {
8336 *mask = *pieceToSolid(piece);
8337 } else if (useImages) {
8339 *mask = xpmMask[piece];
8341 *mask = ximMaskPm[piece];
8344 *mask = *pieceToSolid(piece);
8347 /* GC for piece being moved. Square color doesn't matter, but
8348 since it gets modified we make a copy of the original. */
8350 if (appData.monoMode)
8355 if (appData.monoMode)
8360 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8362 /* Outline only used in mono mode and is not modified */
8364 *outline = bwPieceGC;
8366 *outline = wbPieceGC;
8370 OverlayPiece(piece, clip, outline, dest)
8371 ChessSquare piece; GC clip; GC outline; Drawable dest;
8376 /* Draw solid rectangle which will be clipped to shape of piece */
8377 XFillRectangle(xDisplay, dest, clip,
8378 0, 0, squareSize, squareSize);
8379 if (appData.monoMode)
8380 /* Also draw outline in contrasting color for black
8381 on black / white on white cases */
8382 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8383 0, 0, squareSize, squareSize, 0, 0, 1);
8385 /* Copy the piece */
8390 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8392 0, 0, squareSize, squareSize,
8397 /* Animate the movement of a single piece */
8400 BeginAnimation(anim, piece, startColor, start)
8408 /* The old buffer is initialised with the start square (empty) */
8409 BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8410 anim->prevFrame = *start;
8412 /* The piece will be drawn using its own bitmap as a matte */
8413 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8414 XSetClipMask(xDisplay, anim->pieceGC, mask);
8418 AnimationFrame(anim, frame, piece)
8423 XRectangle updates[4];
8428 /* Save what we are about to draw into the new buffer */
8429 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8430 frame->x, frame->y, squareSize, squareSize,
8433 /* Erase bits of the previous frame */
8434 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8435 /* Where the new frame overlapped the previous,
8436 the contents in newBuf are wrong. */
8437 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8438 overlap.x, overlap.y,
8439 overlap.width, overlap.height,
8441 /* Repaint the areas in the old that don't overlap new */
8442 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8443 for (i = 0; i < count; i++)
8444 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8445 updates[i].x - anim->prevFrame.x,
8446 updates[i].y - anim->prevFrame.y,
8447 updates[i].width, updates[i].height,
8448 updates[i].x, updates[i].y);
8450 /* Easy when no overlap */
8451 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8452 0, 0, squareSize, squareSize,
8453 anim->prevFrame.x, anim->prevFrame.y);
8456 /* Save this frame for next time round */
8457 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8458 0, 0, squareSize, squareSize,
8460 anim->prevFrame = *frame;
8462 /* Draw piece over original screen contents, not current,
8463 and copy entire rect. Wipes out overlapping piece images. */
8464 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8465 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8466 0, 0, squareSize, squareSize,
8467 frame->x, frame->y);
8471 EndAnimation (anim, finish)
8475 XRectangle updates[4];
8480 /* The main code will redraw the final square, so we
8481 only need to erase the bits that don't overlap. */
8482 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8483 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8484 for (i = 0; i < count; i++)
8485 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8486 updates[i].x - anim->prevFrame.x,
8487 updates[i].y - anim->prevFrame.y,
8488 updates[i].width, updates[i].height,
8489 updates[i].x, updates[i].y);
8491 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8492 0, 0, squareSize, squareSize,
8493 anim->prevFrame.x, anim->prevFrame.y);
8498 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8500 ChessSquare piece; int startColor;
8501 XPoint * start; XPoint * finish;
8502 XPoint frames[]; int nFrames;
8506 BeginAnimation(anim, piece, startColor, start);
8507 for (n = 0; n < nFrames; n++) {
8508 AnimationFrame(anim, &(frames[n]), piece);
8509 FrameDelay(appData.animSpeed);
8511 EndAnimation(anim, finish);
8514 /* Main control logic for deciding what to animate and how */
8517 AnimateMove(board, fromX, fromY, toX, toY)
8526 XPoint start, finish, mid;
8527 XPoint frames[kFactor * 2 + 1];
8528 int nFrames, startColor, endColor;
8530 /* Are we animating? */
8531 if (!appData.animate || appData.blindfold)
8534 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8535 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8536 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8538 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8539 piece = board[fromY][fromX];
8540 if (piece >= EmptySquare) return;
8545 hop = (piece == WhiteKnight || piece == BlackKnight);
8548 if (appData.debugMode) {
8549 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8550 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8551 piece, fromX, fromY, toX, toY); }
8553 ScreenSquare(fromX, fromY, &start, &startColor);
8554 ScreenSquare(toX, toY, &finish, &endColor);
8557 /* Knight: make diagonal movement then straight */
8558 if (abs(toY - fromY) < abs(toX - fromX)) {
8559 mid.x = start.x + (finish.x - start.x) / 2;
8563 mid.y = start.y + (finish.y - start.y) / 2;
8566 mid.x = start.x + (finish.x - start.x) / 2;
8567 mid.y = start.y + (finish.y - start.y) / 2;
8570 /* Don't use as many frames for very short moves */
8571 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8572 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8574 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8575 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8577 /* Be sure end square is redrawn */
8578 damage[toY][toX] = True;
8582 DragPieceBegin(x, y)
8585 int boardX, boardY, color;
8588 /* Are we animating? */
8589 if (!appData.animateDragging || appData.blindfold)
8592 /* Figure out which square we start in and the
8593 mouse position relative to top left corner. */
8594 BoardSquare(x, y, &boardX, &boardY);
8595 player.startBoardX = boardX;
8596 player.startBoardY = boardY;
8597 ScreenSquare(boardX, boardY, &corner, &color);
8598 player.startSquare = corner;
8599 player.startColor = color;
8600 /* As soon as we start dragging, the piece will jump slightly to
8601 be centered over the mouse pointer. */
8602 player.mouseDelta.x = squareSize/2;
8603 player.mouseDelta.y = squareSize/2;
8604 /* Initialise animation */
8605 player.dragPiece = PieceForSquare(boardX, boardY);
8607 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8608 player.dragActive = True;
8609 BeginAnimation(&player, player.dragPiece, color, &corner);
8610 /* Mark this square as needing to be redrawn. Note that
8611 we don't remove the piece though, since logically (ie
8612 as seen by opponent) the move hasn't been made yet. */
8613 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8614 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8615 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8616 corner.x, corner.y, squareSize, squareSize,
8617 0, 0); // [HGM] zh: unstack in stead of grab
8618 damage[boardY][boardX] = True;
8620 player.dragActive = False;
8630 /* Are we animating? */
8631 if (!appData.animateDragging || appData.blindfold)
8635 if (! player.dragActive)
8637 /* Move piece, maintaining same relative position
8638 of mouse within square */
8639 corner.x = x - player.mouseDelta.x;
8640 corner.y = y - player.mouseDelta.y;
8641 AnimationFrame(&player, &corner, player.dragPiece);
8643 if (appData.highlightDragging) {
8645 BoardSquare(x, y, &boardX, &boardY);
8646 SetHighlights(fromX, fromY, boardX, boardY);
8655 int boardX, boardY, color;
8658 /* Are we animating? */
8659 if (!appData.animateDragging || appData.blindfold)
8663 if (! player.dragActive)
8665 /* Last frame in sequence is square piece is
8666 placed on, which may not match mouse exactly. */
8667 BoardSquare(x, y, &boardX, &boardY);
8668 ScreenSquare(boardX, boardY, &corner, &color);
8669 EndAnimation(&player, &corner);
8671 /* Be sure end square is redrawn */
8672 damage[boardY][boardX] = True;
8674 /* This prevents weird things happening with fast successive
8675 clicks which on my Sun at least can cause motion events
8676 without corresponding press/release. */
8677 player.dragActive = False;
8680 /* Handle expose event while piece being dragged */
8685 if (!player.dragActive || appData.blindfold)
8688 /* What we're doing: logically, the move hasn't been made yet,
8689 so the piece is still in it's original square. But visually
8690 it's being dragged around the board. So we erase the square
8691 that the piece is on and draw it at the last known drag point. */
8692 BlankSquare(player.startSquare.x, player.startSquare.y,
8693 player.startColor, EmptySquare, xBoardWindow);
8694 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8695 damage[player.startBoardY][player.startBoardX] = TRUE;
8698 #include <sys/ioctl.h>
8699 int get_term_width()
8701 int fd, default_width;
8704 default_width = 79; // this is FICS default anyway...
8706 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8708 if (!ioctl(fd, TIOCGSIZE, &win))
8709 default_width = win.ts_cols;
8710 #elif defined(TIOCGWINSZ)
8712 if (!ioctl(fd, TIOCGWINSZ, &win))
8713 default_width = win.ws_col;
8715 return default_width;
8718 void update_ics_width()
8720 static int old_width = 0;
8721 int new_width = get_term_width();
8723 if (old_width != new_width)
8724 ics_printf("set width %d\n", new_width);
8725 old_width = new_width;
8728 void NotifyFrontendLogin()