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 { "ReloadGameProc", ReloadGameProc },
854 { "LoadPositionProc", LoadPositionProc },
855 { "LoadNextPositionProc", LoadNextPositionProc },
856 { "LoadPrevPositionProc", LoadPrevPositionProc },
857 { "ReloadPositionProc", ReloadPositionProc },
858 { "CopyPositionProc", CopyPositionProc },
859 { "PastePositionProc", PastePositionProc },
860 { "CopyGameProc", CopyGameProc },
861 { "PasteGameProc", PasteGameProc },
862 { "SaveGameProc", SaveGameProc },
863 { "SavePositionProc", SavePositionProc },
864 { "MailMoveProc", MailMoveProc },
865 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
866 { "QuitProc", QuitProc },
867 { "MachineWhiteProc", MachineWhiteProc },
868 { "MachineBlackProc", MachineBlackProc },
869 { "AnalysisModeProc", AnalyzeModeProc },
870 { "AnalyzeFileProc", AnalyzeFileProc },
871 { "TwoMachinesProc", TwoMachinesProc },
872 { "IcsClientProc", IcsClientProc },
873 { "EditGameProc", EditGameProc },
874 { "EditPositionProc", EditPositionProc },
875 { "TrainingProc", EditPositionProc },
876 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
877 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
878 { "ShowGameListProc", ShowGameListProc },
879 { "ShowMoveListProc", HistoryShowProc},
880 { "EditTagsProc", EditCommentProc },
881 { "EditCommentProc", EditCommentProc },
882 { "IcsAlarmProc", IcsAlarmProc },
883 { "IcsInputBoxProc", IcsInputBoxProc },
884 { "PauseProc", PauseProc },
885 { "AcceptProc", AcceptProc },
886 { "DeclineProc", DeclineProc },
887 { "RematchProc", RematchProc },
888 { "CallFlagProc", CallFlagProc },
889 { "DrawProc", DrawProc },
890 { "AdjournProc", AdjournProc },
891 { "AbortProc", AbortProc },
892 { "ResignProc", ResignProc },
893 { "AdjuWhiteProc", AdjuWhiteProc },
894 { "AdjuBlackProc", AdjuBlackProc },
895 { "AdjuDrawProc", AdjuDrawProc },
896 { "EnterKeyProc", EnterKeyProc },
897 { "StopObservingProc", StopObservingProc },
898 { "StopExaminingProc", StopExaminingProc },
899 { "BackwardProc", BackwardProc },
900 { "ForwardProc", ForwardProc },
901 { "ToStartProc", ToStartProc },
902 { "ToEndProc", ToEndProc },
903 { "RevertProc", RevertProc },
904 { "TruncateGameProc", TruncateGameProc },
905 { "MoveNowProc", MoveNowProc },
906 { "RetractMoveProc", RetractMoveProc },
907 { "AlwaysQueenProc", AlwaysQueenProc },
908 { "AnimateDraggingProc", AnimateDraggingProc },
909 { "AnimateMovingProc", AnimateMovingProc },
910 { "AutoflagProc", AutoflagProc },
911 { "AutoflipProc", AutoflipProc },
912 { "AutobsProc", AutobsProc },
913 { "AutoraiseProc", AutoraiseProc },
914 { "AutosaveProc", AutosaveProc },
915 { "BlindfoldProc", BlindfoldProc },
916 { "FlashMovesProc", FlashMovesProc },
917 { "FlipViewProc", FlipViewProc },
918 { "GetMoveListProc", GetMoveListProc },
920 { "HighlightDraggingProc", HighlightDraggingProc },
922 { "HighlightLastMoveProc", HighlightLastMoveProc },
923 { "IcsAlarmProc", IcsAlarmProc },
924 { "MoveSoundProc", MoveSoundProc },
925 { "OldSaveStyleProc", OldSaveStyleProc },
926 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
927 { "PonderNextMoveProc", PonderNextMoveProc },
928 { "PopupExitMessageProc", PopupExitMessageProc },
929 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
930 { "PremoveProc", PremoveProc },
931 { "QuietPlayProc", QuietPlayProc },
932 { "ShowCoordsProc", ShowCoordsProc },
933 { "ShowThinkingProc", ShowThinkingProc },
934 { "HideThinkingProc", HideThinkingProc },
935 { "TestLegalityProc", TestLegalityProc },
936 { "SaveSettingsProc", SaveSettingsProc },
937 { "SaveOnExitProc", SaveOnExitProc },
938 { "InfoProc", InfoProc },
939 { "ManProc", ManProc },
940 { "HintProc", HintProc },
941 { "BookProc", BookProc },
942 { "AboutGameProc", AboutGameProc },
943 { "AboutProc", AboutProc },
944 { "DebugProc", DebugProc },
945 { "NothingProc", NothingProc },
946 { "CommentPopDown", (XtActionProc) CommentPopDown },
947 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
948 { "TagsPopDown", (XtActionProc) TagsPopDown },
949 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
950 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
951 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
952 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
953 { "GameListPopDown", (XtActionProc) GameListPopDown },
954 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
955 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
956 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
957 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
958 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
959 { "EnginePopDown", (XtActionProc) EnginePopDown },
960 { "UciPopDown", (XtActionProc) UciPopDown },
961 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
962 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
963 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
964 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
967 char globalTranslations[] =
968 ":<Key>R: ResignProc() \n \
969 :<Key>r: ResetProc() \n \
970 :<Key>g: LoadGameProc() \n \
971 :<Key>N: LoadNextGameProc() \n \
972 :<Key>P: LoadPrevGameProc() \n \
973 :<Key>Q: QuitProc() \n \
974 :<Key>F: ToEndProc() \n \
975 :<Key>f: ForwardProc() \n \
976 :<Key>B: ToStartProc() \n \
977 :<Key>b: BackwardProc() \n \
978 :<Key>p: PauseProc() \n \
979 :<Key>d: DrawProc() \n \
980 :<Key>t: CallFlagProc() \n \
981 :<Key>i: Iconify() \n \
982 :<Key>c: Iconify() \n \
983 :<Key>v: FlipViewProc() \n \
984 <KeyDown>Control_L: BackwardProc() \n \
985 <KeyUp>Control_L: ForwardProc() \n \
986 <KeyDown>Control_R: BackwardProc() \n \
987 <KeyUp>Control_R: ForwardProc() \n \
988 Shift<Key>1: AskQuestionProc(\"Direct command\",\
989 \"Send to chess program:\",,1) \n \
990 Shift<Key>2: AskQuestionProc(\"Direct command\",\
991 \"Send to second chess program:\",,2) \n";
993 char boardTranslations[] =
994 "<Btn1Down>: HandleUserMove() \n \
995 <Btn1Up>: HandleUserMove() \n \
996 <Btn1Motion>: AnimateUserMove() \n \
997 <Btn3Motion>: HandlePV() \n \
998 <Btn3Up>: UnLoadPV() \n \
999 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1000 PieceMenuPopup(menuB) \n \
1001 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1002 PieceMenuPopup(menuW) \n \
1003 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1004 PieceMenuPopup(menuW) \n \
1005 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1006 PieceMenuPopup(menuB) \n";
1008 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1009 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1011 char ICSInputTranslations[] =
1012 "<Key>Return: EnterKeyProc() \n";
1014 String xboardResources[] = {
1015 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1016 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1017 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1022 /* Max possible square size */
1023 #define MAXSQSIZE 256
1025 static int xpm_avail[MAXSQSIZE];
1027 #ifdef HAVE_DIR_STRUCT
1029 /* Extract piece size from filename */
1031 xpm_getsize(name, len, ext)
1042 if ((p=strchr(name, '.')) == NULL ||
1043 StrCaseCmp(p+1, ext) != 0)
1049 while (*p && isdigit(*p))
1056 /* Setup xpm_avail */
1058 xpm_getavail(dirname, ext)
1066 for (i=0; i<MAXSQSIZE; ++i)
1069 if (appData.debugMode)
1070 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1072 dir = opendir(dirname);
1075 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1076 programName, dirname);
1080 while ((ent=readdir(dir)) != NULL) {
1081 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1082 if (i > 0 && i < MAXSQSIZE)
1092 xpm_print_avail(fp, ext)
1098 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1099 for (i=1; i<MAXSQSIZE; ++i) {
1105 /* Return XPM piecesize closest to size */
1107 xpm_closest_to(dirname, size, ext)
1113 int sm_diff = MAXSQSIZE;
1117 xpm_getavail(dirname, ext);
1119 if (appData.debugMode)
1120 xpm_print_avail(stderr, ext);
1122 for (i=1; i<MAXSQSIZE; ++i) {
1125 diff = (diff<0) ? -diff : diff;
1126 if (diff < sm_diff) {
1134 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1140 #else /* !HAVE_DIR_STRUCT */
1141 /* If we are on a system without a DIR struct, we can't
1142 read the directory, so we can't collect a list of
1143 filenames, etc., so we can't do any size-fitting. */
1145 xpm_closest_to(dirname, size, ext)
1150 fprintf(stderr, _("\
1151 Warning: No DIR structure found on this system --\n\
1152 Unable to autosize for XPM/XIM pieces.\n\
1153 Please report this error to frankm@hiwaay.net.\n\
1154 Include system type & operating system in message.\n"));
1157 #endif /* HAVE_DIR_STRUCT */
1159 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1160 "magenta", "cyan", "white" };
1164 TextColors textColors[(int)NColorClasses];
1166 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1168 parse_color(str, which)
1172 char *p, buf[100], *d;
1175 if (strlen(str) > 99) /* watch bounds on buf */
1180 for (i=0; i<which; ++i) {
1187 /* Could be looking at something like:
1189 .. in which case we want to stop on a comma also */
1190 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1194 return -1; /* Use default for empty field */
1197 if (which == 2 || isdigit(*p))
1200 while (*p && isalpha(*p))
1205 for (i=0; i<8; ++i) {
1206 if (!StrCaseCmp(buf, cnames[i]))
1207 return which? (i+40) : (i+30);
1209 if (!StrCaseCmp(buf, "default")) return -1;
1211 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1216 parse_cpair(cc, str)
1220 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1221 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1226 /* bg and attr are optional */
1227 textColors[(int)cc].bg = parse_color(str, 1);
1228 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1229 textColors[(int)cc].attr = 0;
1235 /* Arrange to catch delete-window events */
1236 Atom wm_delete_window;
1238 CatchDeleteWindow(Widget w, String procname)
1241 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1242 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1243 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1250 XtSetArg(args[0], XtNiconic, False);
1251 XtSetValues(shellWidget, args, 1);
1253 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1256 //---------------------------------------------------------------------------------------------------------
1257 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1260 #define CW_USEDEFAULT (1<<31)
1261 #define ICS_TEXT_MENU_SIZE 90
1262 #define DEBUG_FILE "xboard.debug"
1263 #define SetCurrentDirectory chdir
1264 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1268 // these two must some day move to frontend.h, when they are implemented
1269 Boolean GameListIsUp();
1271 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1274 // front-end part of option handling
1276 // [HGM] This platform-dependent table provides the location for storing the color info
1277 extern char *crWhite, * crBlack;
1281 &appData.whitePieceColor,
1282 &appData.blackPieceColor,
1283 &appData.lightSquareColor,
1284 &appData.darkSquareColor,
1285 &appData.highlightSquareColor,
1286 &appData.premoveHighlightColor,
1299 ParseFont(char *name, int number)
1300 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1302 case 0: // CLOCK_FONT
1303 appData.clockFont = strdup(name);
1305 case 1: // MESSAGE_FONT
1306 appData.font = strdup(name);
1308 case 2: // COORD_FONT
1309 appData.coordFont = strdup(name);
1318 { // only 2 fonts currently
1319 appData.clockFont = CLOCK_FONT_NAME;
1320 appData.coordFont = COORD_FONT_NAME;
1321 appData.font = DEFAULT_FONT_NAME;
1326 { // no-op, until we identify the code for this already in XBoard and move it here
1330 ParseColor(int n, char *name)
1331 { // in XBoard, just copy the color-name string
1332 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1336 ParseTextAttribs(ColorClass cc, char *s)
1338 (&appData.colorShout)[cc] = strdup(s);
1342 ParseBoardSize(void *addr, char *name)
1344 appData.boardSize = strdup(name);
1349 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1353 SetCommPortDefaults()
1354 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1357 // [HGM] args: these three cases taken out to stay in front-end
1359 SaveFontArg(FILE *f, ArgDescriptor *ad)
1362 switch((int)ad->argLoc) {
1363 case 0: // CLOCK_FONT
1364 name = appData.clockFont;
1366 case 1: // MESSAGE_FONT
1367 name = appData.font;
1369 case 2: // COORD_FONT
1370 name = appData.coordFont;
1375 // Do not save fonts for now, as the saved font would be board-size specific
1376 // and not suitable for a re-start at another board size
1377 // fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, name);
1382 { // nothing to do, as the sounds are at all times represented by their text-string names already
1386 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1387 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1388 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1392 SaveColor(FILE *f, ArgDescriptor *ad)
1393 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1394 if(colorVariable[(int)ad->argLoc])
1395 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1399 SaveBoardSize(FILE *f, char *name, void *addr)
1400 { // wrapper to shield back-end from BoardSize & sizeInfo
1401 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1405 ParseCommPortSettings(char *s)
1406 { // no such option in XBoard (yet)
1409 extern Widget engineOutputShell;
1410 extern Widget tagsShell, editTagsShell;
1412 GetActualPlacement(Widget wg, WindowPlacement *wp)
1422 XtSetArg(args[i], XtNx, &x); i++;
1423 XtSetArg(args[i], XtNy, &y); i++;
1424 XtSetArg(args[i], XtNwidth, &w); i++;
1425 XtSetArg(args[i], XtNheight, &h); i++;
1426 XtGetValues(wg, args, i);
1435 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1436 // In XBoard this will have to wait until awareness of window parameters is implemented
1437 GetActualPlacement(shellWidget, &wpMain);
1438 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1439 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1440 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1441 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1442 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1443 else GetActualPlacement(editShell, &wpComment);
1444 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1445 else GetActualPlacement(editTagsShell, &wpTags);
1449 PrintCommPortSettings(FILE *f, char *name)
1450 { // This option does not exist in XBoard
1454 MySearchPath(char *installDir, char *name, char *fullname)
1455 { // just append installDir and name. Perhaps ExpandPath should be used here?
1456 name = ExpandPathName(name);
1457 if(name && name[0] == '/') strcpy(fullname, name); else {
1458 sprintf(fullname, "%s%c%s", installDir, '/', name);
1464 MyGetFullPathName(char *name, char *fullname)
1465 { // should use ExpandPath?
1466 name = ExpandPathName(name);
1467 strcpy(fullname, name);
1472 EnsureOnScreen(int *x, int *y, int minX, int minY)
1479 { // [HGM] args: allows testing if main window is realized from back-end
1480 return xBoardWindow != 0;
1484 PopUpStartupDialog()
1485 { // start menu not implemented in XBoard
1488 ConvertToLine(int argc, char **argv)
1490 static char line[128*1024], buf[1024];
1494 for(i=1; i<argc; i++) {
1495 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1496 && argv[i][0] != '{' )
1497 sprintf(buf, "{%s} ", argv[i]);
1498 else sprintf(buf, "%s ", argv[i]);
1501 line[strlen(line)-1] = NULLCHAR;
1505 //--------------------------------------------------------------------------------------------
1508 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1510 #define BoardSize int
1511 void InitDrawingSizes(BoardSize boardSize, int flags)
1512 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1513 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1515 XtGeometryResult gres;
1518 if(!formWidget) return;
1521 * Enable shell resizing.
1523 shellArgs[0].value = (XtArgVal) &w;
1524 shellArgs[1].value = (XtArgVal) &h;
1525 XtGetValues(shellWidget, shellArgs, 2);
1527 shellArgs[4].value = 2*w; shellArgs[2].value = 10;
1528 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1529 XtSetValues(shellWidget, &shellArgs[2], 4);
1531 XtSetArg(args[0], XtNdefaultDistance, &sep);
1532 XtGetValues(formWidget, args, 1);
1534 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1535 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1538 XtSetArg(args[0], XtNwidth, boardWidth);
1539 XtSetArg(args[1], XtNheight, boardHeight);
1540 XtSetValues(boardWidget, args, 2);
1542 timerWidth = (boardWidth - sep) / 2;
1543 XtSetArg(args[0], XtNwidth, timerWidth);
1544 XtSetValues(whiteTimerWidget, args, 1);
1545 XtSetValues(blackTimerWidget, args, 1);
1547 XawFormDoLayout(formWidget, False);
1549 if (appData.titleInWindow) {
1551 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1552 XtSetArg(args[i], XtNheight, &h); i++;
1553 XtGetValues(titleWidget, args, i);
1555 w = boardWidth - 2*bor;
1557 XtSetArg(args[0], XtNwidth, &w);
1558 XtGetValues(menuBarWidget, args, 1);
1559 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1562 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1563 if (gres != XtGeometryYes && appData.debugMode) {
1565 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1566 programName, gres, w, h, wr, hr);
1570 XawFormDoLayout(formWidget, True);
1573 * Inhibit shell resizing.
1575 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW;
1576 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1577 shellArgs[4].value = shellArgs[2].value = w;
1578 shellArgs[5].value = shellArgs[3].value = h;
1579 XtSetValues(shellWidget, &shellArgs[0], 6);
1581 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1584 for(i=0; i<4; i++) {
1586 for(p=0; p<=(int)WhiteKing; p++)
1587 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1588 if(gameInfo.variant == VariantShogi) {
1589 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1590 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1591 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1592 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1593 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1596 if(gameInfo.variant == VariantGothic) {
1597 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1601 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1602 for(p=0; p<=(int)WhiteKing; p++)
1603 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1604 if(gameInfo.variant == VariantShogi) {
1605 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1606 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1607 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1608 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1609 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1612 if(gameInfo.variant == VariantGothic) {
1613 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1619 for(i=0; i<2; i++) {
1621 for(p=0; p<=(int)WhiteKing; p++)
1622 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1623 if(gameInfo.variant == VariantShogi) {
1624 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1625 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1626 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1627 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1628 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1631 if(gameInfo.variant == VariantGothic) {
1632 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1643 void EscapeExpand(char *p, char *q)
1644 { // [HGM] initstring: routine to shape up string arguments
1645 while(*p++ = *q++) if(p[-1] == '\\')
1647 case 'n': p[-1] = '\n'; break;
1648 case 'r': p[-1] = '\r'; break;
1649 case 't': p[-1] = '\t'; break;
1650 case '\\': p[-1] = '\\'; break;
1651 case 0: *p = 0; return;
1652 default: p[-1] = q[-1]; break;
1661 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1662 XSetWindowAttributes window_attributes;
1664 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1665 XrmValue vFrom, vTo;
1666 XtGeometryResult gres;
1669 int forceMono = False;
1671 srandom(time(0)); // [HGM] book: make random truly random
1673 setbuf(stdout, NULL);
1674 setbuf(stderr, NULL);
1677 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1678 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1682 programName = strrchr(argv[0], '/');
1683 if (programName == NULL)
1684 programName = argv[0];
1689 XtSetLanguageProc(NULL, NULL, NULL);
1690 bindtextdomain(PACKAGE, LOCALEDIR);
1691 textdomain(PACKAGE);
1695 XtAppInitialize(&appContext, "XBoard", shellOptions,
1696 XtNumber(shellOptions),
1697 &argc, argv, xboardResources, NULL, 0);
1698 appData.boardSize = "";
1699 InitAppData(ConvertToLine(argc, argv));
1701 if (p == NULL) p = "/tmp";
1702 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1703 gameCopyFilename = (char*) malloc(i);
1704 gamePasteFilename = (char*) malloc(i);
1705 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1706 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1708 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1709 clientResources, XtNumber(clientResources),
1712 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1713 static char buf[MSG_SIZ];
1714 EscapeExpand(buf, appData.initString);
1715 appData.initString = strdup(buf);
1716 EscapeExpand(buf, appData.secondInitString);
1717 appData.secondInitString = strdup(buf);
1718 EscapeExpand(buf, appData.firstComputerString);
1719 appData.firstComputerString = strdup(buf);
1720 EscapeExpand(buf, appData.secondComputerString);
1721 appData.secondComputerString = strdup(buf);
1724 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1727 if (chdir(chessDir) != 0) {
1728 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1734 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1735 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1736 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1737 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1740 setbuf(debugFP, NULL);
1743 /* [HGM,HR] make sure board size is acceptable */
1744 if(appData.NrFiles > BOARD_FILES ||
1745 appData.NrRanks > BOARD_RANKS )
1746 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1749 /* This feature does not work; animation needs a rewrite */
1750 appData.highlightDragging = FALSE;
1754 xDisplay = XtDisplay(shellWidget);
1755 xScreen = DefaultScreen(xDisplay);
1756 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1758 gameInfo.variant = StringToVariant(appData.variant);
1759 InitPosition(FALSE);
1762 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1764 if (isdigit(appData.boardSize[0])) {
1765 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1766 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1767 &fontPxlSize, &smallLayout, &tinyLayout);
1769 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1770 programName, appData.boardSize);
1774 /* Find some defaults; use the nearest known size */
1775 SizeDefaults *szd, *nearest;
1776 int distance = 99999;
1777 nearest = szd = sizeDefaults;
1778 while (szd->name != NULL) {
1779 if (abs(szd->squareSize - squareSize) < distance) {
1781 distance = abs(szd->squareSize - squareSize);
1782 if (distance == 0) break;
1786 if (i < 2) lineGap = nearest->lineGap;
1787 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1788 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1789 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1790 if (i < 6) smallLayout = nearest->smallLayout;
1791 if (i < 7) tinyLayout = nearest->tinyLayout;
1794 SizeDefaults *szd = sizeDefaults;
1795 if (*appData.boardSize == NULLCHAR) {
1796 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1797 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1800 if (szd->name == NULL) szd--;
1801 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1803 while (szd->name != NULL &&
1804 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1805 if (szd->name == NULL) {
1806 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1807 programName, appData.boardSize);
1811 squareSize = szd->squareSize;
1812 lineGap = szd->lineGap;
1813 clockFontPxlSize = szd->clockFontPxlSize;
1814 coordFontPxlSize = szd->coordFontPxlSize;
1815 fontPxlSize = szd->fontPxlSize;
1816 smallLayout = szd->smallLayout;
1817 tinyLayout = szd->tinyLayout;
1820 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1821 if (strlen(appData.pixmapDirectory) > 0) {
1822 p = ExpandPathName(appData.pixmapDirectory);
1824 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1825 appData.pixmapDirectory);
1828 if (appData.debugMode) {
1829 fprintf(stderr, _("\
1830 XBoard square size (hint): %d\n\
1831 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1833 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1834 if (appData.debugMode) {
1835 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1839 /* [HR] height treated separately (hacked) */
1840 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1841 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1842 if (appData.showJail == 1) {
1843 /* Jail on top and bottom */
1844 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1845 XtSetArg(boardArgs[2], XtNheight,
1846 boardHeight + 2*(lineGap + squareSize));
1847 } else if (appData.showJail == 2) {
1849 XtSetArg(boardArgs[1], XtNwidth,
1850 boardWidth + 2*(lineGap + squareSize));
1851 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1854 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1855 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1859 * Determine what fonts to use.
1861 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1862 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1863 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1864 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1865 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1866 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1867 appData.font = FindFont(appData.font, fontPxlSize);
1868 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1869 countFontStruct = XQueryFont(xDisplay, countFontID);
1870 // appData.font = FindFont(appData.font, fontPxlSize);
1872 xdb = XtDatabase(xDisplay);
1873 XrmPutStringResource(&xdb, "*font", appData.font);
1876 * Detect if there are not enough colors available and adapt.
1878 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1879 appData.monoMode = True;
1882 if (!appData.monoMode) {
1883 vFrom.addr = (caddr_t) appData.lightSquareColor;
1884 vFrom.size = strlen(appData.lightSquareColor);
1885 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1886 if (vTo.addr == NULL) {
1887 appData.monoMode = True;
1890 lightSquareColor = *(Pixel *) vTo.addr;
1893 if (!appData.monoMode) {
1894 vFrom.addr = (caddr_t) appData.darkSquareColor;
1895 vFrom.size = strlen(appData.darkSquareColor);
1896 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1897 if (vTo.addr == NULL) {
1898 appData.monoMode = True;
1901 darkSquareColor = *(Pixel *) vTo.addr;
1904 if (!appData.monoMode) {
1905 vFrom.addr = (caddr_t) appData.whitePieceColor;
1906 vFrom.size = strlen(appData.whitePieceColor);
1907 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1908 if (vTo.addr == NULL) {
1909 appData.monoMode = True;
1912 whitePieceColor = *(Pixel *) vTo.addr;
1915 if (!appData.monoMode) {
1916 vFrom.addr = (caddr_t) appData.blackPieceColor;
1917 vFrom.size = strlen(appData.blackPieceColor);
1918 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1919 if (vTo.addr == NULL) {
1920 appData.monoMode = True;
1923 blackPieceColor = *(Pixel *) vTo.addr;
1927 if (!appData.monoMode) {
1928 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1929 vFrom.size = strlen(appData.highlightSquareColor);
1930 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1931 if (vTo.addr == NULL) {
1932 appData.monoMode = True;
1935 highlightSquareColor = *(Pixel *) vTo.addr;
1939 if (!appData.monoMode) {
1940 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1941 vFrom.size = strlen(appData.premoveHighlightColor);
1942 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1943 if (vTo.addr == NULL) {
1944 appData.monoMode = True;
1947 premoveHighlightColor = *(Pixel *) vTo.addr;
1952 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1955 if (appData.bitmapDirectory == NULL ||
1956 appData.bitmapDirectory[0] == NULLCHAR)
1957 appData.bitmapDirectory = DEF_BITMAP_DIR;
1960 if (appData.lowTimeWarning && !appData.monoMode) {
1961 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
1962 vFrom.size = strlen(appData.lowTimeWarningColor);
1963 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1964 if (vTo.addr == NULL)
1965 appData.monoMode = True;
1967 lowTimeWarningColor = *(Pixel *) vTo.addr;
1970 if (appData.monoMode && appData.debugMode) {
1971 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1972 (unsigned long) XWhitePixel(xDisplay, xScreen),
1973 (unsigned long) XBlackPixel(xDisplay, xScreen));
1976 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1977 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1978 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1979 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1980 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1981 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1982 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1983 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1984 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1985 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1987 if (appData.colorize) {
1989 _("%s: can't parse color names; disabling colorization\n"),
1992 appData.colorize = FALSE;
1994 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
1995 textColors[ColorNone].attr = 0;
1997 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2003 layoutName = "tinyLayout";
2004 } else if (smallLayout) {
2005 layoutName = "smallLayout";
2007 layoutName = "normalLayout";
2009 /* Outer layoutWidget is there only to provide a name for use in
2010 resources that depend on the layout style */
2012 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2013 layoutArgs, XtNumber(layoutArgs));
2015 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2016 formArgs, XtNumber(formArgs));
2017 XtSetArg(args[0], XtNdefaultDistance, &sep);
2018 XtGetValues(formWidget, args, 1);
2021 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2022 XtSetArg(args[0], XtNtop, XtChainTop);
2023 XtSetArg(args[1], XtNbottom, XtChainTop);
2024 XtSetArg(args[2], XtNright, XtChainLeft);
2025 XtSetValues(menuBarWidget, args, 3);
2027 widgetList[j++] = whiteTimerWidget =
2028 XtCreateWidget("whiteTime", labelWidgetClass,
2029 formWidget, timerArgs, XtNumber(timerArgs));
2030 XtSetArg(args[0], XtNfont, clockFontStruct);
2031 XtSetArg(args[1], XtNtop, XtChainTop);
2032 XtSetArg(args[2], XtNbottom, XtChainTop);
2033 XtSetValues(whiteTimerWidget, args, 3);
2035 widgetList[j++] = blackTimerWidget =
2036 XtCreateWidget("blackTime", labelWidgetClass,
2037 formWidget, timerArgs, XtNumber(timerArgs));
2038 XtSetArg(args[0], XtNfont, clockFontStruct);
2039 XtSetArg(args[1], XtNtop, XtChainTop);
2040 XtSetArg(args[2], XtNbottom, XtChainTop);
2041 XtSetValues(blackTimerWidget, args, 3);
2043 if (appData.titleInWindow) {
2044 widgetList[j++] = titleWidget =
2045 XtCreateWidget("title", labelWidgetClass, formWidget,
2046 titleArgs, XtNumber(titleArgs));
2047 XtSetArg(args[0], XtNtop, XtChainTop);
2048 XtSetArg(args[1], XtNbottom, XtChainTop);
2049 XtSetValues(titleWidget, args, 2);
2052 if (appData.showButtonBar) {
2053 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2054 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2055 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2056 XtSetArg(args[2], XtNtop, XtChainTop);
2057 XtSetArg(args[3], XtNbottom, XtChainTop);
2058 XtSetValues(buttonBarWidget, args, 4);
2061 widgetList[j++] = messageWidget =
2062 XtCreateWidget("message", labelWidgetClass, formWidget,
2063 messageArgs, XtNumber(messageArgs));
2064 XtSetArg(args[0], XtNtop, XtChainTop);
2065 XtSetArg(args[1], XtNbottom, XtChainTop);
2066 XtSetValues(messageWidget, args, 2);
2068 widgetList[j++] = boardWidget =
2069 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2070 XtNumber(boardArgs));
2072 XtManageChildren(widgetList, j);
2074 timerWidth = (boardWidth - sep) / 2;
2075 XtSetArg(args[0], XtNwidth, timerWidth);
2076 XtSetValues(whiteTimerWidget, args, 1);
2077 XtSetValues(blackTimerWidget, args, 1);
2079 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2080 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2081 XtGetValues(whiteTimerWidget, args, 2);
2083 if (appData.showButtonBar) {
2084 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2085 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2086 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2090 * formWidget uses these constraints but they are stored
2094 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2095 XtSetValues(menuBarWidget, args, i);
2096 if (appData.titleInWindow) {
2099 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2100 XtSetValues(whiteTimerWidget, args, i);
2102 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2103 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2104 XtSetValues(blackTimerWidget, args, i);
2106 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2107 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2108 XtSetValues(titleWidget, args, i);
2110 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2111 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2112 XtSetValues(messageWidget, args, i);
2113 if (appData.showButtonBar) {
2115 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2116 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2117 XtSetValues(buttonBarWidget, args, i);
2121 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2122 XtSetValues(whiteTimerWidget, args, i);
2124 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2125 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2126 XtSetValues(blackTimerWidget, args, i);
2128 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2129 XtSetValues(titleWidget, args, i);
2131 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2132 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2133 XtSetValues(messageWidget, args, i);
2134 if (appData.showButtonBar) {
2136 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2137 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2138 XtSetValues(buttonBarWidget, args, i);
2143 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2144 XtSetValues(whiteTimerWidget, args, i);
2146 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2147 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2148 XtSetValues(blackTimerWidget, args, i);
2150 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2151 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2152 XtSetValues(messageWidget, args, i);
2153 if (appData.showButtonBar) {
2155 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2156 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2157 XtSetValues(buttonBarWidget, args, i);
2161 XtSetArg(args[0], XtNfromVert, messageWidget);
2162 XtSetArg(args[1], XtNtop, XtChainTop);
2163 XtSetArg(args[2], XtNbottom, XtChainBottom);
2164 XtSetArg(args[3], XtNleft, XtChainLeft);
2165 XtSetArg(args[4], XtNright, XtChainRight);
2166 XtSetValues(boardWidget, args, 5);
2168 XtRealizeWidget(shellWidget);
2171 XtSetArg(args[0], XtNx, wpMain.x);
2172 XtSetArg(args[1], XtNy, wpMain.y);
2173 XtSetValues(shellWidget, args, 2);
2177 * Correct the width of the message and title widgets.
2178 * It is not known why some systems need the extra fudge term.
2179 * The value "2" is probably larger than needed.
2181 XawFormDoLayout(formWidget, False);
2183 #define WIDTH_FUDGE 2
2185 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2186 XtSetArg(args[i], XtNheight, &h); i++;
2187 XtGetValues(messageWidget, args, i);
2188 if (appData.showButtonBar) {
2190 XtSetArg(args[i], XtNwidth, &w); i++;
2191 XtGetValues(buttonBarWidget, args, i);
2192 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2194 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2197 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2198 if (gres != XtGeometryYes && appData.debugMode) {
2199 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2200 programName, gres, w, h, wr, hr);
2203 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2204 /* The size used for the child widget in layout lags one resize behind
2205 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2207 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2208 if (gres != XtGeometryYes && appData.debugMode) {
2209 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2210 programName, gres, w, h, wr, hr);
2213 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2214 XtSetArg(args[1], XtNright, XtChainRight);
2215 XtSetValues(messageWidget, args, 2);
2217 if (appData.titleInWindow) {
2219 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2220 XtSetArg(args[i], XtNheight, &h); i++;
2221 XtGetValues(titleWidget, args, i);
2223 w = boardWidth - 2*bor;
2225 XtSetArg(args[0], XtNwidth, &w);
2226 XtGetValues(menuBarWidget, args, 1);
2227 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2230 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2231 if (gres != XtGeometryYes && appData.debugMode) {
2233 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2234 programName, gres, w, h, wr, hr);
2237 XawFormDoLayout(formWidget, True);
2239 xBoardWindow = XtWindow(boardWidget);
2241 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2242 // not need to go into InitDrawingSizes().
2246 * Create X checkmark bitmap and initialize option menu checks.
2248 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2249 checkmark_bits, checkmark_width, checkmark_height);
2250 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2251 if (appData.alwaysPromoteToQueen) {
2252 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2255 if (appData.animateDragging) {
2256 XtSetValues(XtNameToWidget(menuBarWidget,
2257 "menuOptions.Animate Dragging"),
2260 if (appData.animate) {
2261 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2264 if (appData.autoComment) {
2265 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2268 if (appData.autoCallFlag) {
2269 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2272 if (appData.autoFlipView) {
2273 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2276 if (appData.autoObserve) {
2277 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2280 if (appData.autoRaiseBoard) {
2281 XtSetValues(XtNameToWidget(menuBarWidget,
2282 "menuOptions.Auto Raise Board"), args, 1);
2284 if (appData.autoSaveGames) {
2285 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2288 if (appData.saveGameFile[0] != NULLCHAR) {
2289 /* Can't turn this off from menu */
2290 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2292 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2296 if (appData.blindfold) {
2297 XtSetValues(XtNameToWidget(menuBarWidget,
2298 "menuOptions.Blindfold"), args, 1);
2300 if (appData.flashCount > 0) {
2301 XtSetValues(XtNameToWidget(menuBarWidget,
2302 "menuOptions.Flash Moves"),
2305 if (appData.getMoveList) {
2306 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2310 if (appData.highlightDragging) {
2311 XtSetValues(XtNameToWidget(menuBarWidget,
2312 "menuOptions.Highlight Dragging"),
2316 if (appData.highlightLastMove) {
2317 XtSetValues(XtNameToWidget(menuBarWidget,
2318 "menuOptions.Highlight Last Move"),
2321 if (appData.icsAlarm) {
2322 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2325 if (appData.ringBellAfterMoves) {
2326 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2329 if (appData.oldSaveStyle) {
2330 XtSetValues(XtNameToWidget(menuBarWidget,
2331 "menuOptions.Old Save Style"), args, 1);
2333 if (appData.periodicUpdates) {
2334 XtSetValues(XtNameToWidget(menuBarWidget,
2335 "menuOptions.Periodic Updates"), args, 1);
2337 if (appData.ponderNextMove) {
2338 XtSetValues(XtNameToWidget(menuBarWidget,
2339 "menuOptions.Ponder Next Move"), args, 1);
2341 if (appData.popupExitMessage) {
2342 XtSetValues(XtNameToWidget(menuBarWidget,
2343 "menuOptions.Popup Exit Message"), args, 1);
2345 if (appData.popupMoveErrors) {
2346 XtSetValues(XtNameToWidget(menuBarWidget,
2347 "menuOptions.Popup Move Errors"), args, 1);
2349 if (appData.premove) {
2350 XtSetValues(XtNameToWidget(menuBarWidget,
2351 "menuOptions.Premove"), args, 1);
2353 if (appData.quietPlay) {
2354 XtSetValues(XtNameToWidget(menuBarWidget,
2355 "menuOptions.Quiet Play"), args, 1);
2357 if (appData.showCoords) {
2358 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2361 if (appData.hideThinkingFromHuman) {
2362 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2365 if (appData.testLegality) {
2366 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2369 if (saveSettingsOnExit) {
2370 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2377 ReadBitmap(&wIconPixmap, "icon_white.bm",
2378 icon_white_bits, icon_white_width, icon_white_height);
2379 ReadBitmap(&bIconPixmap, "icon_black.bm",
2380 icon_black_bits, icon_black_width, icon_black_height);
2381 iconPixmap = wIconPixmap;
2383 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2384 XtSetValues(shellWidget, args, i);
2387 * Create a cursor for the board widget.
2389 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2390 XChangeWindowAttributes(xDisplay, xBoardWindow,
2391 CWCursor, &window_attributes);
2394 * Inhibit shell resizing.
2396 shellArgs[0].value = (XtArgVal) &w;
2397 shellArgs[1].value = (XtArgVal) &h;
2398 XtGetValues(shellWidget, shellArgs, 2);
2399 shellArgs[4].value = shellArgs[2].value = w;
2400 shellArgs[5].value = shellArgs[3].value = h;
2401 XtSetValues(shellWidget, &shellArgs[2], 4);
2402 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2403 marginH = h - boardHeight;
2405 CatchDeleteWindow(shellWidget, "QuitProc");
2410 if (appData.bitmapDirectory[0] != NULLCHAR) {
2417 /* Create regular pieces */
2418 if (!useImages) CreatePieces();
2423 if (appData.animate || appData.animateDragging)
2426 XtAugmentTranslations(formWidget,
2427 XtParseTranslationTable(globalTranslations));
2428 XtAugmentTranslations(boardWidget,
2429 XtParseTranslationTable(boardTranslations));
2430 XtAugmentTranslations(whiteTimerWidget,
2431 XtParseTranslationTable(whiteTranslations));
2432 XtAugmentTranslations(blackTimerWidget,
2433 XtParseTranslationTable(blackTranslations));
2435 /* Why is the following needed on some versions of X instead
2436 * of a translation? */
2437 XtAddEventHandler(boardWidget, ExposureMask, False,
2438 (XtEventHandler) EventProc, NULL);
2441 /* [AS] Restore layout */
2442 if( wpMoveHistory.visible ) {
2446 if( wpEvalGraph.visible )
2451 if( wpEngineOutput.visible ) {
2452 EngineOutputPopUp();
2457 if (errorExitStatus == -1) {
2458 if (appData.icsActive) {
2459 /* We now wait until we see "login:" from the ICS before
2460 sending the logon script (problems with timestamp otherwise) */
2461 /*ICSInitScript();*/
2462 if (appData.icsInputBox) ICSInputBoxPopUp();
2466 signal(SIGWINCH, TermSizeSigHandler);
2468 signal(SIGINT, IntSigHandler);
2469 signal(SIGTERM, IntSigHandler);
2470 if (*appData.cmailGameName != NULLCHAR) {
2471 signal(SIGUSR1, CmailSigHandler);
2474 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2477 XtAppMainLoop(appContext);
2478 if (appData.debugMode) fclose(debugFP); // [DM] debug
2485 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2486 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2488 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2489 unlink(gameCopyFilename);
2490 unlink(gamePasteFilename);
2493 RETSIGTYPE TermSizeSigHandler(int sig)
2506 CmailSigHandler(sig)
2512 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2514 /* Activate call-back function CmailSigHandlerCallBack() */
2515 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2517 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2521 CmailSigHandlerCallBack(isr, closure, message, count, error)
2529 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2531 /**** end signal code ****/
2541 f = fopen(appData.icsLogon, "r");
2547 strcat(buf, appData.icsLogon);
2548 f = fopen(buf, "r");
2552 ProcessICSInitScript(f);
2559 EditCommentPopDown();
2574 if (!menuBarWidget) return;
2575 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2577 DisplayError("menuStep.Revert", 0);
2579 XtSetSensitive(w, !grey);
2584 SetMenuEnables(enab)
2588 if (!menuBarWidget) return;
2589 while (enab->name != NULL) {
2590 w = XtNameToWidget(menuBarWidget, enab->name);
2592 DisplayError(enab->name, 0);
2594 XtSetSensitive(w, enab->value);
2600 Enables icsEnables[] = {
2601 { "menuFile.Mail Move", False },
2602 { "menuFile.Reload CMail Message", False },
2603 { "menuMode.Machine Black", False },
2604 { "menuMode.Machine White", False },
2605 { "menuMode.Analysis Mode", False },
2606 { "menuMode.Analyze File", False },
2607 { "menuMode.Two Machines", False },
2609 { "menuHelp.Hint", False },
2610 { "menuHelp.Book", False },
2611 { "menuStep.Move Now", False },
2612 { "menuOptions.Periodic Updates", False },
2613 { "menuOptions.Hide Thinking", False },
2614 { "menuOptions.Ponder Next Move", False },
2619 Enables ncpEnables[] = {
2620 { "menuFile.Mail Move", False },
2621 { "menuFile.Reload CMail Message", False },
2622 { "menuMode.Machine White", False },
2623 { "menuMode.Machine Black", False },
2624 { "menuMode.Analysis Mode", False },
2625 { "menuMode.Analyze File", False },
2626 { "menuMode.Two Machines", False },
2627 { "menuMode.ICS Client", False },
2628 { "menuMode.ICS Input Box", False },
2629 { "Action", False },
2630 { "menuStep.Revert", False },
2631 { "menuStep.Move Now", False },
2632 { "menuStep.Retract Move", False },
2633 { "menuOptions.Auto Comment", False },
2634 { "menuOptions.Auto Flag", False },
2635 { "menuOptions.Auto Flip View", False },
2636 { "menuOptions.Auto Observe", False },
2637 { "menuOptions.Auto Raise Board", False },
2638 { "menuOptions.Get Move List", False },
2639 { "menuOptions.ICS Alarm", False },
2640 { "menuOptions.Move Sound", False },
2641 { "menuOptions.Quiet Play", False },
2642 { "menuOptions.Hide Thinking", False },
2643 { "menuOptions.Periodic Updates", False },
2644 { "menuOptions.Ponder Next Move", False },
2645 { "menuHelp.Hint", False },
2646 { "menuHelp.Book", False },
2650 Enables gnuEnables[] = {
2651 { "menuMode.ICS Client", False },
2652 { "menuMode.ICS Input Box", False },
2653 { "menuAction.Accept", False },
2654 { "menuAction.Decline", False },
2655 { "menuAction.Rematch", False },
2656 { "menuAction.Adjourn", False },
2657 { "menuAction.Stop Examining", False },
2658 { "menuAction.Stop Observing", False },
2659 { "menuStep.Revert", False },
2660 { "menuOptions.Auto Comment", False },
2661 { "menuOptions.Auto Observe", False },
2662 { "menuOptions.Auto Raise Board", False },
2663 { "menuOptions.Get Move List", False },
2664 { "menuOptions.Premove", False },
2665 { "menuOptions.Quiet Play", False },
2667 /* The next two options rely on SetCmailMode being called *after* */
2668 /* SetGNUMode so that when GNU is being used to give hints these */
2669 /* menu options are still available */
2671 { "menuFile.Mail Move", False },
2672 { "menuFile.Reload CMail Message", False },
2676 Enables cmailEnables[] = {
2678 { "menuAction.Call Flag", False },
2679 { "menuAction.Draw", True },
2680 { "menuAction.Adjourn", False },
2681 { "menuAction.Abort", False },
2682 { "menuAction.Stop Observing", False },
2683 { "menuAction.Stop Examining", False },
2684 { "menuFile.Mail Move", True },
2685 { "menuFile.Reload CMail Message", True },
2689 Enables trainingOnEnables[] = {
2690 { "menuMode.Edit Comment", False },
2691 { "menuMode.Pause", False },
2692 { "menuStep.Forward", False },
2693 { "menuStep.Backward", False },
2694 { "menuStep.Forward to End", False },
2695 { "menuStep.Back to Start", False },
2696 { "menuStep.Move Now", False },
2697 { "menuStep.Truncate Game", False },
2701 Enables trainingOffEnables[] = {
2702 { "menuMode.Edit Comment", True },
2703 { "menuMode.Pause", True },
2704 { "menuStep.Forward", True },
2705 { "menuStep.Backward", True },
2706 { "menuStep.Forward to End", True },
2707 { "menuStep.Back to Start", True },
2708 { "menuStep.Move Now", True },
2709 { "menuStep.Truncate Game", True },
2713 Enables machineThinkingEnables[] = {
2714 { "menuFile.Load Game", False },
2715 { "menuFile.Load Next Game", False },
2716 { "menuFile.Load Previous Game", False },
2717 { "menuFile.Reload Same Game", False },
2718 { "menuFile.Paste Game", False },
2719 { "menuFile.Load Position", False },
2720 { "menuFile.Load Next Position", False },
2721 { "menuFile.Load Previous Position", False },
2722 { "menuFile.Reload Same Position", False },
2723 { "menuFile.Paste Position", False },
2724 { "menuMode.Machine White", False },
2725 { "menuMode.Machine Black", False },
2726 { "menuMode.Two Machines", False },
2727 { "menuStep.Retract Move", False },
2731 Enables userThinkingEnables[] = {
2732 { "menuFile.Load Game", True },
2733 { "menuFile.Load Next Game", True },
2734 { "menuFile.Load Previous Game", True },
2735 { "menuFile.Reload Same Game", True },
2736 { "menuFile.Paste Game", True },
2737 { "menuFile.Load Position", True },
2738 { "menuFile.Load Next Position", True },
2739 { "menuFile.Load Previous Position", True },
2740 { "menuFile.Reload Same Position", True },
2741 { "menuFile.Paste Position", True },
2742 { "menuMode.Machine White", True },
2743 { "menuMode.Machine Black", True },
2744 { "menuMode.Two Machines", True },
2745 { "menuStep.Retract Move", True },
2751 SetMenuEnables(icsEnables);
2754 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2755 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2762 SetMenuEnables(ncpEnables);
2768 SetMenuEnables(gnuEnables);
2774 SetMenuEnables(cmailEnables);
2780 SetMenuEnables(trainingOnEnables);
2781 if (appData.showButtonBar) {
2782 XtSetSensitive(buttonBarWidget, False);
2788 SetTrainingModeOff()
2790 SetMenuEnables(trainingOffEnables);
2791 if (appData.showButtonBar) {
2792 XtSetSensitive(buttonBarWidget, True);
2797 SetUserThinkingEnables()
2799 if (appData.noChessProgram) return;
2800 SetMenuEnables(userThinkingEnables);
2804 SetMachineThinkingEnables()
2806 if (appData.noChessProgram) return;
2807 SetMenuEnables(machineThinkingEnables);
2809 case MachinePlaysBlack:
2810 case MachinePlaysWhite:
2811 case TwoMachinesPlay:
2812 XtSetSensitive(XtNameToWidget(menuBarWidget,
2813 ModeToWidgetName(gameMode)), True);
2820 #define Abs(n) ((n)<0 ? -(n) : (n))
2823 * Find a font that matches "pattern" that is as close as
2824 * possible to the targetPxlSize. Prefer fonts that are k
2825 * pixels smaller to fonts that are k pixels larger. The
2826 * pattern must be in the X Consortium standard format,
2827 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2828 * The return value should be freed with XtFree when no
2831 char *FindFont(pattern, targetPxlSize)
2835 char **fonts, *p, *best, *scalable, *scalableTail;
2836 int i, j, nfonts, minerr, err, pxlSize;
2839 char **missing_list;
2841 char *def_string, *base_fnt_lst, strInt[3];
2843 XFontStruct **fnt_list;
2845 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2846 sprintf(strInt, "%d", targetPxlSize);
2847 p = strstr(pattern, "--");
2848 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2849 strcat(base_fnt_lst, strInt);
2850 strcat(base_fnt_lst, strchr(p + 2, '-'));
2852 if ((fntSet = XCreateFontSet(xDisplay,
2856 &def_string)) == NULL) {
2858 fprintf(stderr, _("Unable to create font set.\n"));
2862 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2864 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2866 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2867 programName, pattern);
2875 for (i=0; i<nfonts; i++) {
2878 if (*p != '-') continue;
2880 if (*p == NULLCHAR) break;
2881 if (*p++ == '-') j++;
2883 if (j < 7) continue;
2886 scalable = fonts[i];
2889 err = pxlSize - targetPxlSize;
2890 if (Abs(err) < Abs(minerr) ||
2891 (minerr > 0 && err < 0 && -err == minerr)) {
2897 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
2898 /* If the error is too big and there is a scalable font,
2899 use the scalable font. */
2900 int headlen = scalableTail - scalable;
2901 p = (char *) XtMalloc(strlen(scalable) + 10);
2902 while (isdigit(*scalableTail)) scalableTail++;
2903 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
2905 p = (char *) XtMalloc(strlen(best) + 1);
2908 if (appData.debugMode) {
2909 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
2910 pattern, targetPxlSize, p);
2913 if (missing_count > 0)
2914 XFreeStringList(missing_list);
2915 XFreeFontSet(xDisplay, fntSet);
2917 XFreeFontNames(fonts);
2924 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
2925 | GCBackground | GCFunction | GCPlaneMask;
2926 XGCValues gc_values;
2929 gc_values.plane_mask = AllPlanes;
2930 gc_values.line_width = lineGap;
2931 gc_values.line_style = LineSolid;
2932 gc_values.function = GXcopy;
2934 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2935 gc_values.background = XBlackPixel(xDisplay, xScreen);
2936 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2938 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2939 gc_values.background = XWhitePixel(xDisplay, xScreen);
2940 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
2941 XSetFont(xDisplay, coordGC, coordFontID);
2943 // [HGM] make font for holdings counts (white on black0
2944 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2945 gc_values.background = XBlackPixel(xDisplay, xScreen);
2946 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
2947 XSetFont(xDisplay, countGC, countFontID);
2949 if (appData.monoMode) {
2950 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2951 gc_values.background = XWhitePixel(xDisplay, xScreen);
2952 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2954 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2955 gc_values.background = XBlackPixel(xDisplay, xScreen);
2956 lightSquareGC = wbPieceGC
2957 = XtGetGC(shellWidget, value_mask, &gc_values);
2959 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2960 gc_values.background = XWhitePixel(xDisplay, xScreen);
2961 darkSquareGC = bwPieceGC
2962 = XtGetGC(shellWidget, value_mask, &gc_values);
2964 if (DefaultDepth(xDisplay, xScreen) == 1) {
2965 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
2966 gc_values.function = GXcopyInverted;
2967 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
2968 gc_values.function = GXcopy;
2969 if (XBlackPixel(xDisplay, xScreen) == 1) {
2970 bwPieceGC = darkSquareGC;
2971 wbPieceGC = copyInvertedGC;
2973 bwPieceGC = copyInvertedGC;
2974 wbPieceGC = lightSquareGC;
2978 gc_values.foreground = highlightSquareColor;
2979 gc_values.background = highlightSquareColor;
2980 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2982 gc_values.foreground = premoveHighlightColor;
2983 gc_values.background = premoveHighlightColor;
2984 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2986 gc_values.foreground = lightSquareColor;
2987 gc_values.background = darkSquareColor;
2988 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2990 gc_values.foreground = darkSquareColor;
2991 gc_values.background = lightSquareColor;
2992 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2994 gc_values.foreground = jailSquareColor;
2995 gc_values.background = jailSquareColor;
2996 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2998 gc_values.foreground = whitePieceColor;
2999 gc_values.background = darkSquareColor;
3000 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3002 gc_values.foreground = whitePieceColor;
3003 gc_values.background = lightSquareColor;
3004 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3006 gc_values.foreground = whitePieceColor;
3007 gc_values.background = jailSquareColor;
3008 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3010 gc_values.foreground = blackPieceColor;
3011 gc_values.background = darkSquareColor;
3012 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3014 gc_values.foreground = blackPieceColor;
3015 gc_values.background = lightSquareColor;
3016 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3018 gc_values.foreground = blackPieceColor;
3019 gc_values.background = jailSquareColor;
3020 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3024 void loadXIM(xim, xmask, filename, dest, mask)
3037 fp = fopen(filename, "rb");
3039 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3046 for (y=0; y<h; ++y) {
3047 for (x=0; x<h; ++x) {
3052 XPutPixel(xim, x, y, blackPieceColor);
3054 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3057 XPutPixel(xim, x, y, darkSquareColor);
3059 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3062 XPutPixel(xim, x, y, whitePieceColor);
3064 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3067 XPutPixel(xim, x, y, lightSquareColor);
3069 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3075 /* create Pixmap of piece */
3076 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3078 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3081 /* create Pixmap of clipmask
3082 Note: We assume the white/black pieces have the same
3083 outline, so we make only 6 masks. This is okay
3084 since the XPM clipmask routines do the same. */
3086 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3088 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3091 /* now create the 1-bit version */
3092 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3095 values.foreground = 1;
3096 values.background = 0;
3098 /* Don't use XtGetGC, not read only */
3099 maskGC = XCreateGC(xDisplay, *mask,
3100 GCForeground | GCBackground, &values);
3101 XCopyPlane(xDisplay, temp, *mask, maskGC,
3102 0, 0, squareSize, squareSize, 0, 0, 1);
3103 XFreePixmap(xDisplay, temp);
3108 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3110 void CreateXIMPieces()
3115 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3120 /* The XSynchronize calls were copied from CreatePieces.
3121 Not sure if needed, but can't hurt */
3122 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3125 /* temp needed by loadXIM() */
3126 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3127 0, 0, ss, ss, AllPlanes, XYPixmap);
3129 if (strlen(appData.pixmapDirectory) == 0) {
3133 if (appData.monoMode) {
3134 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3138 fprintf(stderr, _("\nLoading XIMs...\n"));
3140 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3141 fprintf(stderr, "%d", piece+1);
3142 for (kind=0; kind<4; kind++) {
3143 fprintf(stderr, ".");
3144 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3145 ExpandPathName(appData.pixmapDirectory),
3146 piece <= (int) WhiteKing ? "" : "w",
3147 pieceBitmapNames[piece],
3149 ximPieceBitmap[kind][piece] =
3150 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3151 0, 0, ss, ss, AllPlanes, XYPixmap);
3152 if (appData.debugMode)
3153 fprintf(stderr, _("(File:%s:) "), buf);
3154 loadXIM(ximPieceBitmap[kind][piece],
3156 &(xpmPieceBitmap2[kind][piece]),
3157 &(ximMaskPm2[piece]));
3158 if(piece <= (int)WhiteKing)
3159 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3161 fprintf(stderr," ");
3163 /* Load light and dark squares */
3164 /* If the LSQ and DSQ pieces don't exist, we will
3165 draw them with solid squares. */
3166 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3167 if (access(buf, 0) != 0) {
3171 fprintf(stderr, _("light square "));
3173 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3174 0, 0, ss, ss, AllPlanes, XYPixmap);
3175 if (appData.debugMode)
3176 fprintf(stderr, _("(File:%s:) "), buf);
3178 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3179 fprintf(stderr, _("dark square "));
3180 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3181 ExpandPathName(appData.pixmapDirectory), ss);
3182 if (appData.debugMode)
3183 fprintf(stderr, _("(File:%s:) "), buf);
3185 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3186 0, 0, ss, ss, AllPlanes, XYPixmap);
3187 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3188 xpmJailSquare = xpmLightSquare;
3190 fprintf(stderr, _("Done.\n"));
3192 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3196 void CreateXPMPieces()
3200 u_int ss = squareSize;
3202 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3203 XpmColorSymbol symbols[4];
3205 /* The XSynchronize calls were copied from CreatePieces.
3206 Not sure if needed, but can't hurt */
3207 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3209 /* Setup translations so piece colors match square colors */
3210 symbols[0].name = "light_piece";
3211 symbols[0].value = appData.whitePieceColor;
3212 symbols[1].name = "dark_piece";
3213 symbols[1].value = appData.blackPieceColor;
3214 symbols[2].name = "light_square";
3215 symbols[2].value = appData.lightSquareColor;
3216 symbols[3].name = "dark_square";
3217 symbols[3].value = appData.darkSquareColor;
3219 attr.valuemask = XpmColorSymbols;
3220 attr.colorsymbols = symbols;
3221 attr.numsymbols = 4;
3223 if (appData.monoMode) {
3224 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3228 if (strlen(appData.pixmapDirectory) == 0) {
3229 XpmPieces* pieces = builtInXpms;
3232 while (pieces->size != squareSize && pieces->size) pieces++;
3233 if (!pieces->size) {
3234 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3237 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3238 for (kind=0; kind<4; kind++) {
3240 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3241 pieces->xpm[piece][kind],
3242 &(xpmPieceBitmap2[kind][piece]),
3243 NULL, &attr)) != 0) {
3244 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3248 if(piece <= (int) WhiteKing)
3249 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3253 xpmJailSquare = xpmLightSquare;
3257 fprintf(stderr, _("\nLoading XPMs...\n"));
3260 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3261 fprintf(stderr, "%d ", piece+1);
3262 for (kind=0; kind<4; kind++) {
3263 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3264 ExpandPathName(appData.pixmapDirectory),
3265 piece > (int) WhiteKing ? "w" : "",
3266 pieceBitmapNames[piece],
3268 if (appData.debugMode) {
3269 fprintf(stderr, _("(File:%s:) "), buf);
3271 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3272 &(xpmPieceBitmap2[kind][piece]),
3273 NULL, &attr)) != 0) {
3274 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3275 // [HGM] missing: read of unorthodox piece failed; substitute King.
3276 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3277 ExpandPathName(appData.pixmapDirectory),
3279 if (appData.debugMode) {
3280 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3282 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3283 &(xpmPieceBitmap2[kind][piece]),
3287 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3292 if(piece <= (int) WhiteKing)
3293 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3296 /* Load light and dark squares */
3297 /* If the LSQ and DSQ pieces don't exist, we will
3298 draw them with solid squares. */
3299 fprintf(stderr, _("light square "));
3300 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3301 if (access(buf, 0) != 0) {
3305 if (appData.debugMode)
3306 fprintf(stderr, _("(File:%s:) "), buf);
3308 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3309 &xpmLightSquare, NULL, &attr)) != 0) {
3310 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3313 fprintf(stderr, _("dark square "));
3314 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3315 ExpandPathName(appData.pixmapDirectory), ss);
3316 if (appData.debugMode) {
3317 fprintf(stderr, _("(File:%s:) "), buf);
3319 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3320 &xpmDarkSquare, NULL, &attr)) != 0) {
3321 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3325 xpmJailSquare = xpmLightSquare;
3326 fprintf(stderr, _("Done.\n"));
3328 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3331 #endif /* HAVE_LIBXPM */
3334 /* No built-in bitmaps */
3339 u_int ss = squareSize;
3341 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3344 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3345 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3346 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3347 pieceBitmapNames[piece],
3348 ss, kind == SOLID ? 's' : 'o');
3349 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3350 if(piece <= (int)WhiteKing)
3351 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3355 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3359 /* With built-in bitmaps */
3362 BuiltInBits* bib = builtInBits;
3365 u_int ss = squareSize;
3367 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3370 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3372 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3373 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3374 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3375 pieceBitmapNames[piece],
3376 ss, kind == SOLID ? 's' : 'o');
3377 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3378 bib->bits[kind][piece], ss, ss);
3379 if(piece <= (int)WhiteKing)
3380 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3384 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3389 void ReadBitmap(pm, name, bits, wreq, hreq)
3392 unsigned char bits[];
3398 char msg[MSG_SIZ], fullname[MSG_SIZ];
3400 if (*appData.bitmapDirectory != NULLCHAR) {
3401 strcpy(fullname, appData.bitmapDirectory);
3402 strcat(fullname, "/");
3403 strcat(fullname, name);
3404 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3405 &w, &h, pm, &x_hot, &y_hot);
3406 fprintf(stderr, "load %s\n", name);
3407 if (errcode != BitmapSuccess) {
3409 case BitmapOpenFailed:
3410 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3412 case BitmapFileInvalid:
3413 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3415 case BitmapNoMemory:
3416 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3420 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3424 fprintf(stderr, _("%s: %s...using built-in\n"),
3426 } else if (w != wreq || h != hreq) {
3428 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3429 programName, fullname, w, h, wreq, hreq);
3435 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3444 if (lineGap == 0) return;
3446 /* [HR] Split this into 2 loops for non-square boards. */
3448 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3449 gridSegments[i].x1 = 0;
3450 gridSegments[i].x2 =
3451 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3452 gridSegments[i].y1 = gridSegments[i].y2
3453 = lineGap / 2 + (i * (squareSize + lineGap));
3456 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3457 gridSegments[j + i].y1 = 0;
3458 gridSegments[j + i].y2 =
3459 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3460 gridSegments[j + i].x1 = gridSegments[j + i].x2
3461 = lineGap / 2 + (j * (squareSize + lineGap));
3465 static void MenuBarSelect(w, addr, index)
3470 XtActionProc proc = (XtActionProc) addr;
3472 (proc)(NULL, NULL, NULL, NULL);
3475 void CreateMenuBarPopup(parent, name, mb)
3485 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3488 XtSetArg(args[j], XtNleftMargin, 20); j++;
3489 XtSetArg(args[j], XtNrightMargin, 20); j++;
3491 while (mi->string != NULL) {
3492 if (strcmp(mi->string, "----") == 0) {
3493 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3496 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3497 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3499 XtAddCallback(entry, XtNcallback,
3500 (XtCallbackProc) MenuBarSelect,
3501 (caddr_t) mi->proc);
3507 Widget CreateMenuBar(mb)
3511 Widget anchor, menuBar;
3513 char menuName[MSG_SIZ];
3516 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3517 XtSetArg(args[j], XtNvSpace, 0); j++;
3518 XtSetArg(args[j], XtNborderWidth, 0); j++;
3519 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3520 formWidget, args, j);
3522 while (mb->name != NULL) {
3523 strcpy(menuName, "menu");
3524 strcat(menuName, mb->name);
3526 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3529 shortName[0] = _(mb->name)[0];
3530 shortName[1] = NULLCHAR;
3531 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3534 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3537 XtSetArg(args[j], XtNborderWidth, 0); j++;
3538 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3540 CreateMenuBarPopup(menuBar, menuName, mb);
3546 Widget CreateButtonBar(mi)
3550 Widget button, buttonBar;
3554 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3556 XtSetArg(args[j], XtNhSpace, 0); j++;
3558 XtSetArg(args[j], XtNborderWidth, 0); j++;
3559 XtSetArg(args[j], XtNvSpace, 0); j++;
3560 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3561 formWidget, args, j);
3563 while (mi->string != NULL) {
3566 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3567 XtSetArg(args[j], XtNborderWidth, 0); j++;
3569 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3570 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3571 buttonBar, args, j);
3572 XtAddCallback(button, XtNcallback,
3573 (XtCallbackProc) MenuBarSelect,
3574 (caddr_t) mi->proc);
3581 CreatePieceMenu(name, color)
3588 ChessSquare selection;
3590 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3591 boardWidget, args, 0);
3593 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3594 String item = pieceMenuStrings[color][i];
3596 if (strcmp(item, "----") == 0) {
3597 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3600 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3601 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3603 selection = pieceMenuTranslation[color][i];
3604 XtAddCallback(entry, XtNcallback,
3605 (XtCallbackProc) PieceMenuSelect,
3606 (caddr_t) selection);
3607 if (selection == WhitePawn || selection == BlackPawn) {
3608 XtSetArg(args[0], XtNpopupOnEntry, entry);
3609 XtSetValues(menu, args, 1);
3622 ChessSquare selection;
3624 whitePieceMenu = CreatePieceMenu("menuW", 0);
3625 blackPieceMenu = CreatePieceMenu("menuB", 1);
3627 XtRegisterGrabAction(PieceMenuPopup, True,
3628 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3629 GrabModeAsync, GrabModeAsync);
3631 XtSetArg(args[0], XtNlabel, _("Drop"));
3632 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3633 boardWidget, args, 1);
3634 for (i = 0; i < DROP_MENU_SIZE; i++) {
3635 String item = dropMenuStrings[i];
3637 if (strcmp(item, "----") == 0) {
3638 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3641 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3642 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3644 selection = dropMenuTranslation[i];
3645 XtAddCallback(entry, XtNcallback,
3646 (XtCallbackProc) DropMenuSelect,
3647 (caddr_t) selection);
3652 void SetupDropMenu()
3660 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3661 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3662 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3663 dmEnables[i].piece);
3664 XtSetSensitive(entry, p != NULL || !appData.testLegality
3665 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3666 && !appData.icsActive));
3668 while (p && *p++ == dmEnables[i].piece) count++;
3669 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3671 XtSetArg(args[j], XtNlabel, label); j++;
3672 XtSetValues(entry, args, j);
3676 void PieceMenuPopup(w, event, params, num_params)
3680 Cardinal *num_params;
3684 if (event->type != ButtonRelease) UnLoadPV(); // [HGM] pv
3685 if (event->type != ButtonPress) return;
3686 if (errorUp) ErrorPopDown();
3690 whichMenu = params[0];
3693 if(!appData.icsEngineAnalyze) return;
3694 case IcsPlayingWhite:
3695 case IcsPlayingBlack:
3696 if(!appData.zippyPlay) goto noZip;
3699 case MachinePlaysWhite:
3700 case MachinePlaysBlack:
3701 case TwoMachinesPlay: // [HGM] pv: use for showing PV
3702 if (!appData.dropMenu) {
3703 LoadPV(event->xbutton.x, event->xbutton.y);
3706 if(gameMode == TwoMachinesPlay || gameMode == AnalyzeMode ||
3707 gameMode == AnalyzeFile || gameMode == IcsObserving) return;
3710 if (!appData.dropMenu || appData.testLegality &&
3711 gameInfo.variant != VariantBughouse &&
3712 gameInfo.variant != VariantCrazyhouse) return;
3714 whichMenu = "menuD";
3720 if (((pmFromX = EventToSquare(event->xbutton.x, BOARD_WIDTH)) < 0) ||
3721 ((pmFromY = EventToSquare(event->xbutton.y, BOARD_HEIGHT)) < 0)) {
3722 pmFromX = pmFromY = -1;
3726 pmFromX = BOARD_WIDTH - 1 - pmFromX;
3728 pmFromY = BOARD_HEIGHT - 1 - pmFromY;
3730 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3733 static void PieceMenuSelect(w, piece, junk)
3738 if (pmFromX < 0 || pmFromY < 0) return;
3739 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3742 static void DropMenuSelect(w, piece, junk)
3747 if (pmFromX < 0 || pmFromY < 0) return;
3748 DropMenuEvent(piece, pmFromX, pmFromY);
3751 void WhiteClock(w, event, prms, nprms)
3757 if (gameMode == EditPosition || gameMode == IcsExamining) {
3758 SetWhiteToPlayEvent();
3759 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3764 void BlackClock(w, event, prms, nprms)
3770 if (gameMode == EditPosition || gameMode == IcsExamining) {
3771 SetBlackToPlayEvent();
3772 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3779 * If the user selects on a border boundary, return -1; if off the board,
3780 * return -2. Otherwise map the event coordinate to the square.
3782 int EventToSquare(x, limit)
3790 if ((x % (squareSize + lineGap)) >= squareSize)
3792 x /= (squareSize + lineGap);
3798 static void do_flash_delay(msec)
3804 static void drawHighlight(file, rank, gc)
3810 if (lineGap == 0 || appData.blindfold) return;
3813 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3814 (squareSize + lineGap);
3815 y = lineGap/2 + rank * (squareSize + lineGap);
3817 x = lineGap/2 + file * (squareSize + lineGap);
3818 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3819 (squareSize + lineGap);
3822 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3823 squareSize+lineGap, squareSize+lineGap);
3826 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3827 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3830 SetHighlights(fromX, fromY, toX, toY)
3831 int fromX, fromY, toX, toY;
3833 if (hi1X != fromX || hi1Y != fromY) {
3834 if (hi1X >= 0 && hi1Y >= 0) {
3835 drawHighlight(hi1X, hi1Y, lineGC);
3837 if (fromX >= 0 && fromY >= 0) {
3838 drawHighlight(fromX, fromY, highlineGC);
3841 if (hi2X != toX || hi2Y != toY) {
3842 if (hi2X >= 0 && hi2Y >= 0) {
3843 drawHighlight(hi2X, hi2Y, lineGC);
3845 if (toX >= 0 && toY >= 0) {
3846 drawHighlight(toX, toY, highlineGC);
3858 SetHighlights(-1, -1, -1, -1);
3863 SetPremoveHighlights(fromX, fromY, toX, toY)
3864 int fromX, fromY, toX, toY;
3866 if (pm1X != fromX || pm1Y != fromY) {
3867 if (pm1X >= 0 && pm1Y >= 0) {
3868 drawHighlight(pm1X, pm1Y, lineGC);
3870 if (fromX >= 0 && fromY >= 0) {
3871 drawHighlight(fromX, fromY, prelineGC);
3874 if (pm2X != toX || pm2Y != toY) {
3875 if (pm2X >= 0 && pm2Y >= 0) {
3876 drawHighlight(pm2X, pm2Y, lineGC);
3878 if (toX >= 0 && toY >= 0) {
3879 drawHighlight(toX, toY, prelineGC);
3889 ClearPremoveHighlights()
3891 SetPremoveHighlights(-1, -1, -1, -1);
3894 static void BlankSquare(x, y, color, piece, dest)
3899 if (useImages && useImageSqs) {
3903 pm = xpmLightSquare;
3908 case 2: /* neutral */
3913 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
3914 squareSize, squareSize, x, y);
3924 case 2: /* neutral */
3929 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
3934 I split out the routines to draw a piece so that I could
3935 make a generic flash routine.
3937 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
3939 int square_color, x, y;
3942 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3943 switch (square_color) {
3945 case 2: /* neutral */
3947 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3948 ? *pieceToOutline(piece)
3949 : *pieceToSolid(piece),
3950 dest, bwPieceGC, 0, 0,
3951 squareSize, squareSize, x, y);
3954 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3955 ? *pieceToSolid(piece)
3956 : *pieceToOutline(piece),
3957 dest, wbPieceGC, 0, 0,
3958 squareSize, squareSize, x, y);
3963 static void monoDrawPiece(piece, square_color, x, y, dest)
3965 int square_color, x, y;
3968 switch (square_color) {
3970 case 2: /* neutral */
3972 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3973 ? *pieceToOutline(piece)
3974 : *pieceToSolid(piece),
3975 dest, bwPieceGC, 0, 0,
3976 squareSize, squareSize, x, y, 1);
3979 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3980 ? *pieceToSolid(piece)
3981 : *pieceToOutline(piece),
3982 dest, wbPieceGC, 0, 0,
3983 squareSize, squareSize, x, y, 1);
3988 static void colorDrawPiece(piece, square_color, x, y, dest)
3990 int square_color, x, y;
3993 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
3994 switch (square_color) {
3996 XCopyPlane(xDisplay, *pieceToSolid(piece),
3997 dest, (int) piece < (int) BlackPawn
3998 ? wlPieceGC : blPieceGC, 0, 0,
3999 squareSize, squareSize, x, y, 1);
4002 XCopyPlane(xDisplay, *pieceToSolid(piece),
4003 dest, (int) piece < (int) BlackPawn
4004 ? wdPieceGC : bdPieceGC, 0, 0,
4005 squareSize, squareSize, x, y, 1);
4007 case 2: /* neutral */
4009 XCopyPlane(xDisplay, *pieceToSolid(piece),
4010 dest, (int) piece < (int) BlackPawn
4011 ? wjPieceGC : bjPieceGC, 0, 0,
4012 squareSize, squareSize, x, y, 1);
4017 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4019 int square_color, x, y;
4024 switch (square_color) {
4026 case 2: /* neutral */
4028 if ((int)piece < (int) BlackPawn) {
4036 if ((int)piece < (int) BlackPawn) {
4044 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4045 dest, wlPieceGC, 0, 0,
4046 squareSize, squareSize, x, y);
4049 typedef void (*DrawFunc)();
4051 DrawFunc ChooseDrawFunc()
4053 if (appData.monoMode) {
4054 if (DefaultDepth(xDisplay, xScreen) == 1) {
4055 return monoDrawPiece_1bit;
4057 return monoDrawPiece;
4061 return colorDrawPieceImage;
4063 return colorDrawPiece;
4067 /* [HR] determine square color depending on chess variant. */
4068 static int SquareColor(row, column)
4073 if (gameInfo.variant == VariantXiangqi) {
4074 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4076 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4078 } else if (row <= 4) {
4084 square_color = ((column + row) % 2) == 1;
4087 /* [hgm] holdings: next line makes all holdings squares light */
4088 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4090 return square_color;
4093 void DrawSquare(row, column, piece, do_flash)
4094 int row, column, do_flash;
4097 int square_color, x, y, direction, font_ascent, font_descent;
4100 XCharStruct overall;
4104 /* Calculate delay in milliseconds (2-delays per complete flash) */
4105 flash_delay = 500 / appData.flashRate;
4108 x = lineGap + ((BOARD_WIDTH-1)-column) *
4109 (squareSize + lineGap);
4110 y = lineGap + row * (squareSize + lineGap);
4112 x = lineGap + column * (squareSize + lineGap);
4113 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4114 (squareSize + lineGap);
4117 square_color = SquareColor(row, column);
4119 if ( // [HGM] holdings: blank out area between board and holdings
4120 column == BOARD_LEFT-1 || column == BOARD_RGHT
4121 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4122 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4123 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4125 // [HGM] print piece counts next to holdings
4126 string[1] = NULLCHAR;
4127 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4128 string[0] = '0' + piece;
4129 XTextExtents(countFontStruct, string, 1, &direction,
4130 &font_ascent, &font_descent, &overall);
4131 if (appData.monoMode) {
4132 XDrawImageString(xDisplay, xBoardWindow, countGC,
4133 x + squareSize - overall.width - 2,
4134 y + font_ascent + 1, string, 1);
4136 XDrawString(xDisplay, xBoardWindow, countGC,
4137 x + squareSize - overall.width - 2,
4138 y + font_ascent + 1, string, 1);
4141 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4142 string[0] = '0' + piece;
4143 XTextExtents(countFontStruct, string, 1, &direction,
4144 &font_ascent, &font_descent, &overall);
4145 if (appData.monoMode) {
4146 XDrawImageString(xDisplay, xBoardWindow, countGC,
4147 x + 2, y + font_ascent + 1, string, 1);
4149 XDrawString(xDisplay, xBoardWindow, countGC,
4150 x + 2, y + font_ascent + 1, string, 1);
4154 if (piece == EmptySquare || appData.blindfold) {
4155 BlankSquare(x, y, square_color, piece, xBoardWindow);
4157 drawfunc = ChooseDrawFunc();
4158 if (do_flash && appData.flashCount > 0) {
4159 for (i=0; i<appData.flashCount; ++i) {
4161 drawfunc(piece, square_color, x, y, xBoardWindow);
4162 XSync(xDisplay, False);
4163 do_flash_delay(flash_delay);
4165 BlankSquare(x, y, square_color, piece, xBoardWindow);
4166 XSync(xDisplay, False);
4167 do_flash_delay(flash_delay);
4170 drawfunc(piece, square_color, x, y, xBoardWindow);
4174 string[1] = NULLCHAR;
4175 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4176 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4177 string[0] = 'a' + column - BOARD_LEFT;
4178 XTextExtents(coordFontStruct, string, 1, &direction,
4179 &font_ascent, &font_descent, &overall);
4180 if (appData.monoMode) {
4181 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4182 x + squareSize - overall.width - 2,
4183 y + squareSize - font_descent - 1, string, 1);
4185 XDrawString(xDisplay, xBoardWindow, coordGC,
4186 x + squareSize - overall.width - 2,
4187 y + squareSize - font_descent - 1, string, 1);
4190 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4191 string[0] = ONE + row;
4192 XTextExtents(coordFontStruct, string, 1, &direction,
4193 &font_ascent, &font_descent, &overall);
4194 if (appData.monoMode) {
4195 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4196 x + 2, y + font_ascent + 1, string, 1);
4198 XDrawString(xDisplay, xBoardWindow, coordGC,
4199 x + 2, y + font_ascent + 1, string, 1);
4202 if(marker[row][column]) {
4203 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4204 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4209 /* Why is this needed on some versions of X? */
4210 void EventProc(widget, unused, event)
4215 if (!XtIsRealized(widget))
4218 switch (event->type) {
4220 if (event->xexpose.count > 0) return; /* no clipping is done */
4221 XDrawPosition(widget, True, NULL);
4229 void DrawPosition(fullRedraw, board)
4230 /*Boolean*/int fullRedraw;
4233 XDrawPosition(boardWidget, fullRedraw, board);
4236 /* Returns 1 if there are "too many" differences between b1 and b2
4237 (i.e. more than 1 move was made) */
4238 static int too_many_diffs(b1, b2)
4244 for (i=0; i<BOARD_HEIGHT; ++i) {
4245 for (j=0; j<BOARD_WIDTH; ++j) {
4246 if (b1[i][j] != b2[i][j]) {
4247 if (++c > 4) /* Castling causes 4 diffs */
4256 /* Matrix describing castling maneuvers */
4257 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4258 static int castling_matrix[4][5] = {
4259 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4260 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4261 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4262 { 7, 7, 4, 5, 6 } /* 0-0, black */
4265 /* Checks whether castling occurred. If it did, *rrow and *rcol
4266 are set to the destination (row,col) of the rook that moved.
4268 Returns 1 if castling occurred, 0 if not.
4270 Note: Only handles a max of 1 castling move, so be sure
4271 to call too_many_diffs() first.
4273 static int check_castle_draw(newb, oldb, rrow, rcol)
4280 /* For each type of castling... */
4281 for (i=0; i<4; ++i) {
4282 r = castling_matrix[i];
4284 /* Check the 4 squares involved in the castling move */
4286 for (j=1; j<=4; ++j) {
4287 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4294 /* All 4 changed, so it must be a castling move */
4303 static int damage[BOARD_RANKS][BOARD_FILES];
4306 * event handler for redrawing the board
4308 void XDrawPosition(w, repaint, board)
4310 /*Boolean*/int repaint;
4314 static int lastFlipView = 0;
4315 static int lastBoardValid = 0;
4316 static Board lastBoard;
4320 if (board == NULL) {
4321 if (!lastBoardValid) return;
4324 if (!lastBoardValid || lastFlipView != flipView) {
4325 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4326 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4331 * It would be simpler to clear the window with XClearWindow()
4332 * but this causes a very distracting flicker.
4335 if (!repaint && lastBoardValid && lastFlipView == flipView) {
4337 /* If too much changes (begin observing new game, etc.), don't
4339 do_flash = too_many_diffs(board, lastBoard) ? 0 : 1;
4341 /* Special check for castling so we don't flash both the king
4342 and the rook (just flash the king). */
4344 if (check_castle_draw(board, lastBoard, &rrow, &rcol)) {
4345 /* Draw rook with NO flashing. King will be drawn flashing later */
4346 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4347 lastBoard[rrow][rcol] = board[rrow][rcol];
4351 /* First pass -- Draw (newly) empty squares and repair damage.
4352 This prevents you from having a piece show up twice while it
4353 is flashing on its new square */
4354 for (i = 0; i < BOARD_HEIGHT; i++)
4355 for (j = 0; j < BOARD_WIDTH; j++)
4356 if ((board[i][j] != lastBoard[i][j] && board[i][j] == EmptySquare)
4358 DrawSquare(i, j, board[i][j], 0);
4359 damage[i][j] = False;
4362 /* Second pass -- Draw piece(s) in new position and flash them */
4363 for (i = 0; i < BOARD_HEIGHT; i++)
4364 for (j = 0; j < BOARD_WIDTH; j++)
4365 if (board[i][j] != lastBoard[i][j]) {
4366 DrawSquare(i, j, board[i][j], do_flash);
4370 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4371 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4373 for (i = 0; i < BOARD_HEIGHT; i++)
4374 for (j = 0; j < BOARD_WIDTH; j++) {
4375 DrawSquare(i, j, board[i][j], 0);
4376 damage[i][j] = False;
4380 CopyBoard(lastBoard, board);
4382 lastFlipView = flipView;
4384 /* Draw highlights */
4385 if (pm1X >= 0 && pm1Y >= 0) {
4386 drawHighlight(pm1X, pm1Y, prelineGC);
4388 if (pm2X >= 0 && pm2Y >= 0) {
4389 drawHighlight(pm2X, pm2Y, prelineGC);
4391 if (hi1X >= 0 && hi1Y >= 0) {
4392 drawHighlight(hi1X, hi1Y, highlineGC);
4394 if (hi2X >= 0 && hi2Y >= 0) {
4395 drawHighlight(hi2X, hi2Y, highlineGC);
4398 /* If piece being dragged around board, must redraw that too */
4401 XSync(xDisplay, False);
4406 * event handler for redrawing the board
4408 void DrawPositionProc(w, event, prms, nprms)
4414 XDrawPosition(w, True, NULL);
4419 * event handler for parsing user moves
4421 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4422 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4423 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4424 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4425 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4426 // and at the end FinishMove() to perform the move after optional promotion popups.
4427 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4428 void HandleUserMove(w, event, prms, nprms)
4434 if (w != boardWidget || errorExitStatus != -1) return;
4437 if (event->type == ButtonPress) {
4438 XtPopdown(promotionShell);
4439 XtDestroyWidget(promotionShell);
4440 promotionUp = False;
4448 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4449 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4450 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4453 void AnimateUserMove (Widget w, XEvent * event,
4454 String * params, Cardinal * nParams)
4456 DragPieceMove(event->xmotion.x, event->xmotion.y);
4459 void HandlePV (Widget w, XEvent * event,
4460 String * params, Cardinal * nParams)
4461 { // [HGM] pv: walk PV
4462 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4465 Widget CommentCreate(name, text, mutable, callback, lines)
4467 int /*Boolean*/ mutable;
4468 XtCallbackProc callback;
4472 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4477 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4478 XtGetValues(boardWidget, args, j);
4481 XtSetArg(args[j], XtNresizable, True); j++;
4484 XtCreatePopupShell(name, topLevelShellWidgetClass,
4485 shellWidget, args, j);
4488 XtCreatePopupShell(name, transientShellWidgetClass,
4489 shellWidget, args, j);
4492 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4493 layoutArgs, XtNumber(layoutArgs));
4495 XtCreateManagedWidget("form", formWidgetClass, layout,
4496 formArgs, XtNumber(formArgs));
4500 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4501 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4503 XtSetArg(args[j], XtNstring, text); j++;
4504 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4505 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4506 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4507 XtSetArg(args[j], XtNright, XtChainRight); j++;
4508 XtSetArg(args[j], XtNresizable, True); j++;
4509 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4510 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4511 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4512 XtSetArg(args[j], XtNautoFill, True); j++;
4513 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4515 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4519 XtSetArg(args[j], XtNfromVert, edit); j++;
4520 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4521 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4522 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4523 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4525 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4526 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4529 XtSetArg(args[j], XtNfromVert, edit); j++;
4530 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4531 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4532 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4533 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4534 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4536 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4537 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4540 XtSetArg(args[j], XtNfromVert, edit); j++;
4541 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4542 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4543 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4544 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4545 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4547 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4548 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4551 XtSetArg(args[j], XtNfromVert, edit); j++;
4552 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4553 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4554 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4555 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4557 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4558 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4561 XtSetArg(args[j], XtNfromVert, edit); j++;
4562 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4563 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4564 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4565 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4566 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4568 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4569 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4572 XtRealizeWidget(shell);
4574 if (commentX == -1) {
4577 Dimension pw_height;
4578 Dimension ew_height;
4581 XtSetArg(args[j], XtNheight, &ew_height); j++;
4582 XtGetValues(edit, args, j);
4585 XtSetArg(args[j], XtNheight, &pw_height); j++;
4586 XtGetValues(shell, args, j);
4587 commentH = pw_height + (lines - 1) * ew_height;
4588 commentW = bw_width - 16;
4590 XSync(xDisplay, False);
4592 /* This code seems to tickle an X bug if it is executed too soon
4593 after xboard starts up. The coordinates get transformed as if
4594 the main window was positioned at (0, 0).
4596 XtTranslateCoords(shellWidget,
4597 (bw_width - commentW) / 2, 0 - commentH / 2,
4598 &commentX, &commentY);
4600 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4601 RootWindowOfScreen(XtScreen(shellWidget)),
4602 (bw_width - commentW) / 2, 0 - commentH / 2,
4607 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4610 if(wpComment.width > 0) {
4611 commentX = wpComment.x;
4612 commentY = wpComment.y;
4613 commentW = wpComment.width;
4614 commentH = wpComment.height;
4618 XtSetArg(args[j], XtNheight, commentH); j++;
4619 XtSetArg(args[j], XtNwidth, commentW); j++;
4620 XtSetArg(args[j], XtNx, commentX); j++;
4621 XtSetArg(args[j], XtNy, commentY); j++;
4622 XtSetValues(shell, args, j);
4623 XtSetKeyboardFocus(shell, edit);
4628 /* Used for analysis window and ICS input window */
4629 Widget MiscCreate(name, text, mutable, callback, lines)
4631 int /*Boolean*/ mutable;
4632 XtCallbackProc callback;
4636 Widget shell, layout, form, edit;
4638 Dimension bw_width, pw_height, ew_height, w, h;
4644 XtSetArg(args[j], XtNresizable, True); j++;
4647 XtCreatePopupShell(name, topLevelShellWidgetClass,
4648 shellWidget, args, j);
4651 XtCreatePopupShell(name, transientShellWidgetClass,
4652 shellWidget, args, j);
4655 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4656 layoutArgs, XtNumber(layoutArgs));
4658 XtCreateManagedWidget("form", formWidgetClass, layout,
4659 formArgs, XtNumber(formArgs));
4663 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4664 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4666 XtSetArg(args[j], XtNstring, text); j++;
4667 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4668 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4669 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4670 XtSetArg(args[j], XtNright, XtChainRight); j++;
4671 XtSetArg(args[j], XtNresizable, True); j++;
4672 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4673 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4674 XtSetArg(args[j], XtNautoFill, True); j++;
4675 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4677 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4679 XtRealizeWidget(shell);
4682 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4683 XtGetValues(boardWidget, args, j);
4686 XtSetArg(args[j], XtNheight, &ew_height); j++;
4687 XtGetValues(edit, args, j);
4690 XtSetArg(args[j], XtNheight, &pw_height); j++;
4691 XtGetValues(shell, args, j);
4692 h = pw_height + (lines - 1) * ew_height;
4695 XSync(xDisplay, False);
4697 /* This code seems to tickle an X bug if it is executed too soon
4698 after xboard starts up. The coordinates get transformed as if
4699 the main window was positioned at (0, 0).
4701 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4703 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4704 RootWindowOfScreen(XtScreen(shellWidget)),
4705 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4709 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4712 XtSetArg(args[j], XtNheight, h); j++;
4713 XtSetArg(args[j], XtNwidth, w); j++;
4714 XtSetArg(args[j], XtNx, x); j++;
4715 XtSetArg(args[j], XtNy, y); j++;
4716 XtSetValues(shell, args, j);
4722 static int savedIndex; /* gross that this is global */
4724 void EditCommentPopUp(index, title, text)
4733 if (text == NULL) text = "";
4735 if (editShell == NULL) {
4737 CommentCreate(title, text, True, EditCommentCallback, 4);
4738 XtRealizeWidget(editShell);
4739 CatchDeleteWindow(editShell, "EditCommentPopDown");
4741 edit = XtNameToWidget(editShell, "*form.text");
4743 XtSetArg(args[j], XtNstring, text); j++;
4744 XtSetValues(edit, args, j);
4746 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4747 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4748 XtSetValues(editShell, args, j);
4751 XtPopup(editShell, XtGrabNone);
4755 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4756 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4760 void EditCommentCallback(w, client_data, call_data)
4762 XtPointer client_data, call_data;
4770 XtSetArg(args[j], XtNlabel, &name); j++;
4771 XtGetValues(w, args, j);
4773 if (strcmp(name, _("ok")) == 0) {
4774 edit = XtNameToWidget(editShell, "*form.text");
4776 XtSetArg(args[j], XtNstring, &val); j++;
4777 XtGetValues(edit, args, j);
4778 ReplaceComment(savedIndex, val);
4779 EditCommentPopDown();
4780 } else if (strcmp(name, _("cancel")) == 0) {
4781 EditCommentPopDown();
4782 } else if (strcmp(name, _("clear")) == 0) {
4783 edit = XtNameToWidget(editShell, "*form.text");
4784 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4785 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4789 void EditCommentPopDown()
4794 if (!editUp) return;
4796 XtSetArg(args[j], XtNx, &commentX); j++;
4797 XtSetArg(args[j], XtNy, &commentY); j++;
4798 XtSetArg(args[j], XtNheight, &commentH); j++;
4799 XtSetArg(args[j], XtNwidth, &commentW); j++;
4800 XtGetValues(editShell, args, j);
4801 XtPopdown(editShell);
4804 XtSetArg(args[j], XtNleftBitmap, None); j++;
4805 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4809 void ICSInputBoxPopUp()
4814 char *title = _("ICS Input");
4817 if (ICSInputShell == NULL) {
4818 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
4819 tr = XtParseTranslationTable(ICSInputTranslations);
4820 edit = XtNameToWidget(ICSInputShell, "*form.text");
4821 XtOverrideTranslations(edit, tr);
4822 XtRealizeWidget(ICSInputShell);
4823 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
4826 edit = XtNameToWidget(ICSInputShell, "*form.text");
4828 XtSetArg(args[j], XtNstring, ""); j++;
4829 XtSetValues(edit, args, j);
4831 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4832 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4833 XtSetValues(ICSInputShell, args, j);
4836 XtPopup(ICSInputShell, XtGrabNone);
4837 XtSetKeyboardFocus(ICSInputShell, edit);
4839 ICSInputBoxUp = True;
4841 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4842 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4846 void ICSInputSendText()
4853 edit = XtNameToWidget(ICSInputShell, "*form.text");
4855 XtSetArg(args[j], XtNstring, &val); j++;
4856 XtGetValues(edit, args, j);
4857 SendMultiLineToICS(val);
4858 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4859 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4862 void ICSInputBoxPopDown()
4867 if (!ICSInputBoxUp) return;
4869 XtPopdown(ICSInputShell);
4870 ICSInputBoxUp = False;
4872 XtSetArg(args[j], XtNleftBitmap, None); j++;
4873 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4877 void CommentPopUp(title, text)
4884 if (commentShell == NULL) {
4886 CommentCreate(title, text, False, CommentCallback, 4);
4887 XtRealizeWidget(commentShell);
4888 CatchDeleteWindow(commentShell, "CommentPopDown");
4890 edit = XtNameToWidget(commentShell, "*form.text");
4892 XtSetArg(args[j], XtNstring, text); j++;
4893 XtSetValues(edit, args, j);
4895 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4896 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4897 XtSetValues(commentShell, args, j);
4900 XtPopup(commentShell, XtGrabNone);
4901 XSync(xDisplay, False);
4906 void CommentCallback(w, client_data, call_data)
4908 XtPointer client_data, call_data;
4915 XtSetArg(args[j], XtNlabel, &name); j++;
4916 XtGetValues(w, args, j);
4918 if (strcmp(name, _("close")) == 0) {
4920 } else if (strcmp(name, _("edit")) == 0) {
4927 void CommentPopDown()
4932 if (!commentUp) return;
4934 XtSetArg(args[j], XtNx, &commentX); j++;
4935 XtSetArg(args[j], XtNy, &commentY); j++;
4936 XtSetArg(args[j], XtNwidth, &commentW); j++;
4937 XtSetArg(args[j], XtNheight, &commentH); j++;
4938 XtGetValues(commentShell, args, j);
4939 XtPopdown(commentShell);
4940 XSync(xDisplay, False);
4944 void FileNamePopUp(label, def, proc, openMode)
4951 Widget popup, layout, dialog, edit;
4957 fileProc = proc; /* I can't see a way not */
4958 fileOpenMode = openMode; /* to use globals here */
4961 XtSetArg(args[i], XtNresizable, True); i++;
4962 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
4963 XtSetArg(args[i], XtNtitle, XtNewString(_("File name prompt"))); i++;
4964 fileNameShell = popup =
4965 XtCreatePopupShell("File name prompt", transientShellWidgetClass,
4966 shellWidget, args, i);
4969 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
4970 layoutArgs, XtNumber(layoutArgs));
4973 XtSetArg(args[i], XtNlabel, label); i++;
4974 XtSetArg(args[i], XtNvalue, def); i++;
4975 XtSetArg(args[i], XtNborderWidth, 0); i++;
4976 dialog = XtCreateManagedWidget("fileName", dialogWidgetClass,
4979 XawDialogAddButton(dialog, _("ok"), FileNameCallback, (XtPointer) dialog);
4980 XawDialogAddButton(dialog, _("cancel"), FileNameCallback,
4981 (XtPointer) dialog);
4983 XtRealizeWidget(popup);
4984 CatchDeleteWindow(popup, "FileNamePopDown");
4986 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
4987 &x, &y, &win_x, &win_y, &mask);
4989 XtSetArg(args[0], XtNx, x - 10);
4990 XtSetArg(args[1], XtNy, y - 30);
4991 XtSetValues(popup, args, 2);
4993 XtPopup(popup, XtGrabExclusive);
4996 edit = XtNameToWidget(dialog, "*value");
4997 XtSetKeyboardFocus(popup, edit);
5000 void FileNamePopDown()
5002 if (!filenameUp) return;
5003 XtPopdown(fileNameShell);
5004 XtDestroyWidget(fileNameShell);
5009 void FileNameCallback(w, client_data, call_data)
5011 XtPointer client_data, call_data;
5016 XtSetArg(args[0], XtNlabel, &name);
5017 XtGetValues(w, args, 1);
5019 if (strcmp(name, _("cancel")) == 0) {
5024 FileNameAction(w, NULL, NULL, NULL);
5027 void FileNameAction(w, event, prms, nprms)
5039 name = XawDialogGetValueString(w = XtParent(w));
5041 if ((name != NULL) && (*name != NULLCHAR)) {
5043 XtPopdown(w = XtParent(XtParent(w)));
5047 p = strrchr(buf, ' ');
5054 fullname = ExpandPathName(buf);
5056 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5059 f = fopen(fullname, fileOpenMode);
5061 DisplayError(_("Failed to open file"), errno);
5063 (void) (*fileProc)(f, index, buf);
5070 XtPopdown(w = XtParent(XtParent(w)));
5076 void PromotionPopUp()
5079 Widget dialog, layout;
5081 Dimension bw_width, pw_width;
5085 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5086 XtGetValues(boardWidget, args, j);
5089 XtSetArg(args[j], XtNresizable, True); j++;
5090 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5092 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5093 shellWidget, args, j);
5095 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5096 layoutArgs, XtNumber(layoutArgs));
5099 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5100 XtSetArg(args[j], XtNborderWidth, 0); j++;
5101 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5104 if(gameInfo.variant != VariantShogi) {
5105 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5106 (XtPointer) dialog);
5107 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5108 (XtPointer) dialog);
5109 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5110 (XtPointer) dialog);
5111 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5112 (XtPointer) dialog);
5113 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5114 gameInfo.variant == VariantGiveaway) {
5115 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5116 (XtPointer) dialog);
5118 if(gameInfo.variant == VariantCapablanca ||
5119 gameInfo.variant == VariantGothic ||
5120 gameInfo.variant == VariantCapaRandom) {
5121 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5122 (XtPointer) dialog);
5123 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5124 (XtPointer) dialog);
5126 } else // [HGM] shogi
5128 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5129 (XtPointer) dialog);
5130 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5131 (XtPointer) dialog);
5133 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5134 (XtPointer) dialog);
5136 XtRealizeWidget(promotionShell);
5137 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5140 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5141 XtGetValues(promotionShell, args, j);
5143 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5144 lineGap + squareSize/3 +
5145 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5146 0 : 6*(squareSize + lineGap)), &x, &y);
5149 XtSetArg(args[j], XtNx, x); j++;
5150 XtSetArg(args[j], XtNy, y); j++;
5151 XtSetValues(promotionShell, args, j);
5153 XtPopup(promotionShell, XtGrabNone);
5158 void PromotionPopDown()
5160 if (!promotionUp) return;
5161 XtPopdown(promotionShell);
5162 XtDestroyWidget(promotionShell);
5163 promotionUp = False;
5166 void PromotionCallback(w, client_data, call_data)
5168 XtPointer client_data, call_data;
5174 XtSetArg(args[0], XtNlabel, &name);
5175 XtGetValues(w, args, 1);
5179 if (fromX == -1) return;
5181 if (strcmp(name, _("cancel")) == 0) {
5185 } else if (strcmp(name, _("Knight")) == 0) {
5187 } else if (strcmp(name, _("Promote")) == 0) {
5189 } else if (strcmp(name, _("Defer")) == 0) {
5192 promoChar = ToLower(name[0]);
5195 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5197 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5198 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5203 void ErrorCallback(w, client_data, call_data)
5205 XtPointer client_data, call_data;
5208 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5210 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5216 if (!errorUp) return;
5218 XtPopdown(errorShell);
5219 XtDestroyWidget(errorShell);
5220 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5223 void ErrorPopUp(title, label, modal)
5224 char *title, *label;
5228 Widget dialog, layout;
5232 Dimension bw_width, pw_width;
5233 Dimension pw_height;
5237 XtSetArg(args[i], XtNresizable, True); i++;
5238 XtSetArg(args[i], XtNtitle, title); i++;
5240 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5241 shellWidget, args, i);
5243 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5244 layoutArgs, XtNumber(layoutArgs));
5247 XtSetArg(args[i], XtNlabel, label); i++;
5248 XtSetArg(args[i], XtNborderWidth, 0); i++;
5249 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5252 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5254 XtRealizeWidget(errorShell);
5255 CatchDeleteWindow(errorShell, "ErrorPopDown");
5258 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5259 XtGetValues(boardWidget, args, i);
5261 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5262 XtSetArg(args[i], XtNheight, &pw_height); i++;
5263 XtGetValues(errorShell, args, i);
5266 /* This code seems to tickle an X bug if it is executed too soon
5267 after xboard starts up. The coordinates get transformed as if
5268 the main window was positioned at (0, 0).
5270 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5271 0 - pw_height + squareSize / 3, &x, &y);
5273 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5274 RootWindowOfScreen(XtScreen(boardWidget)),
5275 (bw_width - pw_width) / 2,
5276 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5280 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5283 XtSetArg(args[i], XtNx, x); i++;
5284 XtSetArg(args[i], XtNy, y); i++;
5285 XtSetValues(errorShell, args, i);
5288 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5291 /* Disable all user input other than deleting the window */
5292 static int frozen = 0;
5296 /* Grab by a widget that doesn't accept input */
5297 XtAddGrab(messageWidget, TRUE, FALSE);
5301 /* Undo a FreezeUI */
5304 if (!frozen) return;
5305 XtRemoveGrab(messageWidget);
5309 char *ModeToWidgetName(mode)
5313 case BeginningOfGame:
5314 if (appData.icsActive)
5315 return "menuMode.ICS Client";
5316 else if (appData.noChessProgram ||
5317 *appData.cmailGameName != NULLCHAR)
5318 return "menuMode.Edit Game";
5320 return "menuMode.Machine Black";
5321 case MachinePlaysBlack:
5322 return "menuMode.Machine Black";
5323 case MachinePlaysWhite:
5324 return "menuMode.Machine White";
5326 return "menuMode.Analysis Mode";
5328 return "menuMode.Analyze File";
5329 case TwoMachinesPlay:
5330 return "menuMode.Two Machines";
5332 return "menuMode.Edit Game";
5333 case PlayFromGameFile:
5334 return "menuFile.Load Game";
5336 return "menuMode.Edit Position";
5338 return "menuMode.Training";
5339 case IcsPlayingWhite:
5340 case IcsPlayingBlack:
5344 return "menuMode.ICS Client";
5351 void ModeHighlight()
5354 static int oldPausing = FALSE;
5355 static GameMode oldmode = (GameMode) -1;
5358 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5360 if (pausing != oldPausing) {
5361 oldPausing = pausing;
5363 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5365 XtSetArg(args[0], XtNleftBitmap, None);
5367 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5370 if (appData.showButtonBar) {
5371 /* Always toggle, don't set. Previous code messes up when
5372 invoked while the button is pressed, as releasing it
5373 toggles the state again. */
5376 XtSetArg(args[0], XtNbackground, &oldbg);
5377 XtSetArg(args[1], XtNforeground, &oldfg);
5378 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5380 XtSetArg(args[0], XtNbackground, oldfg);
5381 XtSetArg(args[1], XtNforeground, oldbg);
5383 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5387 wname = ModeToWidgetName(oldmode);
5388 if (wname != NULL) {
5389 XtSetArg(args[0], XtNleftBitmap, None);
5390 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5392 wname = ModeToWidgetName(gameMode);
5393 if (wname != NULL) {
5394 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5395 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5399 /* Maybe all the enables should be handled here, not just this one */
5400 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5401 gameMode == Training || gameMode == PlayFromGameFile);
5406 * Button/menu procedures
5408 void ResetProc(w, event, prms, nprms)
5417 int LoadGamePopUp(f, gameNumber, title)
5422 cmailMsgLoaded = FALSE;
5423 if (gameNumber == 0) {
5424 int error = GameListBuild(f);
5426 DisplayError(_("Cannot build game list"), error);
5427 } else if (!ListEmpty(&gameList) &&
5428 ((ListGame *) gameList.tailPred)->number > 1) {
5429 GameListPopUp(f, title);
5435 return LoadGame(f, gameNumber, title, FALSE);
5438 void LoadGameProc(w, event, prms, nprms)
5444 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5447 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5450 void LoadNextGameProc(w, event, prms, nprms)
5459 void LoadPrevGameProc(w, event, prms, nprms)
5468 void ReloadGameProc(w, event, prms, nprms)
5477 void LoadNextPositionProc(w, event, prms, nprms)
5486 void LoadPrevPositionProc(w, event, prms, nprms)
5495 void ReloadPositionProc(w, event, prms, nprms)
5504 void LoadPositionProc(w, event, prms, nprms)
5510 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5513 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5516 void SaveGameProc(w, event, prms, nprms)
5522 FileNamePopUp(_("Save game file name?"),
5523 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5527 void SavePositionProc(w, event, prms, nprms)
5533 FileNamePopUp(_("Save position file name?"),
5534 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5538 void ReloadCmailMsgProc(w, event, prms, nprms)
5544 ReloadCmailMsgEvent(FALSE);
5547 void MailMoveProc(w, event, prms, nprms)
5556 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5557 char *selected_fen_position=NULL;
5560 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5561 Atom *type_return, XtPointer *value_return,
5562 unsigned long *length_return, int *format_return)
5564 char *selection_tmp;
5566 if (!selected_fen_position) return False; /* should never happen */
5567 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5568 /* note: since no XtSelectionDoneProc was registered, Xt will
5569 * automatically call XtFree on the value returned. So have to
5570 * make a copy of it allocated with XtMalloc */
5571 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5572 strcpy(selection_tmp, selected_fen_position);
5574 *value_return=selection_tmp;
5575 *length_return=strlen(selection_tmp);
5576 *type_return=*target;
5577 *format_return = 8; /* bits per byte */
5579 } else if (*target == XA_TARGETS(xDisplay)) {
5580 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5581 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5582 targets_tmp[1] = XA_STRING;
5583 *value_return = targets_tmp;
5584 *type_return = XA_ATOM;
5586 *format_return = 8 * sizeof(Atom);
5587 if (*format_return > 32) {
5588 *length_return *= *format_return / 32;
5589 *format_return = 32;
5597 /* note: when called from menu all parameters are NULL, so no clue what the
5598 * Widget which was clicked on was, or what the click event was
5600 void CopyPositionProc(w, event, prms, nprms)
5607 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5608 * have a notion of a position that is selected but not copied.
5609 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5611 if(gameMode == EditPosition) EditPositionDone(TRUE);
5612 if (selected_fen_position) free(selected_fen_position);
5613 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5614 if (!selected_fen_position) return;
5615 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5617 SendPositionSelection,
5618 NULL/* lose_ownership_proc */ ,
5619 NULL/* transfer_done_proc */);
5620 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5622 SendPositionSelection,
5623 NULL/* lose_ownership_proc */ ,
5624 NULL/* transfer_done_proc */);
5627 /* function called when the data to Paste is ready */
5629 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5630 Atom *type, XtPointer value, unsigned long *len, int *format)
5633 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5634 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5635 EditPositionPasteFEN(fenstr);
5639 /* called when Paste Position button is pressed,
5640 * all parameters will be NULL */
5641 void PastePositionProc(w, event, prms, nprms)
5647 XtGetSelectionValue(menuBarWidget,
5648 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5649 /* (XtSelectionCallbackProc) */ PastePositionCB,
5650 NULL, /* client_data passed to PastePositionCB */
5652 /* better to use the time field from the event that triggered the
5653 * call to this function, but that isn't trivial to get
5661 SendGameSelection(Widget w, Atom *selection, Atom *target,
5662 Atom *type_return, XtPointer *value_return,
5663 unsigned long *length_return, int *format_return)
5665 char *selection_tmp;
5667 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5668 FILE* f = fopen(gameCopyFilename, "r");
5671 if (f == NULL) return False;
5675 selection_tmp = XtMalloc(len + 1);
5676 count = fread(selection_tmp, 1, len, f);
5678 XtFree(selection_tmp);
5681 selection_tmp[len] = NULLCHAR;
5682 *value_return = selection_tmp;
5683 *length_return = len;
5684 *type_return = *target;
5685 *format_return = 8; /* bits per byte */
5687 } else if (*target == XA_TARGETS(xDisplay)) {
5688 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5689 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5690 targets_tmp[1] = XA_STRING;
5691 *value_return = targets_tmp;
5692 *type_return = XA_ATOM;
5694 *format_return = 8 * sizeof(Atom);
5695 if (*format_return > 32) {
5696 *length_return *= *format_return / 32;
5697 *format_return = 32;
5705 /* note: when called from menu all parameters are NULL, so no clue what the
5706 * Widget which was clicked on was, or what the click event was
5708 void CopyGameProc(w, event, prms, nprms)
5716 ret = SaveGameToFile(gameCopyFilename, FALSE);
5720 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5721 * have a notion of a game that is selected but not copied.
5722 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5724 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5727 NULL/* lose_ownership_proc */ ,
5728 NULL/* transfer_done_proc */);
5729 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5732 NULL/* lose_ownership_proc */ ,
5733 NULL/* transfer_done_proc */);
5736 /* function called when the data to Paste is ready */
5738 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5739 Atom *type, XtPointer value, unsigned long *len, int *format)
5742 if (value == NULL || *len == 0) {
5743 return; /* nothing had been selected to copy */
5745 f = fopen(gamePasteFilename, "w");
5747 DisplayError(_("Can't open temp file"), errno);
5750 fwrite(value, 1, *len, f);
5753 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5756 /* called when Paste Game button is pressed,
5757 * all parameters will be NULL */
5758 void PasteGameProc(w, event, prms, nprms)
5764 XtGetSelectionValue(menuBarWidget,
5765 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5766 /* (XtSelectionCallbackProc) */ PasteGameCB,
5767 NULL, /* client_data passed to PasteGameCB */
5769 /* better to use the time field from the event that triggered the
5770 * call to this function, but that isn't trivial to get
5780 SaveGameProc(NULL, NULL, NULL, NULL);
5784 void QuitProc(w, event, prms, nprms)
5793 void PauseProc(w, event, prms, nprms)
5803 void MachineBlackProc(w, event, prms, nprms)
5809 MachineBlackEvent();
5812 void MachineWhiteProc(w, event, prms, nprms)
5818 MachineWhiteEvent();
5821 void AnalyzeModeProc(w, event, prms, nprms)
5829 if (!first.analysisSupport) {
5830 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5831 DisplayError(buf, 0);
5834 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5835 if (appData.icsActive) {
5836 if (gameMode != IcsObserving) {
5837 sprintf(buf,_("You are not observing a game"));
5838 DisplayError(buf, 0);
5840 if (appData.icsEngineAnalyze) {
5841 if (appData.debugMode)
5842 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5848 /* if enable, use want disable icsEngineAnalyze */
5849 if (appData.icsEngineAnalyze) {
5854 appData.icsEngineAnalyze = TRUE;
5855 if (appData.debugMode)
5856 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5858 if (!appData.showThinking)
5859 ShowThinkingProc(w,event,prms,nprms);
5864 void AnalyzeFileProc(w, event, prms, nprms)
5870 if (!first.analysisSupport) {
5872 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5873 DisplayError(buf, 0);
5878 if (!appData.showThinking)
5879 ShowThinkingProc(w,event,prms,nprms);
5882 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
5883 AnalysisPeriodicEvent(1);
5886 void TwoMachinesProc(w, event, prms, nprms)
5895 void IcsClientProc(w, event, prms, nprms)
5904 void EditGameProc(w, event, prms, nprms)
5913 void EditPositionProc(w, event, prms, nprms)
5919 EditPositionEvent();
5922 void TrainingProc(w, event, prms, nprms)
5931 void EditCommentProc(w, event, prms, nprms)
5938 EditCommentPopDown();
5944 void IcsInputBoxProc(w, event, prms, nprms)
5950 if (ICSInputBoxUp) {
5951 ICSInputBoxPopDown();
5957 void AcceptProc(w, event, prms, nprms)
5966 void DeclineProc(w, event, prms, nprms)
5975 void RematchProc(w, event, prms, nprms)
5984 void CallFlagProc(w, event, prms, nprms)
5993 void DrawProc(w, event, prms, nprms)
6002 void AbortProc(w, event, prms, nprms)
6011 void AdjournProc(w, event, prms, nprms)
6020 void ResignProc(w, event, prms, nprms)
6029 void AdjuWhiteProc(w, event, prms, nprms)
6035 UserAdjudicationEvent(+1);
6038 void AdjuBlackProc(w, event, prms, nprms)
6044 UserAdjudicationEvent(-1);
6047 void AdjuDrawProc(w, event, prms, nprms)
6053 UserAdjudicationEvent(0);
6056 void EnterKeyProc(w, event, prms, nprms)
6062 if (ICSInputBoxUp == True)
6066 void StopObservingProc(w, event, prms, nprms)
6072 StopObservingEvent();
6075 void StopExaminingProc(w, event, prms, nprms)
6081 StopExaminingEvent();
6085 void ForwardProc(w, event, prms, nprms)
6095 void BackwardProc(w, event, prms, nprms)
6104 void ToStartProc(w, event, prms, nprms)
6113 void ToEndProc(w, event, prms, nprms)
6122 void RevertProc(w, event, prms, nprms)
6131 void TruncateGameProc(w, event, prms, nprms)
6137 TruncateGameEvent();
6139 void RetractMoveProc(w, event, prms, nprms)
6148 void MoveNowProc(w, event, prms, nprms)
6158 void AlwaysQueenProc(w, event, prms, nprms)
6166 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6168 if (appData.alwaysPromoteToQueen) {
6169 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6171 XtSetArg(args[0], XtNleftBitmap, None);
6173 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6177 void AnimateDraggingProc(w, event, prms, nprms)
6185 appData.animateDragging = !appData.animateDragging;
6187 if (appData.animateDragging) {
6188 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6191 XtSetArg(args[0], XtNleftBitmap, None);
6193 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6197 void AnimateMovingProc(w, event, prms, nprms)
6205 appData.animate = !appData.animate;
6207 if (appData.animate) {
6208 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6211 XtSetArg(args[0], XtNleftBitmap, None);
6213 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6217 void AutocommProc(w, event, prms, nprms)
6225 appData.autoComment = !appData.autoComment;
6227 if (appData.autoComment) {
6228 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6230 XtSetArg(args[0], XtNleftBitmap, None);
6232 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6237 void AutoflagProc(w, event, prms, nprms)
6245 appData.autoCallFlag = !appData.autoCallFlag;
6247 if (appData.autoCallFlag) {
6248 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6250 XtSetArg(args[0], XtNleftBitmap, None);
6252 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6256 void AutoflipProc(w, event, prms, nprms)
6264 appData.autoFlipView = !appData.autoFlipView;
6266 if (appData.autoFlipView) {
6267 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6269 XtSetArg(args[0], XtNleftBitmap, None);
6271 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6275 void AutobsProc(w, event, prms, nprms)
6283 appData.autoObserve = !appData.autoObserve;
6285 if (appData.autoObserve) {
6286 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6288 XtSetArg(args[0], XtNleftBitmap, None);
6290 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6294 void AutoraiseProc(w, event, prms, nprms)
6302 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6304 if (appData.autoRaiseBoard) {
6305 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6307 XtSetArg(args[0], XtNleftBitmap, None);
6309 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6313 void AutosaveProc(w, event, prms, nprms)
6321 appData.autoSaveGames = !appData.autoSaveGames;
6323 if (appData.autoSaveGames) {
6324 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6326 XtSetArg(args[0], XtNleftBitmap, None);
6328 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6332 void BlindfoldProc(w, event, prms, nprms)
6340 appData.blindfold = !appData.blindfold;
6342 if (appData.blindfold) {
6343 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6345 XtSetArg(args[0], XtNleftBitmap, None);
6347 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6350 DrawPosition(True, NULL);
6353 void TestLegalityProc(w, event, prms, nprms)
6361 appData.testLegality = !appData.testLegality;
6363 if (appData.testLegality) {
6364 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6366 XtSetArg(args[0], XtNleftBitmap, None);
6368 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6373 void FlashMovesProc(w, event, prms, nprms)
6381 if (appData.flashCount == 0) {
6382 appData.flashCount = 3;
6384 appData.flashCount = -appData.flashCount;
6387 if (appData.flashCount > 0) {
6388 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6390 XtSetArg(args[0], XtNleftBitmap, None);
6392 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6396 void FlipViewProc(w, event, prms, nprms)
6402 flipView = !flipView;
6403 DrawPosition(True, NULL);
6406 void GetMoveListProc(w, event, prms, nprms)
6414 appData.getMoveList = !appData.getMoveList;
6416 if (appData.getMoveList) {
6417 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6420 XtSetArg(args[0], XtNleftBitmap, None);
6422 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6427 void HighlightDraggingProc(w, event, prms, nprms)
6435 appData.highlightDragging = !appData.highlightDragging;
6437 if (appData.highlightDragging) {
6438 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6440 XtSetArg(args[0], XtNleftBitmap, None);
6442 XtSetValues(XtNameToWidget(menuBarWidget,
6443 "menuOptions.Highlight Dragging"), args, 1);
6447 void HighlightLastMoveProc(w, event, prms, nprms)
6455 appData.highlightLastMove = !appData.highlightLastMove;
6457 if (appData.highlightLastMove) {
6458 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6460 XtSetArg(args[0], XtNleftBitmap, None);
6462 XtSetValues(XtNameToWidget(menuBarWidget,
6463 "menuOptions.Highlight Last Move"), args, 1);
6466 void IcsAlarmProc(w, event, prms, nprms)
6474 appData.icsAlarm = !appData.icsAlarm;
6476 if (appData.icsAlarm) {
6477 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6479 XtSetArg(args[0], XtNleftBitmap, None);
6481 XtSetValues(XtNameToWidget(menuBarWidget,
6482 "menuOptions.ICS Alarm"), args, 1);
6485 void MoveSoundProc(w, event, prms, nprms)
6493 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6495 if (appData.ringBellAfterMoves) {
6496 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6498 XtSetArg(args[0], XtNleftBitmap, None);
6500 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6505 void OldSaveStyleProc(w, event, prms, nprms)
6513 appData.oldSaveStyle = !appData.oldSaveStyle;
6515 if (appData.oldSaveStyle) {
6516 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6518 XtSetArg(args[0], XtNleftBitmap, None);
6520 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6524 void PeriodicUpdatesProc(w, event, prms, nprms)
6532 PeriodicUpdatesEvent(!appData.periodicUpdates);
6534 if (appData.periodicUpdates) {
6535 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6537 XtSetArg(args[0], XtNleftBitmap, None);
6539 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6543 void PonderNextMoveProc(w, event, prms, nprms)
6551 PonderNextMoveEvent(!appData.ponderNextMove);
6553 if (appData.ponderNextMove) {
6554 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6556 XtSetArg(args[0], XtNleftBitmap, None);
6558 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6562 void PopupExitMessageProc(w, event, prms, nprms)
6570 appData.popupExitMessage = !appData.popupExitMessage;
6572 if (appData.popupExitMessage) {
6573 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6575 XtSetArg(args[0], XtNleftBitmap, None);
6577 XtSetValues(XtNameToWidget(menuBarWidget,
6578 "menuOptions.Popup Exit Message"), args, 1);
6581 void PopupMoveErrorsProc(w, event, prms, nprms)
6589 appData.popupMoveErrors = !appData.popupMoveErrors;
6591 if (appData.popupMoveErrors) {
6592 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6594 XtSetArg(args[0], XtNleftBitmap, None);
6596 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6600 void PremoveProc(w, event, prms, nprms)
6608 appData.premove = !appData.premove;
6610 if (appData.premove) {
6611 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6613 XtSetArg(args[0], XtNleftBitmap, None);
6615 XtSetValues(XtNameToWidget(menuBarWidget,
6616 "menuOptions.Premove"), args, 1);
6619 void QuietPlayProc(w, event, prms, nprms)
6627 appData.quietPlay = !appData.quietPlay;
6629 if (appData.quietPlay) {
6630 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6632 XtSetArg(args[0], XtNleftBitmap, None);
6634 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6638 void ShowCoordsProc(w, event, prms, nprms)
6646 appData.showCoords = !appData.showCoords;
6648 if (appData.showCoords) {
6649 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6651 XtSetArg(args[0], XtNleftBitmap, None);
6653 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6656 DrawPosition(True, NULL);
6659 void ShowThinkingProc(w, event, prms, nprms)
6665 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6666 ShowThinkingEvent();
6669 void HideThinkingProc(w, event, prms, nprms)
6677 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6678 ShowThinkingEvent();
6680 if (appData.hideThinkingFromHuman) {
6681 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6683 XtSetArg(args[0], XtNleftBitmap, None);
6685 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6689 void SaveOnExitProc(w, event, prms, nprms)
6697 saveSettingsOnExit = !saveSettingsOnExit;
6699 if (saveSettingsOnExit) {
6700 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6702 XtSetArg(args[0], XtNleftBitmap, None);
6704 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6708 void SaveSettingsProc(w, event, prms, nprms)
6714 SaveSettings(settingsFileName);
6717 void InfoProc(w, event, prms, nprms)
6724 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6729 void ManProc(w, event, prms, nprms)
6737 if (nprms && *nprms > 0)
6741 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6745 void HintProc(w, event, prms, nprms)
6754 void BookProc(w, event, prms, nprms)
6763 void AboutProc(w, event, prms, nprms)
6771 char *zippy = " (with Zippy code)";
6775 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6776 programVersion, zippy,
6777 "Copyright 1991 Digital Equipment Corporation",
6778 "Enhancements Copyright 1992-2009 Free Software Foundation",
6779 "Enhancements Copyright 2005 Alessandro Scotti",
6780 PACKAGE, " is free software and carries NO WARRANTY;",
6781 "see the file COPYING for more information.");
6782 ErrorPopUp(_("About XBoard"), buf, FALSE);
6785 void DebugProc(w, event, prms, nprms)
6791 appData.debugMode = !appData.debugMode;
6794 void AboutGameProc(w, event, prms, nprms)
6803 void NothingProc(w, event, prms, nprms)
6812 void Iconify(w, event, prms, nprms)
6821 XtSetArg(args[0], XtNiconic, True);
6822 XtSetValues(shellWidget, args, 1);
6825 void DisplayMessage(message, extMessage)
6826 char *message, *extMessage;
6828 /* display a message in the message widget */
6837 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
6842 message = extMessage;
6846 /* need to test if messageWidget already exists, since this function
6847 can also be called during the startup, if for example a Xresource
6848 is not set up correctly */
6851 XtSetArg(arg, XtNlabel, message);
6852 XtSetValues(messageWidget, &arg, 1);
6858 void DisplayTitle(text)
6863 char title[MSG_SIZ];
6866 if (text == NULL) text = "";
6868 if (appData.titleInWindow) {
6870 XtSetArg(args[i], XtNlabel, text); i++;
6871 XtSetValues(titleWidget, args, i);
6874 if (*text != NULLCHAR) {
6876 strcpy(title, text);
6877 } else if (appData.icsActive) {
6878 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
6879 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
6880 } else if (appData.cmailGameName[0] != NULLCHAR) {
6881 snprintf(icon, sizeof(icon), "%s", "CMail");
6882 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
6884 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
6885 } else if (gameInfo.variant == VariantGothic) {
6886 strcpy(icon, programName);
6887 strcpy(title, GOTHIC);
6890 } else if (gameInfo.variant == VariantFalcon) {
6891 strcpy(icon, programName);
6892 strcpy(title, FALCON);
6894 } else if (appData.noChessProgram) {
6895 strcpy(icon, programName);
6896 strcpy(title, programName);
6898 strcpy(icon, first.tidy);
6899 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
6902 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
6903 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
6904 XtSetValues(shellWidget, args, i);
6908 void DisplayError(message, error)
6915 if (appData.debugMode || appData.matchMode) {
6916 fprintf(stderr, "%s: %s\n", programName, message);
6919 if (appData.debugMode || appData.matchMode) {
6920 fprintf(stderr, "%s: %s: %s\n",
6921 programName, message, strerror(error));
6923 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6926 ErrorPopUp(_("Error"), message, FALSE);
6930 void DisplayMoveError(message)
6935 DrawPosition(FALSE, NULL);
6936 if (appData.debugMode || appData.matchMode) {
6937 fprintf(stderr, "%s: %s\n", programName, message);
6939 if (appData.popupMoveErrors) {
6940 ErrorPopUp(_("Error"), message, FALSE);
6942 DisplayMessage(message, "");
6947 void DisplayFatalError(message, error, status)
6953 errorExitStatus = status;
6955 fprintf(stderr, "%s: %s\n", programName, message);
6957 fprintf(stderr, "%s: %s: %s\n",
6958 programName, message, strerror(error));
6959 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6962 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
6963 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
6969 void DisplayInformation(message)
6973 ErrorPopUp(_("Information"), message, TRUE);
6976 void DisplayNote(message)
6980 ErrorPopUp(_("Note"), message, FALSE);
6984 NullXErrorCheck(dpy, error_event)
6986 XErrorEvent *error_event;
6991 void DisplayIcsInteractionTitle(message)
6994 if (oldICSInteractionTitle == NULL) {
6995 /* Magic to find the old window title, adapted from vim */
6996 char *wina = getenv("WINDOWID");
6998 Window win = (Window) atoi(wina);
6999 Window root, parent, *children;
7000 unsigned int nchildren;
7001 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7003 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7004 if (!XQueryTree(xDisplay, win, &root, &parent,
7005 &children, &nchildren)) break;
7006 if (children) XFree((void *)children);
7007 if (parent == root || parent == 0) break;
7010 XSetErrorHandler(oldHandler);
7012 if (oldICSInteractionTitle == NULL) {
7013 oldICSInteractionTitle = "xterm";
7016 printf("\033]0;%s\007", message);
7020 char pendingReplyPrefix[MSG_SIZ];
7021 ProcRef pendingReplyPR;
7023 void AskQuestionProc(w, event, prms, nprms)
7030 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7034 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7037 void AskQuestionPopDown()
7039 if (!askQuestionUp) return;
7040 XtPopdown(askQuestionShell);
7041 XtDestroyWidget(askQuestionShell);
7042 askQuestionUp = False;
7045 void AskQuestionReplyAction(w, event, prms, nprms)
7055 reply = XawDialogGetValueString(w = XtParent(w));
7056 strcpy(buf, pendingReplyPrefix);
7057 if (*buf) strcat(buf, " ");
7060 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7061 AskQuestionPopDown();
7063 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7066 void AskQuestionCallback(w, client_data, call_data)
7068 XtPointer client_data, call_data;
7073 XtSetArg(args[0], XtNlabel, &name);
7074 XtGetValues(w, args, 1);
7076 if (strcmp(name, _("cancel")) == 0) {
7077 AskQuestionPopDown();
7079 AskQuestionReplyAction(w, NULL, NULL, NULL);
7083 void AskQuestion(title, question, replyPrefix, pr)
7084 char *title, *question, *replyPrefix;
7088 Widget popup, layout, dialog, edit;
7094 strcpy(pendingReplyPrefix, replyPrefix);
7095 pendingReplyPR = pr;
7098 XtSetArg(args[i], XtNresizable, True); i++;
7099 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7100 askQuestionShell = popup =
7101 XtCreatePopupShell(title, transientShellWidgetClass,
7102 shellWidget, args, i);
7105 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7106 layoutArgs, XtNumber(layoutArgs));
7109 XtSetArg(args[i], XtNlabel, question); i++;
7110 XtSetArg(args[i], XtNvalue, ""); i++;
7111 XtSetArg(args[i], XtNborderWidth, 0); i++;
7112 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7115 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7116 (XtPointer) dialog);
7117 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7118 (XtPointer) dialog);
7120 XtRealizeWidget(popup);
7121 CatchDeleteWindow(popup, "AskQuestionPopDown");
7123 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7124 &x, &y, &win_x, &win_y, &mask);
7126 XtSetArg(args[0], XtNx, x - 10);
7127 XtSetArg(args[1], XtNy, y - 30);
7128 XtSetValues(popup, args, 2);
7130 XtPopup(popup, XtGrabExclusive);
7131 askQuestionUp = True;
7133 edit = XtNameToWidget(dialog, "*value");
7134 XtSetKeyboardFocus(popup, edit);
7142 if (*name == NULLCHAR) {
7144 } else if (strcmp(name, "$") == 0) {
7145 putc(BELLCHAR, stderr);
7148 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7156 PlaySound(appData.soundMove);
7162 PlaySound(appData.soundIcsWin);
7168 PlaySound(appData.soundIcsLoss);
7174 PlaySound(appData.soundIcsDraw);
7178 PlayIcsUnfinishedSound()
7180 PlaySound(appData.soundIcsUnfinished);
7186 PlaySound(appData.soundIcsAlarm);
7192 system("stty echo");
7198 system("stty -echo");
7202 Colorize(cc, continuation)
7207 int count, outCount, error;
7209 if (textColors[(int)cc].bg > 0) {
7210 if (textColors[(int)cc].fg > 0) {
7211 sprintf(buf, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7212 textColors[(int)cc].fg, textColors[(int)cc].bg);
7214 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7215 textColors[(int)cc].bg);
7218 if (textColors[(int)cc].fg > 0) {
7219 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7220 textColors[(int)cc].fg);
7222 sprintf(buf, "\033[0;%dm", textColors[(int)cc].attr);
7225 count = strlen(buf);
7226 outCount = OutputToProcess(NoProc, buf, count, &error);
7227 if (outCount < count) {
7228 DisplayFatalError(_("Error writing to display"), error, 1);
7231 if (continuation) return;
7234 PlaySound(appData.soundShout);
7237 PlaySound(appData.soundSShout);
7240 PlaySound(appData.soundChannel1);
7243 PlaySound(appData.soundChannel);
7246 PlaySound(appData.soundKibitz);
7249 PlaySound(appData.soundTell);
7251 case ColorChallenge:
7252 PlaySound(appData.soundChallenge);
7255 PlaySound(appData.soundRequest);
7258 PlaySound(appData.soundSeek);
7269 return getpwuid(getuid())->pw_name;
7272 static char *ExpandPathName(path)
7275 static char static_buf[2000];
7276 char *d, *s, buf[2000];
7282 while (*s && isspace(*s))
7291 if (*(s+1) == '/') {
7292 strcpy(d, getpwuid(getuid())->pw_dir);
7297 *strchr(buf, '/') = 0;
7298 pwd = getpwnam(buf);
7301 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7305 strcpy(d, pwd->pw_dir);
7306 strcat(d, strchr(s+1, '/'));
7317 static char host_name[MSG_SIZ];
7319 #if HAVE_GETHOSTNAME
7320 gethostname(host_name, MSG_SIZ);
7322 #else /* not HAVE_GETHOSTNAME */
7323 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7324 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7326 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7328 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7329 #endif /* not HAVE_GETHOSTNAME */
7332 XtIntervalId delayedEventTimerXID = 0;
7333 DelayedEventCallback delayedEventCallback = 0;
7338 delayedEventTimerXID = 0;
7339 delayedEventCallback();
7343 ScheduleDelayedEvent(cb, millisec)
7344 DelayedEventCallback cb; long millisec;
7346 if(delayedEventTimerXID && delayedEventCallback == cb)
7347 // [HGM] alive: replace, rather than add or flush identical event
7348 XtRemoveTimeOut(delayedEventTimerXID);
7349 delayedEventCallback = cb;
7350 delayedEventTimerXID =
7351 XtAppAddTimeOut(appContext, millisec,
7352 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7355 DelayedEventCallback
7358 if (delayedEventTimerXID) {
7359 return delayedEventCallback;
7366 CancelDelayedEvent()
7368 if (delayedEventTimerXID) {
7369 XtRemoveTimeOut(delayedEventTimerXID);
7370 delayedEventTimerXID = 0;
7374 XtIntervalId loadGameTimerXID = 0;
7376 int LoadGameTimerRunning()
7378 return loadGameTimerXID != 0;
7381 int StopLoadGameTimer()
7383 if (loadGameTimerXID != 0) {
7384 XtRemoveTimeOut(loadGameTimerXID);
7385 loadGameTimerXID = 0;
7393 LoadGameTimerCallback(arg, id)
7397 loadGameTimerXID = 0;
7402 StartLoadGameTimer(millisec)
7406 XtAppAddTimeOut(appContext, millisec,
7407 (XtTimerCallbackProc) LoadGameTimerCallback,
7411 XtIntervalId analysisClockXID = 0;
7414 AnalysisClockCallback(arg, id)
7418 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7419 || appData.icsEngineAnalyze) { // [DM]
7420 AnalysisPeriodicEvent(0);
7421 StartAnalysisClock();
7426 StartAnalysisClock()
7429 XtAppAddTimeOut(appContext, 2000,
7430 (XtTimerCallbackProc) AnalysisClockCallback,
7434 XtIntervalId clockTimerXID = 0;
7436 int ClockTimerRunning()
7438 return clockTimerXID != 0;
7441 int StopClockTimer()
7443 if (clockTimerXID != 0) {
7444 XtRemoveTimeOut(clockTimerXID);
7453 ClockTimerCallback(arg, id)
7462 StartClockTimer(millisec)
7466 XtAppAddTimeOut(appContext, millisec,
7467 (XtTimerCallbackProc) ClockTimerCallback,
7472 DisplayTimerLabel(w, color, timer, highlight)
7481 /* check for low time warning */
7482 Pixel foregroundOrWarningColor = timerForegroundPixel;
7485 appData.lowTimeWarning &&
7486 (timer / 1000) < appData.icsAlarmTime)
7487 foregroundOrWarningColor = lowTimeWarningColor;
7489 if (appData.clockMode) {
7490 sprintf(buf, "%s: %s", color, TimeString(timer));
7491 XtSetArg(args[0], XtNlabel, buf);
7493 sprintf(buf, "%s ", color);
7494 XtSetArg(args[0], XtNlabel, buf);
7499 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7500 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7502 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7503 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7506 XtSetValues(w, args, 3);
7510 DisplayWhiteClock(timeRemaining, highlight)
7516 if(appData.noGUI) return;
7517 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7518 if (highlight && iconPixmap == bIconPixmap) {
7519 iconPixmap = wIconPixmap;
7520 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7521 XtSetValues(shellWidget, args, 1);
7526 DisplayBlackClock(timeRemaining, highlight)
7532 if(appData.noGUI) return;
7533 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7534 if (highlight && iconPixmap == wIconPixmap) {
7535 iconPixmap = bIconPixmap;
7536 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7537 XtSetValues(shellWidget, args, 1);
7555 int StartChildProcess(cmdLine, dir, pr)
7562 int to_prog[2], from_prog[2];
7566 if (appData.debugMode) {
7567 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7570 /* We do NOT feed the cmdLine to the shell; we just
7571 parse it into blank-separated arguments in the
7572 most simple-minded way possible.
7575 strcpy(buf, cmdLine);
7578 while(*p == ' ') p++;
7580 if(*p == '"' || *p == '\'')
7581 p = strchr(++argv[i-1], *p);
7582 else p = strchr(p, ' ');
7583 if (p == NULL) break;
7588 SetUpChildIO(to_prog, from_prog);
7590 if ((pid = fork()) == 0) {
7592 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7593 close(to_prog[1]); // first close the unused pipe ends
7594 close(from_prog[0]);
7595 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7596 dup2(from_prog[1], 1);
7597 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7598 close(from_prog[1]); // and closing again loses one of the pipes!
7599 if(fileno(stderr) >= 2) // better safe than sorry...
7600 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7602 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7607 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7609 execvp(argv[0], argv);
7611 /* If we get here, exec failed */
7616 /* Parent process */
7618 close(from_prog[1]);
7620 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7623 cp->fdFrom = from_prog[0];
7624 cp->fdTo = to_prog[1];
7629 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7630 static RETSIGTYPE AlarmCallBack(int n)
7636 DestroyChildProcess(pr, signalType)
7640 ChildProc *cp = (ChildProc *) pr;
7642 if (cp->kind != CPReal) return;
7644 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7645 signal(SIGALRM, AlarmCallBack);
7647 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7648 kill(cp->pid, SIGKILL); // kill it forcefully
7649 wait((int *) 0); // and wait again
7653 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7655 /* Process is exiting either because of the kill or because of
7656 a quit command sent by the backend; either way, wait for it to die.
7665 InterruptChildProcess(pr)
7668 ChildProc *cp = (ChildProc *) pr;
7670 if (cp->kind != CPReal) return;
7671 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7674 int OpenTelnet(host, port, pr)
7679 char cmdLine[MSG_SIZ];
7681 if (port[0] == NULLCHAR) {
7682 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7684 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7686 return StartChildProcess(cmdLine, "", pr);
7689 int OpenTCP(host, port, pr)
7695 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7696 #else /* !OMIT_SOCKETS */
7698 struct sockaddr_in sa;
7700 unsigned short uport;
7703 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7707 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7708 sa.sin_family = AF_INET;
7709 sa.sin_addr.s_addr = INADDR_ANY;
7710 uport = (unsigned short) 0;
7711 sa.sin_port = htons(uport);
7712 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7716 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7717 if (!(hp = gethostbyname(host))) {
7719 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7720 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7721 hp->h_addrtype = AF_INET;
7723 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7724 hp->h_addr_list[0] = (char *) malloc(4);
7725 hp->h_addr_list[0][0] = b0;
7726 hp->h_addr_list[0][1] = b1;
7727 hp->h_addr_list[0][2] = b2;
7728 hp->h_addr_list[0][3] = b3;
7733 sa.sin_family = hp->h_addrtype;
7734 uport = (unsigned short) atoi(port);
7735 sa.sin_port = htons(uport);
7736 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7738 if (connect(s, (struct sockaddr *) &sa,
7739 sizeof(struct sockaddr_in)) < 0) {
7743 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7750 #endif /* !OMIT_SOCKETS */
7755 int OpenCommPort(name, pr)
7762 fd = open(name, 2, 0);
7763 if (fd < 0) return errno;
7765 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7775 int OpenLoopback(pr)
7781 SetUpChildIO(to, from);
7783 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7786 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7793 int OpenRcmd(host, user, cmd, pr)
7794 char *host, *user, *cmd;
7797 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7801 #define INPUT_SOURCE_BUF_SIZE 8192
7810 char buf[INPUT_SOURCE_BUF_SIZE];
7815 DoInputCallback(closure, source, xid)
7820 InputSource *is = (InputSource *) closure;
7825 if (is->lineByLine) {
7826 count = read(is->fd, is->unused,
7827 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7829 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7832 is->unused += count;
7834 while (p < is->unused) {
7835 q = memchr(p, '\n', is->unused - p);
7836 if (q == NULL) break;
7838 (is->func)(is, is->closure, p, q - p, 0);
7842 while (p < is->unused) {
7847 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
7852 (is->func)(is, is->closure, is->buf, count, error);
7856 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
7863 ChildProc *cp = (ChildProc *) pr;
7865 is = (InputSource *) calloc(1, sizeof(InputSource));
7866 is->lineByLine = lineByLine;
7870 is->fd = fileno(stdin);
7872 is->kind = cp->kind;
7873 is->fd = cp->fdFrom;
7876 is->unused = is->buf;
7879 is->xid = XtAppAddInput(appContext, is->fd,
7880 (XtPointer) (XtInputReadMask),
7881 (XtInputCallbackProc) DoInputCallback,
7883 is->closure = closure;
7884 return (InputSourceRef) is;
7888 RemoveInputSource(isr)
7891 InputSource *is = (InputSource *) isr;
7893 if (is->xid == 0) return;
7894 XtRemoveInput(is->xid);
7898 int OutputToProcess(pr, message, count, outError)
7904 static int line = 0;
7905 ChildProc *cp = (ChildProc *) pr;
7910 if (appData.noJoin || !appData.useInternalWrap)
7911 outCount = fwrite(message, 1, count, stdout);
7914 int width = get_term_width();
7915 int len = wrap(NULL, message, count, width, &line);
7916 char *msg = malloc(len);
7920 outCount = fwrite(message, 1, count, stdout);
7923 dbgchk = wrap(msg, message, count, width, &line);
7924 if (dbgchk != len && appData.debugMode)
7925 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
7926 outCount = fwrite(msg, 1, dbgchk, stdout);
7932 outCount = write(cp->fdTo, message, count);
7942 /* Output message to process, with "ms" milliseconds of delay
7943 between each character. This is needed when sending the logon
7944 script to ICC, which for some reason doesn't like the
7945 instantaneous send. */
7946 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
7953 ChildProc *cp = (ChildProc *) pr;
7958 r = write(cp->fdTo, message++, 1);
7971 /**** Animation code by Hugh Fisher, DCS, ANU.
7973 Known problem: if a window overlapping the board is
7974 moved away while a piece is being animated underneath,
7975 the newly exposed area won't be updated properly.
7976 I can live with this.
7978 Known problem: if you look carefully at the animation
7979 of pieces in mono mode, they are being drawn as solid
7980 shapes without interior detail while moving. Fixing
7981 this would be a major complication for minimal return.
7984 /* Masks for XPM pieces. Black and white pieces can have
7985 different shapes, but in the interest of retaining my
7986 sanity pieces must have the same outline on both light
7987 and dark squares, and all pieces must use the same
7988 background square colors/images. */
7990 static int xpmDone = 0;
7993 CreateAnimMasks (pieceDepth)
8000 unsigned long plane;
8003 /* Need a bitmap just to get a GC with right depth */
8004 buf = XCreatePixmap(xDisplay, xBoardWindow,
8006 values.foreground = 1;
8007 values.background = 0;
8008 /* Don't use XtGetGC, not read only */
8009 maskGC = XCreateGC(xDisplay, buf,
8010 GCForeground | GCBackground, &values);
8011 XFreePixmap(xDisplay, buf);
8013 buf = XCreatePixmap(xDisplay, xBoardWindow,
8014 squareSize, squareSize, pieceDepth);
8015 values.foreground = XBlackPixel(xDisplay, xScreen);
8016 values.background = XWhitePixel(xDisplay, xScreen);
8017 bufGC = XCreateGC(xDisplay, buf,
8018 GCForeground | GCBackground, &values);
8020 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8021 /* Begin with empty mask */
8022 if(!xpmDone) // [HGM] pieces: keep using existing
8023 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8024 squareSize, squareSize, 1);
8025 XSetFunction(xDisplay, maskGC, GXclear);
8026 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8027 0, 0, squareSize, squareSize);
8029 /* Take a copy of the piece */
8034 XSetFunction(xDisplay, bufGC, GXcopy);
8035 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8037 0, 0, squareSize, squareSize, 0, 0);
8039 /* XOR the background (light) over the piece */
8040 XSetFunction(xDisplay, bufGC, GXxor);
8042 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8043 0, 0, squareSize, squareSize, 0, 0);
8045 XSetForeground(xDisplay, bufGC, lightSquareColor);
8046 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8049 /* We now have an inverted piece image with the background
8050 erased. Construct mask by just selecting all the non-zero
8051 pixels - no need to reconstruct the original image. */
8052 XSetFunction(xDisplay, maskGC, GXor);
8054 /* Might be quicker to download an XImage and create bitmap
8055 data from it rather than this N copies per piece, but it
8056 only takes a fraction of a second and there is a much
8057 longer delay for loading the pieces. */
8058 for (n = 0; n < pieceDepth; n ++) {
8059 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8060 0, 0, squareSize, squareSize,
8066 XFreePixmap(xDisplay, buf);
8067 XFreeGC(xDisplay, bufGC);
8068 XFreeGC(xDisplay, maskGC);
8072 InitAnimState (anim, info)
8074 XWindowAttributes * info;
8079 /* Each buffer is square size, same depth as window */
8080 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8081 squareSize, squareSize, info->depth);
8082 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8083 squareSize, squareSize, info->depth);
8085 /* Create a plain GC for blitting */
8086 mask = GCForeground | GCBackground | GCFunction |
8087 GCPlaneMask | GCGraphicsExposures;
8088 values.foreground = XBlackPixel(xDisplay, xScreen);
8089 values.background = XWhitePixel(xDisplay, xScreen);
8090 values.function = GXcopy;
8091 values.plane_mask = AllPlanes;
8092 values.graphics_exposures = False;
8093 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8095 /* Piece will be copied from an existing context at
8096 the start of each new animation/drag. */
8097 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8099 /* Outline will be a read-only copy of an existing */
8100 anim->outlineGC = None;
8106 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8107 XWindowAttributes info;
8109 if (xpmDone && gameInfo.variant == old) return;
8110 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8111 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8113 InitAnimState(&game, &info);
8114 InitAnimState(&player, &info);
8116 /* For XPM pieces, we need bitmaps to use as masks. */
8118 CreateAnimMasks(info.depth);
8124 static Boolean frameWaiting;
8126 static RETSIGTYPE FrameAlarm (sig)
8129 frameWaiting = False;
8130 /* In case System-V style signals. Needed?? */
8131 signal(SIGALRM, FrameAlarm);
8138 struct itimerval delay;
8140 XSync(xDisplay, False);
8143 frameWaiting = True;
8144 signal(SIGALRM, FrameAlarm);
8145 delay.it_interval.tv_sec =
8146 delay.it_value.tv_sec = time / 1000;
8147 delay.it_interval.tv_usec =
8148 delay.it_value.tv_usec = (time % 1000) * 1000;
8149 setitimer(ITIMER_REAL, &delay, NULL);
8150 while (frameWaiting) pause();
8151 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8152 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8153 setitimer(ITIMER_REAL, &delay, NULL);
8163 XSync(xDisplay, False);
8165 usleep(time * 1000);
8170 /* Convert board position to corner of screen rect and color */
8173 ScreenSquare(column, row, pt, color)
8174 int column; int row; XPoint * pt; int * color;
8177 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8178 pt->y = lineGap + row * (squareSize + lineGap);
8180 pt->x = lineGap + column * (squareSize + lineGap);
8181 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8183 *color = SquareColor(row, column);
8186 /* Convert window coords to square */
8189 BoardSquare(x, y, column, row)
8190 int x; int y; int * column; int * row;
8192 *column = EventToSquare(x, BOARD_WIDTH);
8193 if (flipView && *column >= 0)
8194 *column = BOARD_WIDTH - 1 - *column;
8195 *row = EventToSquare(y, BOARD_HEIGHT);
8196 if (!flipView && *row >= 0)
8197 *row = BOARD_HEIGHT - 1 - *row;
8202 #undef Max /* just in case */
8204 #define Max(a, b) ((a) > (b) ? (a) : (b))
8205 #define Min(a, b) ((a) < (b) ? (a) : (b))
8208 SetRect(rect, x, y, width, height)
8209 XRectangle * rect; int x; int y; int width; int height;
8213 rect->width = width;
8214 rect->height = height;
8217 /* Test if two frames overlap. If they do, return
8218 intersection rect within old and location of
8219 that rect within new. */
8222 Intersect(old, new, size, area, pt)
8223 XPoint * old; XPoint * new;
8224 int size; XRectangle * area; XPoint * pt;
8226 if (old->x > new->x + size || new->x > old->x + size ||
8227 old->y > new->y + size || new->y > old->y + size) {
8230 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8231 size - abs(old->x - new->x), size - abs(old->y - new->y));
8232 pt->x = Max(old->x - new->x, 0);
8233 pt->y = Max(old->y - new->y, 0);
8238 /* For two overlapping frames, return the rect(s)
8239 in the old that do not intersect with the new. */
8242 CalcUpdateRects(old, new, size, update, nUpdates)
8243 XPoint * old; XPoint * new; int size;
8244 XRectangle update[]; int * nUpdates;
8248 /* If old = new (shouldn't happen) then nothing to draw */
8249 if (old->x == new->x && old->y == new->y) {
8253 /* Work out what bits overlap. Since we know the rects
8254 are the same size we don't need a full intersect calc. */
8256 /* Top or bottom edge? */
8257 if (new->y > old->y) {
8258 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8260 } else if (old->y > new->y) {
8261 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8262 size, old->y - new->y);
8265 /* Left or right edge - don't overlap any update calculated above. */
8266 if (new->x > old->x) {
8267 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8268 new->x - old->x, size - abs(new->y - old->y));
8270 } else if (old->x > new->x) {
8271 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8272 old->x - new->x, size - abs(new->y - old->y));
8279 /* Generate a series of frame coords from start->mid->finish.
8280 The movement rate doubles until the half way point is
8281 reached, then halves back down to the final destination,
8282 which gives a nice slow in/out effect. The algorithmn
8283 may seem to generate too many intermediates for short
8284 moves, but remember that the purpose is to attract the
8285 viewers attention to the piece about to be moved and
8286 then to where it ends up. Too few frames would be less
8290 Tween(start, mid, finish, factor, frames, nFrames)
8291 XPoint * start; XPoint * mid;
8292 XPoint * finish; int factor;
8293 XPoint frames[]; int * nFrames;
8295 int fraction, n, count;
8299 /* Slow in, stepping 1/16th, then 1/8th, ... */
8301 for (n = 0; n < factor; n++)
8303 for (n = 0; n < factor; n++) {
8304 frames[count].x = start->x + (mid->x - start->x) / fraction;
8305 frames[count].y = start->y + (mid->y - start->y) / fraction;
8307 fraction = fraction / 2;
8311 frames[count] = *mid;
8314 /* Slow out, stepping 1/2, then 1/4, ... */
8316 for (n = 0; n < factor; n++) {
8317 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8318 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8320 fraction = fraction * 2;
8325 /* Draw a piece on the screen without disturbing what's there */
8328 SelectGCMask(piece, clip, outline, mask)
8329 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8333 /* Bitmap for piece being moved. */
8334 if (appData.monoMode) {
8335 *mask = *pieceToSolid(piece);
8336 } else if (useImages) {
8338 *mask = xpmMask[piece];
8340 *mask = ximMaskPm[piece];
8343 *mask = *pieceToSolid(piece);
8346 /* GC for piece being moved. Square color doesn't matter, but
8347 since it gets modified we make a copy of the original. */
8349 if (appData.monoMode)
8354 if (appData.monoMode)
8359 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8361 /* Outline only used in mono mode and is not modified */
8363 *outline = bwPieceGC;
8365 *outline = wbPieceGC;
8369 OverlayPiece(piece, clip, outline, dest)
8370 ChessSquare piece; GC clip; GC outline; Drawable dest;
8375 /* Draw solid rectangle which will be clipped to shape of piece */
8376 XFillRectangle(xDisplay, dest, clip,
8377 0, 0, squareSize, squareSize);
8378 if (appData.monoMode)
8379 /* Also draw outline in contrasting color for black
8380 on black / white on white cases */
8381 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8382 0, 0, squareSize, squareSize, 0, 0, 1);
8384 /* Copy the piece */
8389 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8391 0, 0, squareSize, squareSize,
8396 /* Animate the movement of a single piece */
8399 BeginAnimation(anim, piece, startColor, start)
8407 /* The old buffer is initialised with the start square (empty) */
8408 BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8409 anim->prevFrame = *start;
8411 /* The piece will be drawn using its own bitmap as a matte */
8412 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8413 XSetClipMask(xDisplay, anim->pieceGC, mask);
8417 AnimationFrame(anim, frame, piece)
8422 XRectangle updates[4];
8427 /* Save what we are about to draw into the new buffer */
8428 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8429 frame->x, frame->y, squareSize, squareSize,
8432 /* Erase bits of the previous frame */
8433 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8434 /* Where the new frame overlapped the previous,
8435 the contents in newBuf are wrong. */
8436 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8437 overlap.x, overlap.y,
8438 overlap.width, overlap.height,
8440 /* Repaint the areas in the old that don't overlap new */
8441 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8442 for (i = 0; i < count; i++)
8443 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8444 updates[i].x - anim->prevFrame.x,
8445 updates[i].y - anim->prevFrame.y,
8446 updates[i].width, updates[i].height,
8447 updates[i].x, updates[i].y);
8449 /* Easy when no overlap */
8450 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8451 0, 0, squareSize, squareSize,
8452 anim->prevFrame.x, anim->prevFrame.y);
8455 /* Save this frame for next time round */
8456 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8457 0, 0, squareSize, squareSize,
8459 anim->prevFrame = *frame;
8461 /* Draw piece over original screen contents, not current,
8462 and copy entire rect. Wipes out overlapping piece images. */
8463 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8464 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8465 0, 0, squareSize, squareSize,
8466 frame->x, frame->y);
8470 EndAnimation (anim, finish)
8474 XRectangle updates[4];
8479 /* The main code will redraw the final square, so we
8480 only need to erase the bits that don't overlap. */
8481 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8482 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8483 for (i = 0; i < count; i++)
8484 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8485 updates[i].x - anim->prevFrame.x,
8486 updates[i].y - anim->prevFrame.y,
8487 updates[i].width, updates[i].height,
8488 updates[i].x, updates[i].y);
8490 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8491 0, 0, squareSize, squareSize,
8492 anim->prevFrame.x, anim->prevFrame.y);
8497 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8499 ChessSquare piece; int startColor;
8500 XPoint * start; XPoint * finish;
8501 XPoint frames[]; int nFrames;
8505 BeginAnimation(anim, piece, startColor, start);
8506 for (n = 0; n < nFrames; n++) {
8507 AnimationFrame(anim, &(frames[n]), piece);
8508 FrameDelay(appData.animSpeed);
8510 EndAnimation(anim, finish);
8513 /* Main control logic for deciding what to animate and how */
8516 AnimateMove(board, fromX, fromY, toX, toY)
8525 XPoint start, finish, mid;
8526 XPoint frames[kFactor * 2 + 1];
8527 int nFrames, startColor, endColor;
8529 /* Are we animating? */
8530 if (!appData.animate || appData.blindfold)
8533 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8534 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8535 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8537 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8538 piece = board[fromY][fromX];
8539 if (piece >= EmptySquare) return;
8544 hop = (piece == WhiteKnight || piece == BlackKnight);
8547 if (appData.debugMode) {
8548 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8549 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8550 piece, fromX, fromY, toX, toY); }
8552 ScreenSquare(fromX, fromY, &start, &startColor);
8553 ScreenSquare(toX, toY, &finish, &endColor);
8556 /* Knight: make diagonal movement then straight */
8557 if (abs(toY - fromY) < abs(toX - fromX)) {
8558 mid.x = start.x + (finish.x - start.x) / 2;
8562 mid.y = start.y + (finish.y - start.y) / 2;
8565 mid.x = start.x + (finish.x - start.x) / 2;
8566 mid.y = start.y + (finish.y - start.y) / 2;
8569 /* Don't use as many frames for very short moves */
8570 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8571 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8573 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8574 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8576 /* Be sure end square is redrawn */
8577 damage[toY][toX] = True;
8581 DragPieceBegin(x, y)
8584 int boardX, boardY, color;
8587 /* Are we animating? */
8588 if (!appData.animateDragging || appData.blindfold)
8591 /* Figure out which square we start in and the
8592 mouse position relative to top left corner. */
8593 BoardSquare(x, y, &boardX, &boardY);
8594 player.startBoardX = boardX;
8595 player.startBoardY = boardY;
8596 ScreenSquare(boardX, boardY, &corner, &color);
8597 player.startSquare = corner;
8598 player.startColor = color;
8599 /* As soon as we start dragging, the piece will jump slightly to
8600 be centered over the mouse pointer. */
8601 player.mouseDelta.x = squareSize/2;
8602 player.mouseDelta.y = squareSize/2;
8603 /* Initialise animation */
8604 player.dragPiece = PieceForSquare(boardX, boardY);
8606 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8607 player.dragActive = True;
8608 BeginAnimation(&player, player.dragPiece, color, &corner);
8609 /* Mark this square as needing to be redrawn. Note that
8610 we don't remove the piece though, since logically (ie
8611 as seen by opponent) the move hasn't been made yet. */
8612 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8613 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8614 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8615 corner.x, corner.y, squareSize, squareSize,
8616 0, 0); // [HGM] zh: unstack in stead of grab
8617 damage[boardY][boardX] = True;
8619 player.dragActive = False;
8629 /* Are we animating? */
8630 if (!appData.animateDragging || appData.blindfold)
8634 if (! player.dragActive)
8636 /* Move piece, maintaining same relative position
8637 of mouse within square */
8638 corner.x = x - player.mouseDelta.x;
8639 corner.y = y - player.mouseDelta.y;
8640 AnimationFrame(&player, &corner, player.dragPiece);
8642 if (appData.highlightDragging) {
8644 BoardSquare(x, y, &boardX, &boardY);
8645 SetHighlights(fromX, fromY, boardX, boardY);
8654 int boardX, boardY, color;
8657 /* Are we animating? */
8658 if (!appData.animateDragging || appData.blindfold)
8662 if (! player.dragActive)
8664 /* Last frame in sequence is square piece is
8665 placed on, which may not match mouse exactly. */
8666 BoardSquare(x, y, &boardX, &boardY);
8667 ScreenSquare(boardX, boardY, &corner, &color);
8668 EndAnimation(&player, &corner);
8670 /* Be sure end square is redrawn */
8671 damage[boardY][boardX] = True;
8673 /* This prevents weird things happening with fast successive
8674 clicks which on my Sun at least can cause motion events
8675 without corresponding press/release. */
8676 player.dragActive = False;
8679 /* Handle expose event while piece being dragged */
8684 if (!player.dragActive || appData.blindfold)
8687 /* What we're doing: logically, the move hasn't been made yet,
8688 so the piece is still in it's original square. But visually
8689 it's being dragged around the board. So we erase the square
8690 that the piece is on and draw it at the last known drag point. */
8691 BlankSquare(player.startSquare.x, player.startSquare.y,
8692 player.startColor, EmptySquare, xBoardWindow);
8693 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8694 damage[player.startBoardY][player.startBoardX] = TRUE;
8697 #include <sys/ioctl.h>
8698 int get_term_width()
8700 int fd, default_width;
8703 default_width = 79; // this is FICS default anyway...
8705 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8707 if (!ioctl(fd, TIOCGSIZE, &win))
8708 default_width = win.ts_cols;
8709 #elif defined(TIOCGWINSZ)
8711 if (!ioctl(fd, TIOCGWINSZ, &win))
8712 default_width = win.ws_col;
8714 return default_width;
8717 void update_ics_width()
8719 static int old_width = 0;
8720 int new_width = get_term_width();
8722 if (old_width != new_width)
8723 ics_printf("set width %d\n", new_width);
8724 old_width = new_width;
8727 void NotifyFrontendLogin()