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. */
58 #include <sys/types.h>
63 # if HAVE_SYS_SOCKET_H
64 # include <sys/socket.h>
65 # include <netinet/in.h>
67 # else /* not HAVE_SYS_SOCKET_H */
68 # if HAVE_LAN_SOCKET_H
69 # include <lan/socket.h>
71 # include <lan/netdb.h>
72 # else /* not HAVE_LAN_SOCKET_H */
73 # define OMIT_SOCKETS 1
74 # endif /* not HAVE_LAN_SOCKET_H */
75 # endif /* not HAVE_SYS_SOCKET_H */
76 #endif /* !OMIT_SOCKETS */
81 #else /* not STDC_HEADERS */
82 extern char *getenv();
85 # else /* not HAVE_STRING_H */
87 # endif /* not HAVE_STRING_H */
88 #endif /* not STDC_HEADERS */
91 # include <sys/fcntl.h>
92 #else /* not HAVE_SYS_FCNTL_H */
95 # endif /* HAVE_FCNTL_H */
96 #endif /* not HAVE_SYS_FCNTL_H */
98 #if HAVE_SYS_SYSTEMINFO_H
99 # include <sys/systeminfo.h>
100 #endif /* HAVE_SYS_SYSTEMINFO_H */
102 #if TIME_WITH_SYS_TIME
103 # include <sys/time.h>
107 # include <sys/time.h>
118 # include <sys/wait.h>
123 # define NAMLEN(dirent) strlen((dirent)->d_name)
124 # define HAVE_DIR_STRUCT
126 # define dirent direct
127 # define NAMLEN(dirent) (dirent)->d_namlen
129 # include <sys/ndir.h>
130 # define HAVE_DIR_STRUCT
133 # include <sys/dir.h>
134 # define HAVE_DIR_STRUCT
138 # define HAVE_DIR_STRUCT
142 #include <X11/Intrinsic.h>
143 #include <X11/StringDefs.h>
144 #include <X11/Shell.h>
145 #include <X11/cursorfont.h>
146 #include <X11/Xatom.h>
147 #include <X11/Xmu/Atoms.h>
149 #include <X11/Xaw3d/Dialog.h>
150 #include <X11/Xaw3d/Form.h>
151 #include <X11/Xaw3d/List.h>
152 #include <X11/Xaw3d/Label.h>
153 #include <X11/Xaw3d/SimpleMenu.h>
154 #include <X11/Xaw3d/SmeBSB.h>
155 #include <X11/Xaw3d/SmeLine.h>
156 #include <X11/Xaw3d/Box.h>
157 #include <X11/Xaw3d/MenuButton.h>
158 #include <X11/Xaw3d/Text.h>
159 #include <X11/Xaw3d/AsciiText.h>
161 #include <X11/Xaw/Dialog.h>
162 #include <X11/Xaw/Form.h>
163 #include <X11/Xaw/List.h>
164 #include <X11/Xaw/Label.h>
165 #include <X11/Xaw/SimpleMenu.h>
166 #include <X11/Xaw/SmeBSB.h>
167 #include <X11/Xaw/SmeLine.h>
168 #include <X11/Xaw/Box.h>
169 #include <X11/Xaw/MenuButton.h>
170 #include <X11/Xaw/Text.h>
171 #include <X11/Xaw/AsciiText.h>
174 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
179 #include "pixmaps/pixmaps.h"
180 #define IMAGE_EXT "xpm"
182 #define IMAGE_EXT "xim"
183 #include "bitmaps/bitmaps.h"
186 #include "bitmaps/icon_white.bm"
187 #include "bitmaps/icon_black.bm"
188 #include "bitmaps/checkmark.bm"
190 #include "frontend.h"
195 #include "xgamelist.h"
196 #include "xhistory.h"
197 #include "xedittags.h"
200 // must be moved to xengineoutput.h
202 void EngineOutputProc P((Widget w, XEvent *event,
203 String *prms, Cardinal *nprms));
204 void EvalGraphProc P((Widget w, XEvent *event,
205 String *prms, Cardinal *nprms));
212 #define usleep(t) _sleep2(((t)+500)/1000)
216 # define _(s) gettext (s)
217 # define N_(s) gettext_noop (s)
233 int main P((int argc, char **argv));
234 RETSIGTYPE CmailSigHandler P((int sig));
235 RETSIGTYPE IntSigHandler P((int sig));
236 RETSIGTYPE TermSizeSigHandler P((int sig));
237 void CreateGCs P((void));
238 void CreateXIMPieces P((void));
239 void CreateXPMPieces P((void));
240 void CreatePieces P((void));
241 void CreatePieceMenus P((void));
242 Widget CreateMenuBar P((Menu *mb));
243 Widget CreateButtonBar P ((MenuItem *mi));
244 char *FindFont P((char *pattern, int targetPxlSize));
245 void PieceMenuPopup P((Widget w, XEvent *event,
246 String *params, Cardinal *num_params));
247 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
248 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
249 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
250 u_int wreq, u_int hreq));
251 void CreateGrid P((void));
252 int EventToSquare P((int x, int limit));
253 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
254 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
255 void HandleUserMove P((Widget w, XEvent *event,
256 String *prms, Cardinal *nprms));
257 void AnimateUserMove P((Widget w, XEvent * event,
258 String * params, Cardinal * nParams));
259 void WhiteClock P((Widget w, XEvent *event,
260 String *prms, Cardinal *nprms));
261 void BlackClock P((Widget w, XEvent *event,
262 String *prms, Cardinal *nprms));
263 void DrawPositionProc P((Widget w, XEvent *event,
264 String *prms, Cardinal *nprms));
265 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
267 void CommentPopUp P((char *title, char *label));
268 void CommentPopDown P((void));
269 void CommentCallback P((Widget w, XtPointer client_data,
270 XtPointer call_data));
271 void ICSInputBoxPopUp P((void));
272 void ICSInputBoxPopDown P((void));
273 void FileNamePopUp P((char *label, char *def,
274 FileProc proc, char *openMode));
275 void FileNamePopDown P((void));
276 void FileNameCallback P((Widget w, XtPointer client_data,
277 XtPointer call_data));
278 void FileNameAction P((Widget w, XEvent *event,
279 String *prms, Cardinal *nprms));
280 void AskQuestionReplyAction P((Widget w, XEvent *event,
281 String *prms, Cardinal *nprms));
282 void AskQuestionProc P((Widget w, XEvent *event,
283 String *prms, Cardinal *nprms));
284 void AskQuestionPopDown P((void));
285 void PromotionPopDown P((void));
286 void PromotionCallback P((Widget w, XtPointer client_data,
287 XtPointer call_data));
288 void EditCommentPopDown P((void));
289 void EditCommentCallback P((Widget w, XtPointer client_data,
290 XtPointer call_data));
291 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
292 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
293 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
294 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
296 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
298 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
300 void LoadPositionProc P((Widget w, XEvent *event,
301 String *prms, Cardinal *nprms));
302 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
304 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
306 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
308 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
310 void PastePositionProc P((Widget w, XEvent *event, String *prms,
312 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
313 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
314 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
315 void SavePositionProc P((Widget w, XEvent *event,
316 String *prms, Cardinal *nprms));
317 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
318 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
320 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
321 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
322 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
324 void MachineWhiteProc P((Widget w, XEvent *event,
325 String *prms, Cardinal *nprms));
326 void AnalyzeModeProc P((Widget w, XEvent *event,
327 String *prms, Cardinal *nprms));
328 void AnalyzeFileProc P((Widget w, XEvent *event,
329 String *prms, Cardinal *nprms));
330 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
332 void IcsClientProc P((Widget w, XEvent *event, String *prms,
334 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
335 void EditPositionProc P((Widget w, XEvent *event,
336 String *prms, Cardinal *nprms));
337 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
338 void EditCommentProc P((Widget w, XEvent *event,
339 String *prms, Cardinal *nprms));
340 void IcsInputBoxProc P((Widget w, XEvent *event,
341 String *prms, Cardinal *nprms));
342 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
343 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
344 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
345 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
346 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
347 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
348 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
349 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
350 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
351 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
352 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
353 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
354 void StopObservingProc P((Widget w, XEvent *event, String *prms,
356 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
358 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
365 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
367 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
370 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
372 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
374 void AutocommProc P((Widget w, XEvent *event, String *prms,
376 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
377 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void AutobsProc P((Widget w, XEvent *event, String *prms,
380 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
385 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
386 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
388 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
390 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
392 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
393 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
394 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
396 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
398 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
400 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
402 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
404 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
405 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
406 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
408 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
410 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
412 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
414 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
415 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
416 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
417 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
418 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
419 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
420 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
421 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
422 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
423 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
424 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
425 void DisplayMove P((int moveNumber));
426 void DisplayTitle P((char *title));
427 void ICSInitScript P((void));
428 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
429 void ErrorPopUp P((char *title, char *text, int modal));
430 void ErrorPopDown P((void));
431 static char *ExpandPathName P((char *path));
432 static void CreateAnimVars P((void));
433 static void DragPieceMove P((int x, int y));
434 static void DrawDragPiece P((void));
435 char *ModeToWidgetName P((GameMode mode));
436 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
442 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
443 void ShufflePopDown P(());
444 void EnginePopDown P(());
445 void UciPopDown P(());
446 void TimeControlPopDown P(());
447 void NewVariantPopDown P(());
448 void SettingsPopDown P(());
449 void update_ics_width P(());
450 int get_term_width P(());
451 int CopyMemoProc P(());
453 * XBoard depends on Xt R4 or higher
455 int xtVersion = XtSpecificationRelease;
460 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
461 jailSquareColor, highlightSquareColor, premoveHighlightColor;
462 Pixel lowTimeWarningColor;
463 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
464 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
465 wjPieceGC, bjPieceGC, prelineGC, countGC;
466 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
467 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
468 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
469 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
470 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
471 ICSInputShell, fileNameShell, askQuestionShell;
472 Widget historyShell, evalGraphShell, gameListShell;
473 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
474 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
475 Font clockFontID, coordFontID, countFontID;
476 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
477 XtAppContext appContext;
479 char *oldICSInteractionTitle;
483 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
485 Position commentX = -1, commentY = -1;
486 Dimension commentW, commentH;
487 typedef unsigned int BoardSize;
489 Boolean chessProgram;
491 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
492 int squareSize, smallLayout = 0, tinyLayout = 0,
493 marginW, marginH, // [HGM] for run-time resizing
494 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
495 ICSInputBoxUp = False, askQuestionUp = False,
496 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
497 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
498 Pixel timerForegroundPixel, timerBackgroundPixel;
499 Pixel buttonForegroundPixel, buttonBackgroundPixel;
500 char *chessDir, *programName, *programVersion,
501 *gameCopyFilename, *gamePasteFilename;
502 Boolean alwaysOnTop = False;
503 Boolean saveSettingsOnExit;
504 char *settingsFileName;
505 char *icsTextMenuString;
507 char *firstChessProgramNames;
508 char *secondChessProgramNames;
510 WindowPlacement wpMain;
511 WindowPlacement wpConsole;
512 WindowPlacement wpComment;
513 WindowPlacement wpMoveHistory;
514 WindowPlacement wpEvalGraph;
515 WindowPlacement wpEngineOutput;
516 WindowPlacement wpGameList;
517 WindowPlacement wpTags;
521 Pixmap pieceBitmap[2][(int)BlackPawn];
522 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
523 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
524 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
525 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
526 int useImages, useImageSqs;
527 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
528 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
529 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
530 XImage *ximLightSquare, *ximDarkSquare;
533 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
534 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
536 #define White(piece) ((int)(piece) < (int)BlackPawn)
538 /* Variables for doing smooth animation. This whole thing
539 would be much easier if the board was double-buffered,
540 but that would require a fairly major rewrite. */
545 GC blitGC, pieceGC, outlineGC;
546 XPoint startSquare, prevFrame, mouseDelta;
550 int startBoardX, startBoardY;
553 /* There can be two pieces being animated at once: a player
554 can begin dragging a piece before the remote opponent has moved. */
556 static AnimState game, player;
558 /* Bitmaps for use as masks when drawing XPM pieces.
559 Need one for each black and white piece. */
560 static Pixmap xpmMask[BlackKing + 1];
562 /* This magic number is the number of intermediate frames used
563 in each half of the animation. For short moves it's reduced
564 by 1. The total number of frames will be factor * 2 + 1. */
567 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
569 MenuItem fileMenu[] = {
570 {N_("New Game"), ResetProc},
571 {N_("New Shuffle Game ..."), ShuffleMenuProc},
572 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
573 {"----", NothingProc},
574 {N_("Load Game"), LoadGameProc},
575 {N_("Load Next Game"), LoadNextGameProc},
576 {N_("Load Previous Game"), LoadPrevGameProc},
577 {N_("Reload Same Game"), ReloadGameProc},
578 {N_("Save Game"), SaveGameProc},
579 {"----", NothingProc},
580 {N_("Copy Game"), CopyGameProc},
581 {N_("Paste Game"), PasteGameProc},
582 {"----", NothingProc},
583 {N_("Load Position"), LoadPositionProc},
584 {N_("Load Next Position"), LoadNextPositionProc},
585 {N_("Load Previous Position"), LoadPrevPositionProc},
586 {N_("Reload Same Position"), ReloadPositionProc},
587 {N_("Save Position"), SavePositionProc},
588 {"----", NothingProc},
589 {N_("Copy Position"), CopyPositionProc},
590 {N_("Paste Position"), PastePositionProc},
591 {"----", NothingProc},
592 {N_("Mail Move"), MailMoveProc},
593 {N_("Reload CMail Message"), ReloadCmailMsgProc},
594 {"----", NothingProc},
595 {N_("Exit"), QuitProc},
599 MenuItem modeMenu[] = {
600 {N_("Machine White"), MachineWhiteProc},
601 {N_("Machine Black"), MachineBlackProc},
602 {N_("Two Machines"), TwoMachinesProc},
603 {N_("Analysis Mode"), AnalyzeModeProc},
604 {N_("Analyze File"), AnalyzeFileProc },
605 {N_("ICS Client"), IcsClientProc},
606 {N_("Edit Game"), EditGameProc},
607 {N_("Edit Position"), EditPositionProc},
608 {N_("Training"), TrainingProc},
609 {"----", NothingProc},
610 {N_("Show Engine Output"), EngineOutputProc},
611 {N_("Show Evaluation Graph"), EvalGraphProc},
612 {N_("Show Game List"), ShowGameListProc},
613 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
614 {"----", NothingProc},
615 {N_("Edit Tags"), EditTagsProc},
616 {N_("Edit Comment"), EditCommentProc},
617 {N_("ICS Input Box"), IcsInputBoxProc},
618 {N_("Pause"), PauseProc},
622 MenuItem actionMenu[] = {
623 {N_("Accept"), AcceptProc},
624 {N_("Decline"), DeclineProc},
625 {N_("Rematch"), RematchProc},
626 {"----", NothingProc},
627 {N_("Call Flag"), CallFlagProc},
628 {N_("Draw"), DrawProc},
629 {N_("Adjourn"), AdjournProc},
630 {N_("Abort"), AbortProc},
631 {N_("Resign"), ResignProc},
632 {"----", NothingProc},
633 {N_("Stop Observing"), StopObservingProc},
634 {N_("Stop Examining"), StopExaminingProc},
635 {"----", NothingProc},
636 {N_("Adjudicate to White"), AdjuWhiteProc},
637 {N_("Adjudicate to Black"), AdjuBlackProc},
638 {N_("Adjudicate Draw"), AdjuDrawProc},
642 MenuItem stepMenu[] = {
643 {N_("Backward"), BackwardProc},
644 {N_("Forward"), ForwardProc},
645 {N_("Back to Start"), ToStartProc},
646 {N_("Forward to End"), ToEndProc},
647 {N_("Revert"), RevertProc},
648 {N_("Truncate Game"), TruncateGameProc},
649 {"----", NothingProc},
650 {N_("Move Now"), MoveNowProc},
651 {N_("Retract Move"), RetractMoveProc},
655 MenuItem optionsMenu[] = {
656 {N_("Flip View"), FlipViewProc},
657 {"----", NothingProc},
658 {N_("Adjudications ..."), EngineMenuProc},
659 {N_("General Settings ..."), UciMenuProc},
660 {N_("Engine #1 Settings ..."), FirstSettingsProc},
661 {N_("Engine #2 Settings ..."), SecondSettingsProc},
662 {N_("Time Control ..."), TimeControlProc},
663 {"----", NothingProc},
664 {N_("Always Queen"), AlwaysQueenProc},
665 {N_("Animate Dragging"), AnimateDraggingProc},
666 {N_("Animate Moving"), AnimateMovingProc},
667 {N_("Auto Comment"), AutocommProc},
668 {N_("Auto Flag"), AutoflagProc},
669 {N_("Auto Flip View"), AutoflipProc},
670 {N_("Auto Observe"), AutobsProc},
671 {N_("Auto Raise Board"), AutoraiseProc},
672 {N_("Auto Save"), AutosaveProc},
673 {N_("Blindfold"), BlindfoldProc},
674 {N_("Flash Moves"), FlashMovesProc},
675 {N_("Get Move List"), GetMoveListProc},
677 {N_("Highlight Dragging"), HighlightDraggingProc},
679 {N_("Highlight Last Move"), HighlightLastMoveProc},
680 {N_("Move Sound"), MoveSoundProc},
681 {N_("ICS Alarm"), IcsAlarmProc},
682 {N_("Old Save Style"), OldSaveStyleProc},
683 {N_("Periodic Updates"), PeriodicUpdatesProc},
684 {N_("Ponder Next Move"), PonderNextMoveProc},
685 {N_("Popup Exit Message"), PopupExitMessageProc},
686 {N_("Popup Move Errors"), PopupMoveErrorsProc},
687 {N_("Premove"), PremoveProc},
688 {N_("Quiet Play"), QuietPlayProc},
689 {N_("Show Coords"), ShowCoordsProc},
690 {N_("Hide Thinking"), HideThinkingProc},
691 {N_("Test Legality"), TestLegalityProc},
692 {"----", NothingProc},
693 {N_("Save Settings Now"), SaveSettingsProc},
694 {N_("Save Settings on Exit"), SaveOnExitProc},
698 MenuItem helpMenu[] = {
699 {N_("Info XBoard"), InfoProc},
700 {N_("Man XBoard"), ManProc},
701 {"----", NothingProc},
702 {N_("Hint"), HintProc},
703 {N_("Book"), BookProc},
704 {"----", NothingProc},
705 {N_("About XBoard"), AboutProc},
710 {N_("File"), fileMenu},
711 {N_("Mode"), modeMenu},
712 {N_("Action"), actionMenu},
713 {N_("Step"), stepMenu},
714 {N_("Options"), optionsMenu},
715 {N_("Help"), helpMenu},
719 #define PAUSE_BUTTON N_("P")
720 MenuItem buttonBar[] = {
723 {PAUSE_BUTTON, PauseProc},
729 #define PIECE_MENU_SIZE 18
730 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
731 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
732 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
733 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
734 N_("Empty square"), N_("Clear board") },
735 { N_("Black"), "----", 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") }
740 /* must be in same order as PieceMenuStrings! */
741 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
742 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
743 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
744 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
745 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
746 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
747 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
748 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
749 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
752 #define DROP_MENU_SIZE 6
753 String dropMenuStrings[DROP_MENU_SIZE] = {
754 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
756 /* must be in same order as PieceMenuStrings! */
757 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
758 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
759 WhiteRook, WhiteQueen
767 DropMenuEnables dmEnables[] = {
785 { XtNborderWidth, 0 },
786 { XtNdefaultDistance, 0 },
790 { XtNborderWidth, 0 },
791 { XtNresizable, (XtArgVal) True },
795 { XtNborderWidth, 0 },
801 { XtNjustify, (XtArgVal) XtJustifyRight },
802 { XtNlabel, (XtArgVal) "..." },
803 { XtNresizable, (XtArgVal) True },
804 { XtNresize, (XtArgVal) False }
807 Arg messageArgs[] = {
808 { XtNjustify, (XtArgVal) XtJustifyLeft },
809 { XtNlabel, (XtArgVal) "..." },
810 { XtNresizable, (XtArgVal) True },
811 { XtNresize, (XtArgVal) False }
815 { XtNborderWidth, 0 },
816 { XtNjustify, (XtArgVal) XtJustifyLeft }
819 XtResource clientResources[] = {
820 { "flashCount", "flashCount", XtRInt, sizeof(int),
821 XtOffset(AppDataPtr, flashCount), XtRImmediate,
822 (XtPointer) FLASH_COUNT },
825 XrmOptionDescRec shellOptions[] = {
826 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
827 { "-flash", "flashCount", XrmoptionNoArg, "3" },
828 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
831 XtActionsRec boardActions[] = {
832 { "DrawPosition", DrawPositionProc },
833 { "HandleUserMove", HandleUserMove },
834 { "AnimateUserMove", AnimateUserMove },
835 { "FileNameAction", FileNameAction },
836 { "AskQuestionProc", AskQuestionProc },
837 { "AskQuestionReplyAction", AskQuestionReplyAction },
838 { "PieceMenuPopup", PieceMenuPopup },
839 { "WhiteClock", WhiteClock },
840 { "BlackClock", BlackClock },
841 { "Iconify", Iconify },
842 { "ResetProc", ResetProc },
843 { "LoadGameProc", LoadGameProc },
844 { "LoadNextGameProc", LoadNextGameProc },
845 { "LoadPrevGameProc", LoadPrevGameProc },
846 { "LoadSelectedProc", LoadSelectedProc },
847 { "ReloadGameProc", ReloadGameProc },
848 { "LoadPositionProc", LoadPositionProc },
849 { "LoadNextPositionProc", LoadNextPositionProc },
850 { "LoadPrevPositionProc", LoadPrevPositionProc },
851 { "ReloadPositionProc", ReloadPositionProc },
852 { "CopyPositionProc", CopyPositionProc },
853 { "PastePositionProc", PastePositionProc },
854 { "CopyGameProc", CopyGameProc },
855 { "PasteGameProc", PasteGameProc },
856 { "SaveGameProc", SaveGameProc },
857 { "SavePositionProc", SavePositionProc },
858 { "MailMoveProc", MailMoveProc },
859 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
860 { "QuitProc", QuitProc },
861 { "MachineWhiteProc", MachineWhiteProc },
862 { "MachineBlackProc", MachineBlackProc },
863 { "AnalysisModeProc", AnalyzeModeProc },
864 { "AnalyzeFileProc", AnalyzeFileProc },
865 { "TwoMachinesProc", TwoMachinesProc },
866 { "IcsClientProc", IcsClientProc },
867 { "EditGameProc", EditGameProc },
868 { "EditPositionProc", EditPositionProc },
869 { "TrainingProc", EditPositionProc },
870 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
871 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
872 { "ShowGameListProc", ShowGameListProc },
873 { "ShowMoveListProc", HistoryShowProc},
874 { "EditTagsProc", EditCommentProc },
875 { "EditCommentProc", EditCommentProc },
876 { "IcsAlarmProc", IcsAlarmProc },
877 { "IcsInputBoxProc", IcsInputBoxProc },
878 { "PauseProc", PauseProc },
879 { "AcceptProc", AcceptProc },
880 { "DeclineProc", DeclineProc },
881 { "RematchProc", RematchProc },
882 { "CallFlagProc", CallFlagProc },
883 { "DrawProc", DrawProc },
884 { "AdjournProc", AdjournProc },
885 { "AbortProc", AbortProc },
886 { "ResignProc", ResignProc },
887 { "AdjuWhiteProc", AdjuWhiteProc },
888 { "AdjuBlackProc", AdjuBlackProc },
889 { "AdjuDrawProc", AdjuDrawProc },
890 { "EnterKeyProc", EnterKeyProc },
891 { "StopObservingProc", StopObservingProc },
892 { "StopExaminingProc", StopExaminingProc },
893 { "BackwardProc", BackwardProc },
894 { "ForwardProc", ForwardProc },
895 { "ToStartProc", ToStartProc },
896 { "ToEndProc", ToEndProc },
897 { "RevertProc", RevertProc },
898 { "TruncateGameProc", TruncateGameProc },
899 { "MoveNowProc", MoveNowProc },
900 { "RetractMoveProc", RetractMoveProc },
901 { "AlwaysQueenProc", AlwaysQueenProc },
902 { "AnimateDraggingProc", AnimateDraggingProc },
903 { "AnimateMovingProc", AnimateMovingProc },
904 { "AutoflagProc", AutoflagProc },
905 { "AutoflipProc", AutoflipProc },
906 { "AutobsProc", AutobsProc },
907 { "AutoraiseProc", AutoraiseProc },
908 { "AutosaveProc", AutosaveProc },
909 { "BlindfoldProc", BlindfoldProc },
910 { "FlashMovesProc", FlashMovesProc },
911 { "FlipViewProc", FlipViewProc },
912 { "GetMoveListProc", GetMoveListProc },
914 { "HighlightDraggingProc", HighlightDraggingProc },
916 { "HighlightLastMoveProc", HighlightLastMoveProc },
917 { "IcsAlarmProc", IcsAlarmProc },
918 { "MoveSoundProc", MoveSoundProc },
919 { "OldSaveStyleProc", OldSaveStyleProc },
920 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
921 { "PonderNextMoveProc", PonderNextMoveProc },
922 { "PopupExitMessageProc", PopupExitMessageProc },
923 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
924 { "PremoveProc", PremoveProc },
925 { "QuietPlayProc", QuietPlayProc },
926 { "ShowCoordsProc", ShowCoordsProc },
927 { "ShowThinkingProc", ShowThinkingProc },
928 { "HideThinkingProc", HideThinkingProc },
929 { "TestLegalityProc", TestLegalityProc },
930 { "SaveSettingsProc", SaveSettingsProc },
931 { "SaveOnExitProc", SaveOnExitProc },
932 { "InfoProc", InfoProc },
933 { "ManProc", ManProc },
934 { "HintProc", HintProc },
935 { "BookProc", BookProc },
936 { "AboutGameProc", AboutGameProc },
937 { "AboutProc", AboutProc },
938 { "DebugProc", DebugProc },
939 { "NothingProc", NothingProc },
940 { "CommentPopDown", (XtActionProc) CommentPopDown },
941 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
942 { "TagsPopDown", (XtActionProc) TagsPopDown },
943 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
944 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
945 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
946 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
947 { "GameListPopDown", (XtActionProc) GameListPopDown },
948 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
949 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
950 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
951 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
952 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
953 { "EnginePopDown", (XtActionProc) EnginePopDown },
954 { "UciPopDown", (XtActionProc) UciPopDown },
955 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
956 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
957 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
958 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
961 char globalTranslations[] =
962 ":<Key>R: ResignProc() \n \
963 :<Key>r: ResetProc() \n \
964 :<Key>g: LoadGameProc() \n \
965 :<Key>N: LoadNextGameProc() \n \
966 :<Key>P: LoadPrevGameProc() \n \
967 :<Key>Q: QuitProc() \n \
968 :<Key>F: ToEndProc() \n \
969 :<Key>f: ForwardProc() \n \
970 :<Key>B: ToStartProc() \n \
971 :<Key>b: BackwardProc() \n \
972 :<Key>p: PauseProc() \n \
973 :<Key>d: DrawProc() \n \
974 :<Key>t: CallFlagProc() \n \
975 :<Key>i: Iconify() \n \
976 :<Key>c: Iconify() \n \
977 :<Key>v: FlipViewProc() \n \
978 <KeyDown>Control_L: BackwardProc() \n \
979 <KeyUp>Control_L: ForwardProc() \n \
980 <KeyDown>Control_R: BackwardProc() \n \
981 <KeyUp>Control_R: ForwardProc() \n \
982 Shift<Key>1: AskQuestionProc(\"Direct command\",\
983 \"Send to chess program:\",,1) \n \
984 Shift<Key>2: AskQuestionProc(\"Direct command\",\
985 \"Send to second chess program:\",,2) \n";
987 char boardTranslations[] =
988 "<Btn1Down>: HandleUserMove() \n \
989 <Btn1Up>: HandleUserMove() \n \
990 <Btn1Motion>: AnimateUserMove() \n \
991 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
992 PieceMenuPopup(menuB) \n \
993 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
994 PieceMenuPopup(menuW) \n \
995 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
996 PieceMenuPopup(menuW) \n \
997 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
998 PieceMenuPopup(menuB) \n";
1000 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1001 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1003 char ICSInputTranslations[] =
1004 "<Key>Return: EnterKeyProc() \n";
1006 String xboardResources[] = {
1007 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1008 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1009 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1014 /* Max possible square size */
1015 #define MAXSQSIZE 256
1017 static int xpm_avail[MAXSQSIZE];
1019 #ifdef HAVE_DIR_STRUCT
1021 /* Extract piece size from filename */
1023 xpm_getsize(name, len, ext)
1034 if ((p=strchr(name, '.')) == NULL ||
1035 StrCaseCmp(p+1, ext) != 0)
1041 while (*p && isdigit(*p))
1048 /* Setup xpm_avail */
1050 xpm_getavail(dirname, ext)
1058 for (i=0; i<MAXSQSIZE; ++i)
1061 if (appData.debugMode)
1062 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1064 dir = opendir(dirname);
1067 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1068 programName, dirname);
1072 while ((ent=readdir(dir)) != NULL) {
1073 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1074 if (i > 0 && i < MAXSQSIZE)
1084 xpm_print_avail(fp, ext)
1090 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1091 for (i=1; i<MAXSQSIZE; ++i) {
1097 /* Return XPM piecesize closest to size */
1099 xpm_closest_to(dirname, size, ext)
1105 int sm_diff = MAXSQSIZE;
1109 xpm_getavail(dirname, ext);
1111 if (appData.debugMode)
1112 xpm_print_avail(stderr, ext);
1114 for (i=1; i<MAXSQSIZE; ++i) {
1117 diff = (diff<0) ? -diff : diff;
1118 if (diff < sm_diff) {
1126 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1132 #else /* !HAVE_DIR_STRUCT */
1133 /* If we are on a system without a DIR struct, we can't
1134 read the directory, so we can't collect a list of
1135 filenames, etc., so we can't do any size-fitting. */
1137 xpm_closest_to(dirname, size, ext)
1142 fprintf(stderr, _("\
1143 Warning: No DIR structure found on this system --\n\
1144 Unable to autosize for XPM/XIM pieces.\n\
1145 Please report this error to frankm@hiwaay.net.\n\
1146 Include system type & operating system in message.\n"));
1149 #endif /* HAVE_DIR_STRUCT */
1151 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1152 "magenta", "cyan", "white" };
1156 TextColors textColors[(int)NColorClasses];
1158 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1160 parse_color(str, which)
1164 char *p, buf[100], *d;
1167 if (strlen(str) > 99) /* watch bounds on buf */
1172 for (i=0; i<which; ++i) {
1179 /* Could be looking at something like:
1181 .. in which case we want to stop on a comma also */
1182 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1186 return -1; /* Use default for empty field */
1189 if (which == 2 || isdigit(*p))
1192 while (*p && isalpha(*p))
1197 for (i=0; i<8; ++i) {
1198 if (!StrCaseCmp(buf, cnames[i]))
1199 return which? (i+40) : (i+30);
1201 if (!StrCaseCmp(buf, "default")) return -1;
1203 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1208 parse_cpair(cc, str)
1212 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1213 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1218 /* bg and attr are optional */
1219 textColors[(int)cc].bg = parse_color(str, 1);
1220 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1221 textColors[(int)cc].attr = 0;
1227 /* Arrange to catch delete-window events */
1228 Atom wm_delete_window;
1230 CatchDeleteWindow(Widget w, String procname)
1233 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1234 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1235 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1242 XtSetArg(args[0], XtNiconic, False);
1243 XtSetValues(shellWidget, args, 1);
1245 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1248 //---------------------------------------------------------------------------------------------------------
1249 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1252 #define CW_USEDEFAULT (1<<31)
1253 #define ICS_TEXT_MENU_SIZE 90
1254 #define DEBUG_FILE "xboard.debug"
1255 #define SetCurrentDirectory chdir
1256 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1260 // these two must some day move to frontend.h, when they are implemented
1261 Boolean MoveHistoryIsUp();
1262 Boolean GameListIsUp();
1264 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1267 // front-end part of option handling
1269 // [HGM] This platform-dependent table provides the location for storing the color info
1270 extern char *crWhite, * crBlack;
1274 &appData.whitePieceColor,
1275 &appData.blackPieceColor,
1276 &appData.lightSquareColor,
1277 &appData.darkSquareColor,
1278 &appData.highlightSquareColor,
1279 &appData.premoveHighlightColor,
1292 ParseFont(char *name, int number)
1293 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1295 case 0: // CLOCK_FONT
1296 appData.clockFont = strdup(name);
1298 case 1: // MESSAGE_FONT
1299 appData.font = strdup(name);
1301 case 2: // COORD_FONT
1302 appData.coordFont = strdup(name);
1311 { // only 2 fonts currently
1312 appData.clockFont = CLOCK_FONT_NAME;
1313 appData.coordFont = COORD_FONT_NAME;
1314 appData.font = DEFAULT_FONT_NAME;
1319 { // no-op, until we identify the code for this already in XBoard and move it here
1323 ParseColor(int n, char *name)
1324 { // in XBoard, just copy the color-name string
1325 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1329 ParseTextAttribs(ColorClass cc, char *s)
1331 (&appData.colorShout)[cc] = strdup(s);
1335 ParseBoardSize(void *addr, char *name)
1337 appData.boardSize = strdup(name);
1342 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1346 SetCommPortDefaults()
1347 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1350 // [HGM] args: these three cases taken out to stay in front-end
1352 SaveFontArg(FILE *f, ArgDescriptor *ad)
1355 switch((int)ad->argLoc) {
1356 case 0: // CLOCK_FONT
1357 name = appData.clockFont;
1359 case 1: // MESSAGE_FONT
1360 name = appData.font;
1362 case 2: // COORD_FONT
1363 name = appData.coordFont;
1368 // Do not save fonts for now, as the saved font would be board-size specific
1369 // and not suitable for a re-start at another board size
1370 // fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, name);
1375 { // nothing to do, as the sounds are at all times represented by their text-string names already
1379 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1380 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1381 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1385 SaveColor(FILE *f, ArgDescriptor *ad)
1386 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1387 if(colorVariable[(int)ad->argLoc])
1388 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1392 SaveBoardSize(FILE *f, char *name, void *addr)
1393 { // wrapper to shield back-end from BoardSize & sizeInfo
1394 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1398 ParseCommPortSettings(char *s)
1399 { // no such option in XBoard (yet)
1402 extern Widget engineOutputShell;
1403 extern Widget tagsShell, editTagsShell;
1405 GetActualPlacement(Widget wg, WindowPlacement *wp)
1415 XtSetArg(args[i], XtNx, &x); i++;
1416 XtSetArg(args[i], XtNy, &y); i++;
1417 XtSetArg(args[i], XtNwidth, &w); i++;
1418 XtSetArg(args[i], XtNheight, &h); i++;
1419 XtGetValues(wg, args, i);
1428 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1429 // In XBoard this will have to wait until awareness of window parameters is implemented
1430 GetActualPlacement(shellWidget, &wpMain);
1431 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1432 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1433 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1434 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1435 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1436 else GetActualPlacement(editShell, &wpComment);
1437 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1438 else GetActualPlacement(editTagsShell, &wpTags);
1442 PrintCommPortSettings(FILE *f, char *name)
1443 { // This option does not exist in XBoard
1447 MySearchPath(char *installDir, char *name, char *fullname)
1448 { // just append installDir and name. Perhaps ExpandPath should be used here?
1449 name = ExpandPathName(name);
1450 if(name && name[0] == '/') strcpy(fullname, name); else {
1451 sprintf(fullname, "%s%c%s", installDir, '/', name);
1457 MyGetFullPathName(char *name, char *fullname)
1458 { // should use ExpandPath?
1459 name = ExpandPathName(name);
1460 strcpy(fullname, name);
1465 EnsureOnScreen(int *x, int *y, int minX, int minY)
1472 { // [HGM] args: allows testing if main window is realized from back-end
1473 return xBoardWindow != 0;
1477 PopUpStartupDialog()
1478 { // start menu not implemented in XBoard
1481 ConvertToLine(int argc, char **argv)
1483 static char line[128*1024], buf[1024];
1487 for(i=1; i<argc; i++) {
1488 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1489 && argv[i][0] != '{' )
1490 sprintf(buf, "{%s} ", argv[i]);
1491 else sprintf(buf, "%s ", argv[i]);
1494 line[strlen(line)-1] = NULLCHAR;
1498 //--------------------------------------------------------------------------------------------
1501 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1503 #define BoardSize int
1504 void InitDrawingSizes(BoardSize boardSize, int flags)
1505 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1506 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1508 XtGeometryResult gres;
1511 if(!formWidget) return;
1514 * Enable shell resizing.
1516 shellArgs[0].value = (XtArgVal) &w;
1517 shellArgs[1].value = (XtArgVal) &h;
1518 XtGetValues(shellWidget, shellArgs, 2);
1520 shellArgs[4].value = 2*w; shellArgs[2].value = 10;
1521 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1522 XtSetValues(shellWidget, &shellArgs[2], 4);
1524 XtSetArg(args[0], XtNdefaultDistance, &sep);
1525 XtGetValues(formWidget, args, 1);
1527 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1528 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1531 XtSetArg(args[0], XtNwidth, boardWidth);
1532 XtSetArg(args[1], XtNheight, boardHeight);
1533 XtSetValues(boardWidget, args, 2);
1535 timerWidth = (boardWidth - sep) / 2;
1536 XtSetArg(args[0], XtNwidth, timerWidth);
1537 XtSetValues(whiteTimerWidget, args, 1);
1538 XtSetValues(blackTimerWidget, args, 1);
1540 XawFormDoLayout(formWidget, False);
1542 if (appData.titleInWindow) {
1544 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1545 XtSetArg(args[i], XtNheight, &h); i++;
1546 XtGetValues(titleWidget, args, i);
1548 w = boardWidth - 2*bor;
1550 XtSetArg(args[0], XtNwidth, &w);
1551 XtGetValues(menuBarWidget, args, 1);
1552 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1555 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1556 if (gres != XtGeometryYes && appData.debugMode) {
1558 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1559 programName, gres, w, h, wr, hr);
1563 XawFormDoLayout(formWidget, True);
1566 * Inhibit shell resizing.
1568 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW;
1569 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1570 shellArgs[4].value = shellArgs[2].value = w;
1571 shellArgs[5].value = shellArgs[3].value = h;
1572 XtSetValues(shellWidget, &shellArgs[0], 6);
1574 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1577 for(i=0; i<4; i++) {
1579 for(p=0; p<=(int)WhiteKing; p++)
1580 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1581 if(gameInfo.variant == VariantShogi) {
1582 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1583 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1584 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1585 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1586 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1589 if(gameInfo.variant == VariantGothic) {
1590 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1594 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1595 for(p=0; p<=(int)WhiteKing; p++)
1596 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1597 if(gameInfo.variant == VariantShogi) {
1598 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1599 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1600 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1601 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1602 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1605 if(gameInfo.variant == VariantGothic) {
1606 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1612 for(i=0; i<2; i++) {
1614 for(p=0; p<=(int)WhiteKing; p++)
1615 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1616 if(gameInfo.variant == VariantShogi) {
1617 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1618 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1619 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1620 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1621 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1624 if(gameInfo.variant == VariantGothic) {
1625 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1636 void EscapeExpand(char *p, char *q)
1637 { // [HGM] initstring: routine to shape up string arguments
1638 while(*p++ = *q++) if(p[-1] == '\\')
1640 case 'n': p[-1] = '\n'; break;
1641 case 'r': p[-1] = '\r'; break;
1642 case 't': p[-1] = '\t'; break;
1643 case '\\': p[-1] = '\\'; break;
1644 case 0: *p = 0; return;
1645 default: p[-1] = q[-1]; break;
1654 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1655 XSetWindowAttributes window_attributes;
1657 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1658 XrmValue vFrom, vTo;
1659 XtGeometryResult gres;
1662 int forceMono = False;
1664 srandom(time(0)); // [HGM] book: make random truly random
1666 setbuf(stdout, NULL);
1667 setbuf(stderr, NULL);
1670 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1671 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1675 programName = strrchr(argv[0], '/');
1676 if (programName == NULL)
1677 programName = argv[0];
1682 XtSetLanguageProc(NULL, NULL, NULL);
1683 bindtextdomain(PACKAGE, LOCALEDIR);
1684 textdomain(PACKAGE);
1688 XtAppInitialize(&appContext, "XBoard", shellOptions,
1689 XtNumber(shellOptions),
1690 &argc, argv, xboardResources, NULL, 0);
1691 appData.boardSize = "";
1692 InitAppData(ConvertToLine(argc, argv));
1694 if (p == NULL) p = "/tmp";
1695 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1696 gameCopyFilename = (char*) malloc(i);
1697 gamePasteFilename = (char*) malloc(i);
1698 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1699 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1701 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1702 clientResources, XtNumber(clientResources),
1705 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1706 static char buf[MSG_SIZ];
1707 EscapeExpand(buf, appData.initString);
1708 appData.initString = strdup(buf);
1709 EscapeExpand(buf, appData.secondInitString);
1710 appData.secondInitString = strdup(buf);
1711 EscapeExpand(buf, appData.firstComputerString);
1712 appData.firstComputerString = strdup(buf);
1713 EscapeExpand(buf, appData.secondComputerString);
1714 appData.secondComputerString = strdup(buf);
1717 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1720 if (chdir(chessDir) != 0) {
1721 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1727 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1728 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1729 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1730 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1733 setbuf(debugFP, NULL);
1736 /* [HGM,HR] make sure board size is acceptable */
1737 if(appData.NrFiles > BOARD_FILES ||
1738 appData.NrRanks > BOARD_RANKS )
1739 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1742 /* This feature does not work; animation needs a rewrite */
1743 appData.highlightDragging = FALSE;
1747 xDisplay = XtDisplay(shellWidget);
1748 xScreen = DefaultScreen(xDisplay);
1749 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1751 gameInfo.variant = StringToVariant(appData.variant);
1752 InitPosition(FALSE);
1755 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1757 if (isdigit(appData.boardSize[0])) {
1758 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1759 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1760 &fontPxlSize, &smallLayout, &tinyLayout);
1762 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1763 programName, appData.boardSize);
1767 /* Find some defaults; use the nearest known size */
1768 SizeDefaults *szd, *nearest;
1769 int distance = 99999;
1770 nearest = szd = sizeDefaults;
1771 while (szd->name != NULL) {
1772 if (abs(szd->squareSize - squareSize) < distance) {
1774 distance = abs(szd->squareSize - squareSize);
1775 if (distance == 0) break;
1779 if (i < 2) lineGap = nearest->lineGap;
1780 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1781 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1782 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1783 if (i < 6) smallLayout = nearest->smallLayout;
1784 if (i < 7) tinyLayout = nearest->tinyLayout;
1787 SizeDefaults *szd = sizeDefaults;
1788 if (*appData.boardSize == NULLCHAR) {
1789 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1790 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1793 if (szd->name == NULL) szd--;
1794 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1796 while (szd->name != NULL &&
1797 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1798 if (szd->name == NULL) {
1799 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1800 programName, appData.boardSize);
1804 squareSize = szd->squareSize;
1805 lineGap = szd->lineGap;
1806 clockFontPxlSize = szd->clockFontPxlSize;
1807 coordFontPxlSize = szd->coordFontPxlSize;
1808 fontPxlSize = szd->fontPxlSize;
1809 smallLayout = szd->smallLayout;
1810 tinyLayout = szd->tinyLayout;
1813 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1814 if (strlen(appData.pixmapDirectory) > 0) {
1815 p = ExpandPathName(appData.pixmapDirectory);
1817 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1818 appData.pixmapDirectory);
1821 if (appData.debugMode) {
1822 fprintf(stderr, _("\
1823 XBoard square size (hint): %d\n\
1824 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1826 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1827 if (appData.debugMode) {
1828 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1832 /* [HR] height treated separately (hacked) */
1833 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1834 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1835 if (appData.showJail == 1) {
1836 /* Jail on top and bottom */
1837 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1838 XtSetArg(boardArgs[2], XtNheight,
1839 boardHeight + 2*(lineGap + squareSize));
1840 } else if (appData.showJail == 2) {
1842 XtSetArg(boardArgs[1], XtNwidth,
1843 boardWidth + 2*(lineGap + squareSize));
1844 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1847 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1848 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1852 * Determine what fonts to use.
1854 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1855 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1856 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1857 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1858 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1859 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1860 appData.font = FindFont(appData.font, fontPxlSize);
1861 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1862 countFontStruct = XQueryFont(xDisplay, countFontID);
1863 // appData.font = FindFont(appData.font, fontPxlSize);
1865 xdb = XtDatabase(xDisplay);
1866 XrmPutStringResource(&xdb, "*font", appData.font);
1869 * Detect if there are not enough colors available and adapt.
1871 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1872 appData.monoMode = True;
1875 if (!appData.monoMode) {
1876 vFrom.addr = (caddr_t) appData.lightSquareColor;
1877 vFrom.size = strlen(appData.lightSquareColor);
1878 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1879 if (vTo.addr == NULL) {
1880 appData.monoMode = True;
1883 lightSquareColor = *(Pixel *) vTo.addr;
1886 if (!appData.monoMode) {
1887 vFrom.addr = (caddr_t) appData.darkSquareColor;
1888 vFrom.size = strlen(appData.darkSquareColor);
1889 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1890 if (vTo.addr == NULL) {
1891 appData.monoMode = True;
1894 darkSquareColor = *(Pixel *) vTo.addr;
1897 if (!appData.monoMode) {
1898 vFrom.addr = (caddr_t) appData.whitePieceColor;
1899 vFrom.size = strlen(appData.whitePieceColor);
1900 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1901 if (vTo.addr == NULL) {
1902 appData.monoMode = True;
1905 whitePieceColor = *(Pixel *) vTo.addr;
1908 if (!appData.monoMode) {
1909 vFrom.addr = (caddr_t) appData.blackPieceColor;
1910 vFrom.size = strlen(appData.blackPieceColor);
1911 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1912 if (vTo.addr == NULL) {
1913 appData.monoMode = True;
1916 blackPieceColor = *(Pixel *) vTo.addr;
1920 if (!appData.monoMode) {
1921 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1922 vFrom.size = strlen(appData.highlightSquareColor);
1923 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1924 if (vTo.addr == NULL) {
1925 appData.monoMode = True;
1928 highlightSquareColor = *(Pixel *) vTo.addr;
1932 if (!appData.monoMode) {
1933 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1934 vFrom.size = strlen(appData.premoveHighlightColor);
1935 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1936 if (vTo.addr == NULL) {
1937 appData.monoMode = True;
1940 premoveHighlightColor = *(Pixel *) vTo.addr;
1945 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1948 if (appData.bitmapDirectory == NULL ||
1949 appData.bitmapDirectory[0] == NULLCHAR)
1950 appData.bitmapDirectory = DEF_BITMAP_DIR;
1953 if (appData.lowTimeWarning && !appData.monoMode) {
1954 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
1955 vFrom.size = strlen(appData.lowTimeWarningColor);
1956 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1957 if (vTo.addr == NULL)
1958 appData.monoMode = True;
1960 lowTimeWarningColor = *(Pixel *) vTo.addr;
1963 if (appData.monoMode && appData.debugMode) {
1964 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1965 (unsigned long) XWhitePixel(xDisplay, xScreen),
1966 (unsigned long) XBlackPixel(xDisplay, xScreen));
1969 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1970 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1971 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1972 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1973 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1974 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1975 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1976 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1977 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1978 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1980 if (appData.colorize) {
1982 _("%s: can't parse color names; disabling colorization\n"),
1985 appData.colorize = FALSE;
1987 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
1988 textColors[ColorNone].attr = 0;
1990 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
1996 layoutName = "tinyLayout";
1997 } else if (smallLayout) {
1998 layoutName = "smallLayout";
2000 layoutName = "normalLayout";
2002 /* Outer layoutWidget is there only to provide a name for use in
2003 resources that depend on the layout style */
2005 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2006 layoutArgs, XtNumber(layoutArgs));
2008 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2009 formArgs, XtNumber(formArgs));
2010 XtSetArg(args[0], XtNdefaultDistance, &sep);
2011 XtGetValues(formWidget, args, 1);
2014 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2015 XtSetArg(args[0], XtNtop, XtChainTop);
2016 XtSetArg(args[1], XtNbottom, XtChainTop);
2017 XtSetArg(args[2], XtNright, XtChainLeft);
2018 XtSetValues(menuBarWidget, args, 3);
2020 widgetList[j++] = whiteTimerWidget =
2021 XtCreateWidget("whiteTime", labelWidgetClass,
2022 formWidget, timerArgs, XtNumber(timerArgs));
2023 XtSetArg(args[0], XtNfont, clockFontStruct);
2024 XtSetArg(args[1], XtNtop, XtChainTop);
2025 XtSetArg(args[2], XtNbottom, XtChainTop);
2026 XtSetValues(whiteTimerWidget, args, 3);
2028 widgetList[j++] = blackTimerWidget =
2029 XtCreateWidget("blackTime", labelWidgetClass,
2030 formWidget, timerArgs, XtNumber(timerArgs));
2031 XtSetArg(args[0], XtNfont, clockFontStruct);
2032 XtSetArg(args[1], XtNtop, XtChainTop);
2033 XtSetArg(args[2], XtNbottom, XtChainTop);
2034 XtSetValues(blackTimerWidget, args, 3);
2036 if (appData.titleInWindow) {
2037 widgetList[j++] = titleWidget =
2038 XtCreateWidget("title", labelWidgetClass, formWidget,
2039 titleArgs, XtNumber(titleArgs));
2040 XtSetArg(args[0], XtNtop, XtChainTop);
2041 XtSetArg(args[1], XtNbottom, XtChainTop);
2042 XtSetValues(titleWidget, args, 2);
2045 if (appData.showButtonBar) {
2046 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2047 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2048 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2049 XtSetArg(args[2], XtNtop, XtChainTop);
2050 XtSetArg(args[3], XtNbottom, XtChainTop);
2051 XtSetValues(buttonBarWidget, args, 4);
2054 widgetList[j++] = messageWidget =
2055 XtCreateWidget("message", labelWidgetClass, formWidget,
2056 messageArgs, XtNumber(messageArgs));
2057 XtSetArg(args[0], XtNtop, XtChainTop);
2058 XtSetArg(args[1], XtNbottom, XtChainTop);
2059 XtSetValues(messageWidget, args, 2);
2061 widgetList[j++] = boardWidget =
2062 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2063 XtNumber(boardArgs));
2065 XtManageChildren(widgetList, j);
2067 timerWidth = (boardWidth - sep) / 2;
2068 XtSetArg(args[0], XtNwidth, timerWidth);
2069 XtSetValues(whiteTimerWidget, args, 1);
2070 XtSetValues(blackTimerWidget, args, 1);
2072 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2073 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2074 XtGetValues(whiteTimerWidget, args, 2);
2076 if (appData.showButtonBar) {
2077 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2078 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2079 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2083 * formWidget uses these constraints but they are stored
2087 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2088 XtSetValues(menuBarWidget, args, i);
2089 if (appData.titleInWindow) {
2092 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2093 XtSetValues(whiteTimerWidget, args, i);
2095 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2096 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2097 XtSetValues(blackTimerWidget, args, i);
2099 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2100 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2101 XtSetValues(titleWidget, args, i);
2103 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2104 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2105 XtSetValues(messageWidget, args, i);
2106 if (appData.showButtonBar) {
2108 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2109 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2110 XtSetValues(buttonBarWidget, args, i);
2114 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2115 XtSetValues(whiteTimerWidget, args, i);
2117 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2118 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2119 XtSetValues(blackTimerWidget, args, i);
2121 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2122 XtSetValues(titleWidget, args, i);
2124 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2125 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2126 XtSetValues(messageWidget, args, i);
2127 if (appData.showButtonBar) {
2129 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2130 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2131 XtSetValues(buttonBarWidget, args, i);
2136 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2137 XtSetValues(whiteTimerWidget, args, i);
2139 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2140 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2141 XtSetValues(blackTimerWidget, args, i);
2143 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2144 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2145 XtSetValues(messageWidget, args, i);
2146 if (appData.showButtonBar) {
2148 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2149 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2150 XtSetValues(buttonBarWidget, args, i);
2154 XtSetArg(args[0], XtNfromVert, messageWidget);
2155 XtSetArg(args[1], XtNtop, XtChainTop);
2156 XtSetArg(args[2], XtNbottom, XtChainBottom);
2157 XtSetArg(args[3], XtNleft, XtChainLeft);
2158 XtSetArg(args[4], XtNright, XtChainRight);
2159 XtSetValues(boardWidget, args, 5);
2161 XtRealizeWidget(shellWidget);
2164 XtSetArg(args[0], XtNx, wpMain.x);
2165 XtSetArg(args[1], XtNy, wpMain.y);
2166 XtSetValues(shellWidget, args, 2);
2170 * Correct the width of the message and title widgets.
2171 * It is not known why some systems need the extra fudge term.
2172 * The value "2" is probably larger than needed.
2174 XawFormDoLayout(formWidget, False);
2176 #define WIDTH_FUDGE 2
2178 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2179 XtSetArg(args[i], XtNheight, &h); i++;
2180 XtGetValues(messageWidget, args, i);
2181 if (appData.showButtonBar) {
2183 XtSetArg(args[i], XtNwidth, &w); i++;
2184 XtGetValues(buttonBarWidget, args, i);
2185 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2187 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2190 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2191 if (gres != XtGeometryYes && appData.debugMode) {
2192 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2193 programName, gres, w, h, wr, hr);
2196 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2197 /* The size used for the child widget in layout lags one resize behind
2198 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2200 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2201 if (gres != XtGeometryYes && appData.debugMode) {
2202 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2203 programName, gres, w, h, wr, hr);
2206 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2207 XtSetArg(args[1], XtNright, XtChainRight);
2208 XtSetValues(messageWidget, args, 2);
2210 if (appData.titleInWindow) {
2212 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2213 XtSetArg(args[i], XtNheight, &h); i++;
2214 XtGetValues(titleWidget, args, i);
2216 w = boardWidth - 2*bor;
2218 XtSetArg(args[0], XtNwidth, &w);
2219 XtGetValues(menuBarWidget, args, 1);
2220 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2223 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2224 if (gres != XtGeometryYes && appData.debugMode) {
2226 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2227 programName, gres, w, h, wr, hr);
2230 XawFormDoLayout(formWidget, True);
2232 xBoardWindow = XtWindow(boardWidget);
2234 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2235 // not need to go into InitDrawingSizes().
2239 * Create X checkmark bitmap and initialize option menu checks.
2241 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2242 checkmark_bits, checkmark_width, checkmark_height);
2243 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2244 if (appData.alwaysPromoteToQueen) {
2245 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2248 if (appData.animateDragging) {
2249 XtSetValues(XtNameToWidget(menuBarWidget,
2250 "menuOptions.Animate Dragging"),
2253 if (appData.animate) {
2254 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2257 if (appData.autoComment) {
2258 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2261 if (appData.autoCallFlag) {
2262 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2265 if (appData.autoFlipView) {
2266 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2269 if (appData.autoObserve) {
2270 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2273 if (appData.autoRaiseBoard) {
2274 XtSetValues(XtNameToWidget(menuBarWidget,
2275 "menuOptions.Auto Raise Board"), args, 1);
2277 if (appData.autoSaveGames) {
2278 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2281 if (appData.saveGameFile[0] != NULLCHAR) {
2282 /* Can't turn this off from menu */
2283 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2285 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2289 if (appData.blindfold) {
2290 XtSetValues(XtNameToWidget(menuBarWidget,
2291 "menuOptions.Blindfold"), args, 1);
2293 if (appData.flashCount > 0) {
2294 XtSetValues(XtNameToWidget(menuBarWidget,
2295 "menuOptions.Flash Moves"),
2298 if (appData.getMoveList) {
2299 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2303 if (appData.highlightDragging) {
2304 XtSetValues(XtNameToWidget(menuBarWidget,
2305 "menuOptions.Highlight Dragging"),
2309 if (appData.highlightLastMove) {
2310 XtSetValues(XtNameToWidget(menuBarWidget,
2311 "menuOptions.Highlight Last Move"),
2314 if (appData.icsAlarm) {
2315 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2318 if (appData.ringBellAfterMoves) {
2319 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2322 if (appData.oldSaveStyle) {
2323 XtSetValues(XtNameToWidget(menuBarWidget,
2324 "menuOptions.Old Save Style"), args, 1);
2326 if (appData.periodicUpdates) {
2327 XtSetValues(XtNameToWidget(menuBarWidget,
2328 "menuOptions.Periodic Updates"), args, 1);
2330 if (appData.ponderNextMove) {
2331 XtSetValues(XtNameToWidget(menuBarWidget,
2332 "menuOptions.Ponder Next Move"), args, 1);
2334 if (appData.popupExitMessage) {
2335 XtSetValues(XtNameToWidget(menuBarWidget,
2336 "menuOptions.Popup Exit Message"), args, 1);
2338 if (appData.popupMoveErrors) {
2339 XtSetValues(XtNameToWidget(menuBarWidget,
2340 "menuOptions.Popup Move Errors"), args, 1);
2342 if (appData.premove) {
2343 XtSetValues(XtNameToWidget(menuBarWidget,
2344 "menuOptions.Premove"), args, 1);
2346 if (appData.quietPlay) {
2347 XtSetValues(XtNameToWidget(menuBarWidget,
2348 "menuOptions.Quiet Play"), args, 1);
2350 if (appData.showCoords) {
2351 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2354 if (appData.hideThinkingFromHuman) {
2355 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2358 if (appData.testLegality) {
2359 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2362 if (saveSettingsOnExit) {
2363 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2370 ReadBitmap(&wIconPixmap, "icon_white.bm",
2371 icon_white_bits, icon_white_width, icon_white_height);
2372 ReadBitmap(&bIconPixmap, "icon_black.bm",
2373 icon_black_bits, icon_black_width, icon_black_height);
2374 iconPixmap = wIconPixmap;
2376 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2377 XtSetValues(shellWidget, args, i);
2380 * Create a cursor for the board widget.
2382 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2383 XChangeWindowAttributes(xDisplay, xBoardWindow,
2384 CWCursor, &window_attributes);
2387 * Inhibit shell resizing.
2389 shellArgs[0].value = (XtArgVal) &w;
2390 shellArgs[1].value = (XtArgVal) &h;
2391 XtGetValues(shellWidget, shellArgs, 2);
2392 shellArgs[4].value = shellArgs[2].value = w;
2393 shellArgs[5].value = shellArgs[3].value = h;
2394 XtSetValues(shellWidget, &shellArgs[2], 4);
2395 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2396 marginH = h - boardHeight;
2398 CatchDeleteWindow(shellWidget, "QuitProc");
2403 if (appData.bitmapDirectory[0] != NULLCHAR) {
2410 /* Create regular pieces */
2411 if (!useImages) CreatePieces();
2416 if (appData.animate || appData.animateDragging)
2419 XtAugmentTranslations(formWidget,
2420 XtParseTranslationTable(globalTranslations));
2421 XtAugmentTranslations(boardWidget,
2422 XtParseTranslationTable(boardTranslations));
2423 XtAugmentTranslations(whiteTimerWidget,
2424 XtParseTranslationTable(whiteTranslations));
2425 XtAugmentTranslations(blackTimerWidget,
2426 XtParseTranslationTable(blackTranslations));
2428 /* Why is the following needed on some versions of X instead
2429 * of a translation? */
2430 XtAddEventHandler(boardWidget, ExposureMask, False,
2431 (XtEventHandler) EventProc, NULL);
2434 /* [AS] Restore layout */
2435 if( wpMoveHistory.visible ) {
2439 if( wpEvalGraph.visible )
2444 if( wpEngineOutput.visible ) {
2445 EngineOutputPopUp();
2450 if (errorExitStatus == -1) {
2451 if (appData.icsActive) {
2452 /* We now wait until we see "login:" from the ICS before
2453 sending the logon script (problems with timestamp otherwise) */
2454 /*ICSInitScript();*/
2455 if (appData.icsInputBox) ICSInputBoxPopUp();
2459 signal(SIGWINCH, TermSizeSigHandler);
2461 signal(SIGINT, IntSigHandler);
2462 signal(SIGTERM, IntSigHandler);
2463 if (*appData.cmailGameName != NULLCHAR) {
2464 signal(SIGUSR1, CmailSigHandler);
2467 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2470 XtAppMainLoop(appContext);
2471 if (appData.debugMode) fclose(debugFP); // [DM] debug
2478 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2479 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2481 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2482 unlink(gameCopyFilename);
2483 unlink(gamePasteFilename);
2486 RETSIGTYPE TermSizeSigHandler(int sig)
2499 CmailSigHandler(sig)
2505 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2507 /* Activate call-back function CmailSigHandlerCallBack() */
2508 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2510 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2514 CmailSigHandlerCallBack(isr, closure, message, count, error)
2522 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2524 /**** end signal code ****/
2534 f = fopen(appData.icsLogon, "r");
2540 strcat(buf, appData.icsLogon);
2541 f = fopen(buf, "r");
2545 ProcessICSInitScript(f);
2552 EditCommentPopDown();
2567 if (!menuBarWidget) return;
2568 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2570 DisplayError("menuStep.Revert", 0);
2572 XtSetSensitive(w, !grey);
2577 SetMenuEnables(enab)
2581 if (!menuBarWidget) return;
2582 while (enab->name != NULL) {
2583 w = XtNameToWidget(menuBarWidget, enab->name);
2585 DisplayError(enab->name, 0);
2587 XtSetSensitive(w, enab->value);
2593 Enables icsEnables[] = {
2594 { "menuFile.Mail Move", False },
2595 { "menuFile.Reload CMail Message", False },
2596 { "menuMode.Machine Black", False },
2597 { "menuMode.Machine White", False },
2598 { "menuMode.Analysis Mode", False },
2599 { "menuMode.Analyze File", False },
2600 { "menuMode.Two Machines", False },
2602 { "menuHelp.Hint", False },
2603 { "menuHelp.Book", False },
2604 { "menuStep.Move Now", False },
2605 { "menuOptions.Periodic Updates", False },
2606 { "menuOptions.Hide Thinking", False },
2607 { "menuOptions.Ponder Next Move", False },
2612 Enables ncpEnables[] = {
2613 { "menuFile.Mail Move", False },
2614 { "menuFile.Reload CMail Message", False },
2615 { "menuMode.Machine White", False },
2616 { "menuMode.Machine Black", False },
2617 { "menuMode.Analysis Mode", False },
2618 { "menuMode.Analyze File", False },
2619 { "menuMode.Two Machines", False },
2620 { "menuMode.ICS Client", False },
2621 { "menuMode.ICS Input Box", False },
2622 { "Action", False },
2623 { "menuStep.Revert", False },
2624 { "menuStep.Move Now", False },
2625 { "menuStep.Retract Move", False },
2626 { "menuOptions.Auto Comment", False },
2627 { "menuOptions.Auto Flag", False },
2628 { "menuOptions.Auto Flip View", False },
2629 { "menuOptions.Auto Observe", False },
2630 { "menuOptions.Auto Raise Board", False },
2631 { "menuOptions.Get Move List", False },
2632 { "menuOptions.ICS Alarm", False },
2633 { "menuOptions.Move Sound", False },
2634 { "menuOptions.Quiet Play", False },
2635 { "menuOptions.Hide Thinking", False },
2636 { "menuOptions.Periodic Updates", False },
2637 { "menuOptions.Ponder Next Move", False },
2638 { "menuHelp.Hint", False },
2639 { "menuHelp.Book", False },
2643 Enables gnuEnables[] = {
2644 { "menuMode.ICS Client", False },
2645 { "menuMode.ICS Input Box", False },
2646 { "menuAction.Accept", False },
2647 { "menuAction.Decline", False },
2648 { "menuAction.Rematch", False },
2649 { "menuAction.Adjourn", False },
2650 { "menuAction.Stop Examining", False },
2651 { "menuAction.Stop Observing", False },
2652 { "menuStep.Revert", False },
2653 { "menuOptions.Auto Comment", False },
2654 { "menuOptions.Auto Observe", False },
2655 { "menuOptions.Auto Raise Board", False },
2656 { "menuOptions.Get Move List", False },
2657 { "menuOptions.Premove", False },
2658 { "menuOptions.Quiet Play", False },
2660 /* The next two options rely on SetCmailMode being called *after* */
2661 /* SetGNUMode so that when GNU is being used to give hints these */
2662 /* menu options are still available */
2664 { "menuFile.Mail Move", False },
2665 { "menuFile.Reload CMail Message", False },
2669 Enables cmailEnables[] = {
2671 { "menuAction.Call Flag", False },
2672 { "menuAction.Draw", True },
2673 { "menuAction.Adjourn", False },
2674 { "menuAction.Abort", False },
2675 { "menuAction.Stop Observing", False },
2676 { "menuAction.Stop Examining", False },
2677 { "menuFile.Mail Move", True },
2678 { "menuFile.Reload CMail Message", True },
2682 Enables trainingOnEnables[] = {
2683 { "menuMode.Edit Comment", False },
2684 { "menuMode.Pause", False },
2685 { "menuStep.Forward", False },
2686 { "menuStep.Backward", False },
2687 { "menuStep.Forward to End", False },
2688 { "menuStep.Back to Start", False },
2689 { "menuStep.Move Now", False },
2690 { "menuStep.Truncate Game", False },
2694 Enables trainingOffEnables[] = {
2695 { "menuMode.Edit Comment", True },
2696 { "menuMode.Pause", True },
2697 { "menuStep.Forward", True },
2698 { "menuStep.Backward", True },
2699 { "menuStep.Forward to End", True },
2700 { "menuStep.Back to Start", True },
2701 { "menuStep.Move Now", True },
2702 { "menuStep.Truncate Game", True },
2706 Enables machineThinkingEnables[] = {
2707 { "menuFile.Load Game", False },
2708 { "menuFile.Load Next Game", False },
2709 { "menuFile.Load Previous Game", False },
2710 { "menuFile.Reload Same Game", False },
2711 { "menuFile.Paste Game", False },
2712 { "menuFile.Load Position", False },
2713 { "menuFile.Load Next Position", False },
2714 { "menuFile.Load Previous Position", False },
2715 { "menuFile.Reload Same Position", False },
2716 { "menuFile.Paste Position", False },
2717 { "menuMode.Machine White", False },
2718 { "menuMode.Machine Black", False },
2719 { "menuMode.Two Machines", False },
2720 { "menuStep.Retract Move", False },
2724 Enables userThinkingEnables[] = {
2725 { "menuFile.Load Game", True },
2726 { "menuFile.Load Next Game", True },
2727 { "menuFile.Load Previous Game", True },
2728 { "menuFile.Reload Same Game", True },
2729 { "menuFile.Paste Game", True },
2730 { "menuFile.Load Position", True },
2731 { "menuFile.Load Next Position", True },
2732 { "menuFile.Load Previous Position", True },
2733 { "menuFile.Reload Same Position", True },
2734 { "menuFile.Paste Position", True },
2735 { "menuMode.Machine White", True },
2736 { "menuMode.Machine Black", True },
2737 { "menuMode.Two Machines", True },
2738 { "menuStep.Retract Move", True },
2744 SetMenuEnables(icsEnables);
2747 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2748 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2755 SetMenuEnables(ncpEnables);
2761 SetMenuEnables(gnuEnables);
2767 SetMenuEnables(cmailEnables);
2773 SetMenuEnables(trainingOnEnables);
2774 if (appData.showButtonBar) {
2775 XtSetSensitive(buttonBarWidget, False);
2781 SetTrainingModeOff()
2783 SetMenuEnables(trainingOffEnables);
2784 if (appData.showButtonBar) {
2785 XtSetSensitive(buttonBarWidget, True);
2790 SetUserThinkingEnables()
2792 if (appData.noChessProgram) return;
2793 SetMenuEnables(userThinkingEnables);
2797 SetMachineThinkingEnables()
2799 if (appData.noChessProgram) return;
2800 SetMenuEnables(machineThinkingEnables);
2802 case MachinePlaysBlack:
2803 case MachinePlaysWhite:
2804 case TwoMachinesPlay:
2805 XtSetSensitive(XtNameToWidget(menuBarWidget,
2806 ModeToWidgetName(gameMode)), True);
2813 #define Abs(n) ((n)<0 ? -(n) : (n))
2816 * Find a font that matches "pattern" that is as close as
2817 * possible to the targetPxlSize. Prefer fonts that are k
2818 * pixels smaller to fonts that are k pixels larger. The
2819 * pattern must be in the X Consortium standard format,
2820 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2821 * The return value should be freed with XtFree when no
2824 char *FindFont(pattern, targetPxlSize)
2828 char **fonts, *p, *best, *scalable, *scalableTail;
2829 int i, j, nfonts, minerr, err, pxlSize;
2832 char **missing_list;
2834 char *def_string, *base_fnt_lst, strInt[3];
2836 XFontStruct **fnt_list;
2838 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2839 sprintf(strInt, "%d", targetPxlSize);
2840 p = strstr(pattern, "--");
2841 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2842 strcat(base_fnt_lst, strInt);
2843 strcat(base_fnt_lst, strchr(p + 2, '-'));
2845 if ((fntSet = XCreateFontSet(xDisplay,
2849 &def_string)) == NULL) {
2851 fprintf(stderr, _("Unable to create font set.\n"));
2855 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2857 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2859 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2860 programName, pattern);
2868 for (i=0; i<nfonts; i++) {
2871 if (*p != '-') continue;
2873 if (*p == NULLCHAR) break;
2874 if (*p++ == '-') j++;
2876 if (j < 7) continue;
2879 scalable = fonts[i];
2882 err = pxlSize - targetPxlSize;
2883 if (Abs(err) < Abs(minerr) ||
2884 (minerr > 0 && err < 0 && -err == minerr)) {
2890 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
2891 /* If the error is too big and there is a scalable font,
2892 use the scalable font. */
2893 int headlen = scalableTail - scalable;
2894 p = (char *) XtMalloc(strlen(scalable) + 10);
2895 while (isdigit(*scalableTail)) scalableTail++;
2896 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
2898 p = (char *) XtMalloc(strlen(best) + 1);
2901 if (appData.debugMode) {
2902 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
2903 pattern, targetPxlSize, p);
2906 if (missing_count > 0)
2907 XFreeStringList(missing_list);
2908 XFreeFontSet(xDisplay, fntSet);
2910 XFreeFontNames(fonts);
2917 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
2918 | GCBackground | GCFunction | GCPlaneMask;
2919 XGCValues gc_values;
2922 gc_values.plane_mask = AllPlanes;
2923 gc_values.line_width = lineGap;
2924 gc_values.line_style = LineSolid;
2925 gc_values.function = GXcopy;
2927 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2928 gc_values.background = XBlackPixel(xDisplay, xScreen);
2929 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2931 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2932 gc_values.background = XWhitePixel(xDisplay, xScreen);
2933 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
2934 XSetFont(xDisplay, coordGC, coordFontID);
2936 // [HGM] make font for holdings counts (white on black0
2937 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2938 gc_values.background = XBlackPixel(xDisplay, xScreen);
2939 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
2940 XSetFont(xDisplay, countGC, countFontID);
2942 if (appData.monoMode) {
2943 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2944 gc_values.background = XWhitePixel(xDisplay, xScreen);
2945 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2947 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2948 gc_values.background = XBlackPixel(xDisplay, xScreen);
2949 lightSquareGC = wbPieceGC
2950 = XtGetGC(shellWidget, value_mask, &gc_values);
2952 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2953 gc_values.background = XWhitePixel(xDisplay, xScreen);
2954 darkSquareGC = bwPieceGC
2955 = XtGetGC(shellWidget, value_mask, &gc_values);
2957 if (DefaultDepth(xDisplay, xScreen) == 1) {
2958 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
2959 gc_values.function = GXcopyInverted;
2960 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
2961 gc_values.function = GXcopy;
2962 if (XBlackPixel(xDisplay, xScreen) == 1) {
2963 bwPieceGC = darkSquareGC;
2964 wbPieceGC = copyInvertedGC;
2966 bwPieceGC = copyInvertedGC;
2967 wbPieceGC = lightSquareGC;
2971 gc_values.foreground = highlightSquareColor;
2972 gc_values.background = highlightSquareColor;
2973 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2975 gc_values.foreground = premoveHighlightColor;
2976 gc_values.background = premoveHighlightColor;
2977 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2979 gc_values.foreground = lightSquareColor;
2980 gc_values.background = darkSquareColor;
2981 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2983 gc_values.foreground = darkSquareColor;
2984 gc_values.background = lightSquareColor;
2985 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2987 gc_values.foreground = jailSquareColor;
2988 gc_values.background = jailSquareColor;
2989 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2991 gc_values.foreground = whitePieceColor;
2992 gc_values.background = darkSquareColor;
2993 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
2995 gc_values.foreground = whitePieceColor;
2996 gc_values.background = lightSquareColor;
2997 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
2999 gc_values.foreground = whitePieceColor;
3000 gc_values.background = jailSquareColor;
3001 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3003 gc_values.foreground = blackPieceColor;
3004 gc_values.background = darkSquareColor;
3005 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3007 gc_values.foreground = blackPieceColor;
3008 gc_values.background = lightSquareColor;
3009 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3011 gc_values.foreground = blackPieceColor;
3012 gc_values.background = jailSquareColor;
3013 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3017 void loadXIM(xim, xmask, filename, dest, mask)
3030 fp = fopen(filename, "rb");
3032 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3039 for (y=0; y<h; ++y) {
3040 for (x=0; x<h; ++x) {
3045 XPutPixel(xim, x, y, blackPieceColor);
3047 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3050 XPutPixel(xim, x, y, darkSquareColor);
3052 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3055 XPutPixel(xim, x, y, whitePieceColor);
3057 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3060 XPutPixel(xim, x, y, lightSquareColor);
3062 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3068 /* create Pixmap of piece */
3069 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3071 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3074 /* create Pixmap of clipmask
3075 Note: We assume the white/black pieces have the same
3076 outline, so we make only 6 masks. This is okay
3077 since the XPM clipmask routines do the same. */
3079 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3081 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3084 /* now create the 1-bit version */
3085 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3088 values.foreground = 1;
3089 values.background = 0;
3091 /* Don't use XtGetGC, not read only */
3092 maskGC = XCreateGC(xDisplay, *mask,
3093 GCForeground | GCBackground, &values);
3094 XCopyPlane(xDisplay, temp, *mask, maskGC,
3095 0, 0, squareSize, squareSize, 0, 0, 1);
3096 XFreePixmap(xDisplay, temp);
3101 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3103 void CreateXIMPieces()
3108 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3113 /* The XSynchronize calls were copied from CreatePieces.
3114 Not sure if needed, but can't hurt */
3115 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3118 /* temp needed by loadXIM() */
3119 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3120 0, 0, ss, ss, AllPlanes, XYPixmap);
3122 if (strlen(appData.pixmapDirectory) == 0) {
3126 if (appData.monoMode) {
3127 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3131 fprintf(stderr, _("\nLoading XIMs...\n"));
3133 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3134 fprintf(stderr, "%d", piece+1);
3135 for (kind=0; kind<4; kind++) {
3136 fprintf(stderr, ".");
3137 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3138 ExpandPathName(appData.pixmapDirectory),
3139 piece <= (int) WhiteKing ? "" : "w",
3140 pieceBitmapNames[piece],
3142 ximPieceBitmap[kind][piece] =
3143 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3144 0, 0, ss, ss, AllPlanes, XYPixmap);
3145 if (appData.debugMode)
3146 fprintf(stderr, _("(File:%s:) "), buf);
3147 loadXIM(ximPieceBitmap[kind][piece],
3149 &(xpmPieceBitmap2[kind][piece]),
3150 &(ximMaskPm2[piece]));
3151 if(piece <= (int)WhiteKing)
3152 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3154 fprintf(stderr," ");
3156 /* Load light and dark squares */
3157 /* If the LSQ and DSQ pieces don't exist, we will
3158 draw them with solid squares. */
3159 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3160 if (access(buf, 0) != 0) {
3164 fprintf(stderr, _("light square "));
3166 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3167 0, 0, ss, ss, AllPlanes, XYPixmap);
3168 if (appData.debugMode)
3169 fprintf(stderr, _("(File:%s:) "), buf);
3171 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3172 fprintf(stderr, _("dark square "));
3173 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3174 ExpandPathName(appData.pixmapDirectory), ss);
3175 if (appData.debugMode)
3176 fprintf(stderr, _("(File:%s:) "), buf);
3178 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3179 0, 0, ss, ss, AllPlanes, XYPixmap);
3180 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3181 xpmJailSquare = xpmLightSquare;
3183 fprintf(stderr, _("Done.\n"));
3185 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3189 void CreateXPMPieces()
3193 u_int ss = squareSize;
3195 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3196 XpmColorSymbol symbols[4];
3198 /* The XSynchronize calls were copied from CreatePieces.
3199 Not sure if needed, but can't hurt */
3200 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3202 /* Setup translations so piece colors match square colors */
3203 symbols[0].name = "light_piece";
3204 symbols[0].value = appData.whitePieceColor;
3205 symbols[1].name = "dark_piece";
3206 symbols[1].value = appData.blackPieceColor;
3207 symbols[2].name = "light_square";
3208 symbols[2].value = appData.lightSquareColor;
3209 symbols[3].name = "dark_square";
3210 symbols[3].value = appData.darkSquareColor;
3212 attr.valuemask = XpmColorSymbols;
3213 attr.colorsymbols = symbols;
3214 attr.numsymbols = 4;
3216 if (appData.monoMode) {
3217 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3221 if (strlen(appData.pixmapDirectory) == 0) {
3222 XpmPieces* pieces = builtInXpms;
3225 while (pieces->size != squareSize && pieces->size) pieces++;
3226 if (!pieces->size) {
3227 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3230 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3231 for (kind=0; kind<4; kind++) {
3233 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3234 pieces->xpm[piece][kind],
3235 &(xpmPieceBitmap2[kind][piece]),
3236 NULL, &attr)) != 0) {
3237 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3241 if(piece <= (int) WhiteKing)
3242 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3246 xpmJailSquare = xpmLightSquare;
3250 fprintf(stderr, _("\nLoading XPMs...\n"));
3253 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3254 fprintf(stderr, "%d ", piece+1);
3255 for (kind=0; kind<4; kind++) {
3256 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3257 ExpandPathName(appData.pixmapDirectory),
3258 piece > (int) WhiteKing ? "w" : "",
3259 pieceBitmapNames[piece],
3261 if (appData.debugMode) {
3262 fprintf(stderr, _("(File:%s:) "), buf);
3264 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3265 &(xpmPieceBitmap2[kind][piece]),
3266 NULL, &attr)) != 0) {
3267 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3268 // [HGM] missing: read of unorthodox piece failed; substitute King.
3269 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3270 ExpandPathName(appData.pixmapDirectory),
3272 if (appData.debugMode) {
3273 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3275 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3276 &(xpmPieceBitmap2[kind][piece]),
3280 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3285 if(piece <= (int) WhiteKing)
3286 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3289 /* Load light and dark squares */
3290 /* If the LSQ and DSQ pieces don't exist, we will
3291 draw them with solid squares. */
3292 fprintf(stderr, _("light square "));
3293 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3294 if (access(buf, 0) != 0) {
3298 if (appData.debugMode)
3299 fprintf(stderr, _("(File:%s:) "), buf);
3301 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3302 &xpmLightSquare, NULL, &attr)) != 0) {
3303 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3306 fprintf(stderr, _("dark square "));
3307 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3308 ExpandPathName(appData.pixmapDirectory), ss);
3309 if (appData.debugMode) {
3310 fprintf(stderr, _("(File:%s:) "), buf);
3312 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3313 &xpmDarkSquare, NULL, &attr)) != 0) {
3314 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3318 xpmJailSquare = xpmLightSquare;
3319 fprintf(stderr, _("Done.\n"));
3321 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3324 #endif /* HAVE_LIBXPM */
3327 /* No built-in bitmaps */
3332 u_int ss = squareSize;
3334 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3337 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3338 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3339 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3340 pieceBitmapNames[piece],
3341 ss, kind == SOLID ? 's' : 'o');
3342 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3343 if(piece <= (int)WhiteKing)
3344 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3348 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3352 /* With built-in bitmaps */
3355 BuiltInBits* bib = builtInBits;
3358 u_int ss = squareSize;
3360 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3363 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3365 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3366 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3367 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3368 pieceBitmapNames[piece],
3369 ss, kind == SOLID ? 's' : 'o');
3370 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3371 bib->bits[kind][piece], ss, ss);
3372 if(piece <= (int)WhiteKing)
3373 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3377 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3382 void ReadBitmap(pm, name, bits, wreq, hreq)
3385 unsigned char bits[];
3391 char msg[MSG_SIZ], fullname[MSG_SIZ];
3393 if (*appData.bitmapDirectory != NULLCHAR) {
3394 strcpy(fullname, appData.bitmapDirectory);
3395 strcat(fullname, "/");
3396 strcat(fullname, name);
3397 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3398 &w, &h, pm, &x_hot, &y_hot);
3399 fprintf(stderr, "load %s\n", name);
3400 if (errcode != BitmapSuccess) {
3402 case BitmapOpenFailed:
3403 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3405 case BitmapFileInvalid:
3406 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3408 case BitmapNoMemory:
3409 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3413 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3417 fprintf(stderr, _("%s: %s...using built-in\n"),
3419 } else if (w != wreq || h != hreq) {
3421 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3422 programName, fullname, w, h, wreq, hreq);
3428 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3437 if (lineGap == 0) return;
3439 /* [HR] Split this into 2 loops for non-square boards. */
3441 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3442 gridSegments[i].x1 = 0;
3443 gridSegments[i].x2 =
3444 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3445 gridSegments[i].y1 = gridSegments[i].y2
3446 = lineGap / 2 + (i * (squareSize + lineGap));
3449 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3450 gridSegments[j + i].y1 = 0;
3451 gridSegments[j + i].y2 =
3452 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3453 gridSegments[j + i].x1 = gridSegments[j + i].x2
3454 = lineGap / 2 + (j * (squareSize + lineGap));
3458 static void MenuBarSelect(w, addr, index)
3463 XtActionProc proc = (XtActionProc) addr;
3465 (proc)(NULL, NULL, NULL, NULL);
3468 void CreateMenuBarPopup(parent, name, mb)
3478 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3481 XtSetArg(args[j], XtNleftMargin, 20); j++;
3482 XtSetArg(args[j], XtNrightMargin, 20); j++;
3484 while (mi->string != NULL) {
3485 if (strcmp(mi->string, "----") == 0) {
3486 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3489 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3490 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3492 XtAddCallback(entry, XtNcallback,
3493 (XtCallbackProc) MenuBarSelect,
3494 (caddr_t) mi->proc);
3500 Widget CreateMenuBar(mb)
3504 Widget anchor, menuBar;
3506 char menuName[MSG_SIZ];
3509 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3510 XtSetArg(args[j], XtNvSpace, 0); j++;
3511 XtSetArg(args[j], XtNborderWidth, 0); j++;
3512 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3513 formWidget, args, j);
3515 while (mb->name != NULL) {
3516 strcpy(menuName, "menu");
3517 strcat(menuName, mb->name);
3519 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3522 shortName[0] = _(mb->name)[0];
3523 shortName[1] = NULLCHAR;
3524 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3527 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3530 XtSetArg(args[j], XtNborderWidth, 0); j++;
3531 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3533 CreateMenuBarPopup(menuBar, menuName, mb);
3539 Widget CreateButtonBar(mi)
3543 Widget button, buttonBar;
3547 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3549 XtSetArg(args[j], XtNhSpace, 0); j++;
3551 XtSetArg(args[j], XtNborderWidth, 0); j++;
3552 XtSetArg(args[j], XtNvSpace, 0); j++;
3553 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3554 formWidget, args, j);
3556 while (mi->string != NULL) {
3559 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3560 XtSetArg(args[j], XtNborderWidth, 0); j++;
3562 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3563 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3564 buttonBar, args, j);
3565 XtAddCallback(button, XtNcallback,
3566 (XtCallbackProc) MenuBarSelect,
3567 (caddr_t) mi->proc);
3574 CreatePieceMenu(name, color)
3581 ChessSquare selection;
3583 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3584 boardWidget, args, 0);
3586 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3587 String item = pieceMenuStrings[color][i];
3589 if (strcmp(item, "----") == 0) {
3590 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3593 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3594 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3596 selection = pieceMenuTranslation[color][i];
3597 XtAddCallback(entry, XtNcallback,
3598 (XtCallbackProc) PieceMenuSelect,
3599 (caddr_t) selection);
3600 if (selection == WhitePawn || selection == BlackPawn) {
3601 XtSetArg(args[0], XtNpopupOnEntry, entry);
3602 XtSetValues(menu, args, 1);
3615 ChessSquare selection;
3617 whitePieceMenu = CreatePieceMenu("menuW", 0);
3618 blackPieceMenu = CreatePieceMenu("menuB", 1);
3620 XtRegisterGrabAction(PieceMenuPopup, True,
3621 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3622 GrabModeAsync, GrabModeAsync);
3624 XtSetArg(args[0], XtNlabel, _("Drop"));
3625 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3626 boardWidget, args, 1);
3627 for (i = 0; i < DROP_MENU_SIZE; i++) {
3628 String item = dropMenuStrings[i];
3630 if (strcmp(item, "----") == 0) {
3631 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3634 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3635 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3637 selection = dropMenuTranslation[i];
3638 XtAddCallback(entry, XtNcallback,
3639 (XtCallbackProc) DropMenuSelect,
3640 (caddr_t) selection);
3645 void SetupDropMenu()
3653 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3654 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3655 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3656 dmEnables[i].piece);
3657 XtSetSensitive(entry, p != NULL || !appData.testLegality
3658 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3659 && !appData.icsActive));
3661 while (p && *p++ == dmEnables[i].piece) count++;
3662 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3664 XtSetArg(args[j], XtNlabel, label); j++;
3665 XtSetValues(entry, args, j);
3669 void PieceMenuPopup(w, event, params, num_params)
3673 Cardinal *num_params;
3676 if (event->type != ButtonPress) return;
3677 if (errorUp) ErrorPopDown();
3681 whichMenu = params[0];
3683 case IcsPlayingWhite:
3684 case IcsPlayingBlack:
3686 case MachinePlaysWhite:
3687 case MachinePlaysBlack:
3688 if (appData.testLegality &&
3689 gameInfo.variant != VariantBughouse &&
3690 gameInfo.variant != VariantCrazyhouse) return;
3692 whichMenu = "menuD";
3698 if (((pmFromX = EventToSquare(event->xbutton.x, BOARD_WIDTH)) < 0) ||
3699 ((pmFromY = EventToSquare(event->xbutton.y, BOARD_HEIGHT)) < 0)) {
3700 pmFromX = pmFromY = -1;
3704 pmFromX = BOARD_WIDTH - 1 - pmFromX;
3706 pmFromY = BOARD_HEIGHT - 1 - pmFromY;
3708 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3711 static void PieceMenuSelect(w, piece, junk)
3716 if (pmFromX < 0 || pmFromY < 0) return;
3717 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3720 static void DropMenuSelect(w, piece, junk)
3725 if (pmFromX < 0 || pmFromY < 0) return;
3726 DropMenuEvent(piece, pmFromX, pmFromY);
3729 void WhiteClock(w, event, prms, nprms)
3735 if (gameMode == EditPosition || gameMode == IcsExamining) {
3736 SetWhiteToPlayEvent();
3737 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3742 void BlackClock(w, event, prms, nprms)
3748 if (gameMode == EditPosition || gameMode == IcsExamining) {
3749 SetBlackToPlayEvent();
3750 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3757 * If the user selects on a border boundary, return -1; if off the board,
3758 * return -2. Otherwise map the event coordinate to the square.
3760 int EventToSquare(x, limit)
3768 if ((x % (squareSize + lineGap)) >= squareSize)
3770 x /= (squareSize + lineGap);
3776 static void do_flash_delay(msec)
3782 static void drawHighlight(file, rank, gc)
3788 if (lineGap == 0 || appData.blindfold) return;
3791 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3792 (squareSize + lineGap);
3793 y = lineGap/2 + rank * (squareSize + lineGap);
3795 x = lineGap/2 + file * (squareSize + lineGap);
3796 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3797 (squareSize + lineGap);
3800 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3801 squareSize+lineGap, squareSize+lineGap);
3804 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3805 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3808 SetHighlights(fromX, fromY, toX, toY)
3809 int fromX, fromY, toX, toY;
3811 if (hi1X != fromX || hi1Y != fromY) {
3812 if (hi1X >= 0 && hi1Y >= 0) {
3813 drawHighlight(hi1X, hi1Y, lineGC);
3815 if (fromX >= 0 && fromY >= 0) {
3816 drawHighlight(fromX, fromY, highlineGC);
3819 if (hi2X != toX || hi2Y != toY) {
3820 if (hi2X >= 0 && hi2Y >= 0) {
3821 drawHighlight(hi2X, hi2Y, lineGC);
3823 if (toX >= 0 && toY >= 0) {
3824 drawHighlight(toX, toY, highlineGC);
3836 SetHighlights(-1, -1, -1, -1);
3841 SetPremoveHighlights(fromX, fromY, toX, toY)
3842 int fromX, fromY, toX, toY;
3844 if (pm1X != fromX || pm1Y != fromY) {
3845 if (pm1X >= 0 && pm1Y >= 0) {
3846 drawHighlight(pm1X, pm1Y, lineGC);
3848 if (fromX >= 0 && fromY >= 0) {
3849 drawHighlight(fromX, fromY, prelineGC);
3852 if (pm2X != toX || pm2Y != toY) {
3853 if (pm2X >= 0 && pm2Y >= 0) {
3854 drawHighlight(pm2X, pm2Y, lineGC);
3856 if (toX >= 0 && toY >= 0) {
3857 drawHighlight(toX, toY, prelineGC);
3867 ClearPremoveHighlights()
3869 SetPremoveHighlights(-1, -1, -1, -1);
3872 static void BlankSquare(x, y, color, piece, dest)
3877 if (useImages && useImageSqs) {
3881 pm = xpmLightSquare;
3886 case 2: /* neutral */
3891 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
3892 squareSize, squareSize, x, y);
3902 case 2: /* neutral */
3907 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
3912 I split out the routines to draw a piece so that I could
3913 make a generic flash routine.
3915 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
3917 int square_color, x, y;
3920 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3921 switch (square_color) {
3923 case 2: /* neutral */
3925 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3926 ? *pieceToOutline(piece)
3927 : *pieceToSolid(piece),
3928 dest, bwPieceGC, 0, 0,
3929 squareSize, squareSize, x, y);
3932 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3933 ? *pieceToSolid(piece)
3934 : *pieceToOutline(piece),
3935 dest, wbPieceGC, 0, 0,
3936 squareSize, squareSize, x, y);
3941 static void monoDrawPiece(piece, square_color, x, y, dest)
3943 int square_color, x, y;
3946 switch (square_color) {
3948 case 2: /* neutral */
3950 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3951 ? *pieceToOutline(piece)
3952 : *pieceToSolid(piece),
3953 dest, bwPieceGC, 0, 0,
3954 squareSize, squareSize, x, y, 1);
3957 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3958 ? *pieceToSolid(piece)
3959 : *pieceToOutline(piece),
3960 dest, wbPieceGC, 0, 0,
3961 squareSize, squareSize, x, y, 1);
3966 static void colorDrawPiece(piece, square_color, x, y, dest)
3968 int square_color, x, y;
3971 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
3972 switch (square_color) {
3974 XCopyPlane(xDisplay, *pieceToSolid(piece),
3975 dest, (int) piece < (int) BlackPawn
3976 ? wlPieceGC : blPieceGC, 0, 0,
3977 squareSize, squareSize, x, y, 1);
3980 XCopyPlane(xDisplay, *pieceToSolid(piece),
3981 dest, (int) piece < (int) BlackPawn
3982 ? wdPieceGC : bdPieceGC, 0, 0,
3983 squareSize, squareSize, x, y, 1);
3985 case 2: /* neutral */
3987 XCopyPlane(xDisplay, *pieceToSolid(piece),
3988 dest, (int) piece < (int) BlackPawn
3989 ? wjPieceGC : bjPieceGC, 0, 0,
3990 squareSize, squareSize, x, y, 1);
3995 static void colorDrawPieceImage(piece, square_color, x, y, dest)
3997 int square_color, x, y;
4002 switch (square_color) {
4004 case 2: /* neutral */
4006 if ((int)piece < (int) BlackPawn) {
4014 if ((int)piece < (int) BlackPawn) {
4022 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4023 dest, wlPieceGC, 0, 0,
4024 squareSize, squareSize, x, y);
4027 typedef void (*DrawFunc)();
4029 DrawFunc ChooseDrawFunc()
4031 if (appData.monoMode) {
4032 if (DefaultDepth(xDisplay, xScreen) == 1) {
4033 return monoDrawPiece_1bit;
4035 return monoDrawPiece;
4039 return colorDrawPieceImage;
4041 return colorDrawPiece;
4045 /* [HR] determine square color depending on chess variant. */
4046 static int SquareColor(row, column)
4051 if (gameInfo.variant == VariantXiangqi) {
4052 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4054 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4056 } else if (row <= 4) {
4062 square_color = ((column + row) % 2) == 1;
4065 /* [hgm] holdings: next line makes all holdings squares light */
4066 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4068 return square_color;
4071 void DrawSquare(row, column, piece, do_flash)
4072 int row, column, do_flash;
4075 int square_color, x, y, direction, font_ascent, font_descent;
4078 XCharStruct overall;
4082 /* Calculate delay in milliseconds (2-delays per complete flash) */
4083 flash_delay = 500 / appData.flashRate;
4086 x = lineGap + ((BOARD_WIDTH-1)-column) *
4087 (squareSize + lineGap);
4088 y = lineGap + row * (squareSize + lineGap);
4090 x = lineGap + column * (squareSize + lineGap);
4091 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4092 (squareSize + lineGap);
4095 square_color = SquareColor(row, column);
4097 if ( // [HGM] holdings: blank out area between board and holdings
4098 column == BOARD_LEFT-1 || column == BOARD_RGHT
4099 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4100 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4101 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4103 // [HGM] print piece counts next to holdings
4104 string[1] = NULLCHAR;
4105 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4106 string[0] = '0' + piece;
4107 XTextExtents(countFontStruct, string, 1, &direction,
4108 &font_ascent, &font_descent, &overall);
4109 if (appData.monoMode) {
4110 XDrawImageString(xDisplay, xBoardWindow, countGC,
4111 x + squareSize - overall.width - 2,
4112 y + font_ascent + 1, string, 1);
4114 XDrawString(xDisplay, xBoardWindow, countGC,
4115 x + squareSize - overall.width - 2,
4116 y + font_ascent + 1, string, 1);
4119 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4120 string[0] = '0' + piece;
4121 XTextExtents(countFontStruct, string, 1, &direction,
4122 &font_ascent, &font_descent, &overall);
4123 if (appData.monoMode) {
4124 XDrawImageString(xDisplay, xBoardWindow, countGC,
4125 x + 2, y + font_ascent + 1, string, 1);
4127 XDrawString(xDisplay, xBoardWindow, countGC,
4128 x + 2, y + font_ascent + 1, string, 1);
4132 if (piece == EmptySquare || appData.blindfold) {
4133 BlankSquare(x, y, square_color, piece, xBoardWindow);
4135 drawfunc = ChooseDrawFunc();
4136 if (do_flash && appData.flashCount > 0) {
4137 for (i=0; i<appData.flashCount; ++i) {
4139 drawfunc(piece, square_color, x, y, xBoardWindow);
4140 XSync(xDisplay, False);
4141 do_flash_delay(flash_delay);
4143 BlankSquare(x, y, square_color, piece, xBoardWindow);
4144 XSync(xDisplay, False);
4145 do_flash_delay(flash_delay);
4148 drawfunc(piece, square_color, x, y, xBoardWindow);
4152 string[1] = NULLCHAR;
4153 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4154 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4155 string[0] = 'a' + column - BOARD_LEFT;
4156 XTextExtents(coordFontStruct, string, 1, &direction,
4157 &font_ascent, &font_descent, &overall);
4158 if (appData.monoMode) {
4159 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4160 x + squareSize - overall.width - 2,
4161 y + squareSize - font_descent - 1, string, 1);
4163 XDrawString(xDisplay, xBoardWindow, coordGC,
4164 x + squareSize - overall.width - 2,
4165 y + squareSize - font_descent - 1, string, 1);
4168 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4169 string[0] = ONE + row;
4170 XTextExtents(coordFontStruct, string, 1, &direction,
4171 &font_ascent, &font_descent, &overall);
4172 if (appData.monoMode) {
4173 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4174 x + 2, y + font_ascent + 1, string, 1);
4176 XDrawString(xDisplay, xBoardWindow, coordGC,
4177 x + 2, y + font_ascent + 1, string, 1);
4183 /* Why is this needed on some versions of X? */
4184 void EventProc(widget, unused, event)
4189 if (!XtIsRealized(widget))
4192 switch (event->type) {
4194 if (event->xexpose.count > 0) return; /* no clipping is done */
4195 XDrawPosition(widget, True, NULL);
4203 void DrawPosition(fullRedraw, board)
4204 /*Boolean*/int fullRedraw;
4207 XDrawPosition(boardWidget, fullRedraw, board);
4210 /* Returns 1 if there are "too many" differences between b1 and b2
4211 (i.e. more than 1 move was made) */
4212 static int too_many_diffs(b1, b2)
4218 for (i=0; i<BOARD_HEIGHT; ++i) {
4219 for (j=0; j<BOARD_WIDTH; ++j) {
4220 if (b1[i][j] != b2[i][j]) {
4221 if (++c > 4) /* Castling causes 4 diffs */
4230 /* Matrix describing castling maneuvers */
4231 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4232 static int castling_matrix[4][5] = {
4233 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4234 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4235 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4236 { 7, 7, 4, 5, 6 } /* 0-0, black */
4239 /* Checks whether castling occurred. If it did, *rrow and *rcol
4240 are set to the destination (row,col) of the rook that moved.
4242 Returns 1 if castling occurred, 0 if not.
4244 Note: Only handles a max of 1 castling move, so be sure
4245 to call too_many_diffs() first.
4247 static int check_castle_draw(newb, oldb, rrow, rcol)
4254 /* For each type of castling... */
4255 for (i=0; i<4; ++i) {
4256 r = castling_matrix[i];
4258 /* Check the 4 squares involved in the castling move */
4260 for (j=1; j<=4; ++j) {
4261 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4268 /* All 4 changed, so it must be a castling move */
4277 static int damage[BOARD_RANKS][BOARD_FILES];
4280 * event handler for redrawing the board
4282 void XDrawPosition(w, repaint, board)
4284 /*Boolean*/int repaint;
4288 static int lastFlipView = 0;
4289 static int lastBoardValid = 0;
4290 static Board lastBoard;
4294 if (board == NULL) {
4295 if (!lastBoardValid) return;
4298 if (!lastBoardValid || lastFlipView != flipView) {
4299 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4300 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4305 * It would be simpler to clear the window with XClearWindow()
4306 * but this causes a very distracting flicker.
4309 if (!repaint && lastBoardValid && lastFlipView == flipView) {
4311 /* If too much changes (begin observing new game, etc.), don't
4313 do_flash = too_many_diffs(board, lastBoard) ? 0 : 1;
4315 /* Special check for castling so we don't flash both the king
4316 and the rook (just flash the king). */
4318 if (check_castle_draw(board, lastBoard, &rrow, &rcol)) {
4319 /* Draw rook with NO flashing. King will be drawn flashing later */
4320 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4321 lastBoard[rrow][rcol] = board[rrow][rcol];
4325 /* First pass -- Draw (newly) empty squares and repair damage.
4326 This prevents you from having a piece show up twice while it
4327 is flashing on its new square */
4328 for (i = 0; i < BOARD_HEIGHT; i++)
4329 for (j = 0; j < BOARD_WIDTH; j++)
4330 if ((board[i][j] != lastBoard[i][j] && board[i][j] == EmptySquare)
4332 DrawSquare(i, j, board[i][j], 0);
4333 damage[i][j] = False;
4336 /* Second pass -- Draw piece(s) in new position and flash them */
4337 for (i = 0; i < BOARD_HEIGHT; i++)
4338 for (j = 0; j < BOARD_WIDTH; j++)
4339 if (board[i][j] != lastBoard[i][j]) {
4340 DrawSquare(i, j, board[i][j], do_flash);
4344 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4345 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4347 for (i = 0; i < BOARD_HEIGHT; i++)
4348 for (j = 0; j < BOARD_WIDTH; j++) {
4349 DrawSquare(i, j, board[i][j], 0);
4350 damage[i][j] = False;
4354 CopyBoard(lastBoard, board);
4356 lastFlipView = flipView;
4358 /* Draw highlights */
4359 if (pm1X >= 0 && pm1Y >= 0) {
4360 drawHighlight(pm1X, pm1Y, prelineGC);
4362 if (pm2X >= 0 && pm2Y >= 0) {
4363 drawHighlight(pm2X, pm2Y, prelineGC);
4365 if (hi1X >= 0 && hi1Y >= 0) {
4366 drawHighlight(hi1X, hi1Y, highlineGC);
4368 if (hi2X >= 0 && hi2Y >= 0) {
4369 drawHighlight(hi2X, hi2Y, highlineGC);
4372 /* If piece being dragged around board, must redraw that too */
4375 XSync(xDisplay, False);
4380 * event handler for redrawing the board
4382 void DrawPositionProc(w, event, prms, nprms)
4388 XDrawPosition(w, True, NULL);
4393 * event handler for parsing user moves
4395 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4396 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4397 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4398 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4399 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4400 // and at the end FinishMove() to perform the move after optional promotion popups.
4401 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4402 void HandleUserMove(w, event, prms, nprms)
4408 if (w != boardWidget || errorExitStatus != -1) return;
4411 if (event->type == ButtonPress) {
4412 XtPopdown(promotionShell);
4413 XtDestroyWidget(promotionShell);
4414 promotionUp = False;
4422 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4423 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4424 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4427 void AnimateUserMove (Widget w, XEvent * event,
4428 String * params, Cardinal * nParams)
4430 DragPieceMove(event->xmotion.x, event->xmotion.y);
4433 Widget CommentCreate(name, text, mutable, callback, lines)
4435 int /*Boolean*/ mutable;
4436 XtCallbackProc callback;
4440 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4445 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4446 XtGetValues(boardWidget, args, j);
4449 XtSetArg(args[j], XtNresizable, True); j++;
4452 XtCreatePopupShell(name, topLevelShellWidgetClass,
4453 shellWidget, args, j);
4456 XtCreatePopupShell(name, transientShellWidgetClass,
4457 shellWidget, args, j);
4460 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4461 layoutArgs, XtNumber(layoutArgs));
4463 XtCreateManagedWidget("form", formWidgetClass, layout,
4464 formArgs, XtNumber(formArgs));
4468 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4469 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4471 XtSetArg(args[j], XtNstring, text); j++;
4472 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4473 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4474 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4475 XtSetArg(args[j], XtNright, XtChainRight); j++;
4476 XtSetArg(args[j], XtNresizable, True); j++;
4477 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4478 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4479 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4480 XtSetArg(args[j], XtNautoFill, True); j++;
4481 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4483 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4487 XtSetArg(args[j], XtNfromVert, edit); j++;
4488 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4489 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4490 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4491 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4493 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4494 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4497 XtSetArg(args[j], XtNfromVert, edit); j++;
4498 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4499 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4500 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4501 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4502 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4504 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4505 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4508 XtSetArg(args[j], XtNfromVert, edit); j++;
4509 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4510 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4511 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4512 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4513 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4515 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4516 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
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(_("close"), commandWidgetClass, form, args, j);
4526 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4529 XtSetArg(args[j], XtNfromVert, edit); j++;
4530 XtSetArg(args[j], XtNfromHoriz, b_close); 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(_("edit"), commandWidgetClass, form, args, j);
4537 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4540 XtRealizeWidget(shell);
4542 if (commentX == -1) {
4545 Dimension pw_height;
4546 Dimension ew_height;
4549 XtSetArg(args[j], XtNheight, &ew_height); j++;
4550 XtGetValues(edit, args, j);
4553 XtSetArg(args[j], XtNheight, &pw_height); j++;
4554 XtGetValues(shell, args, j);
4555 commentH = pw_height + (lines - 1) * ew_height;
4556 commentW = bw_width - 16;
4558 XSync(xDisplay, False);
4560 /* This code seems to tickle an X bug if it is executed too soon
4561 after xboard starts up. The coordinates get transformed as if
4562 the main window was positioned at (0, 0).
4564 XtTranslateCoords(shellWidget,
4565 (bw_width - commentW) / 2, 0 - commentH / 2,
4566 &commentX, &commentY);
4568 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4569 RootWindowOfScreen(XtScreen(shellWidget)),
4570 (bw_width - commentW) / 2, 0 - commentH / 2,
4575 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4578 if(wpComment.width > 0) {
4579 commentX = wpComment.x;
4580 commentY = wpComment.y;
4581 commentW = wpComment.width;
4582 commentH = wpComment.height;
4586 XtSetArg(args[j], XtNheight, commentH); j++;
4587 XtSetArg(args[j], XtNwidth, commentW); j++;
4588 XtSetArg(args[j], XtNx, commentX); j++;
4589 XtSetArg(args[j], XtNy, commentY); j++;
4590 XtSetValues(shell, args, j);
4591 XtSetKeyboardFocus(shell, edit);
4596 /* Used for analysis window and ICS input window */
4597 Widget MiscCreate(name, text, mutable, callback, lines)
4599 int /*Boolean*/ mutable;
4600 XtCallbackProc callback;
4604 Widget shell, layout, form, edit;
4606 Dimension bw_width, pw_height, ew_height, w, h;
4612 XtSetArg(args[j], XtNresizable, True); j++;
4615 XtCreatePopupShell(name, topLevelShellWidgetClass,
4616 shellWidget, args, j);
4619 XtCreatePopupShell(name, transientShellWidgetClass,
4620 shellWidget, args, j);
4623 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4624 layoutArgs, XtNumber(layoutArgs));
4626 XtCreateManagedWidget("form", formWidgetClass, layout,
4627 formArgs, XtNumber(formArgs));
4631 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4632 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4634 XtSetArg(args[j], XtNstring, text); j++;
4635 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4636 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4637 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4638 XtSetArg(args[j], XtNright, XtChainRight); j++;
4639 XtSetArg(args[j], XtNresizable, True); j++;
4640 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4641 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4642 XtSetArg(args[j], XtNautoFill, True); j++;
4643 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4645 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4647 XtRealizeWidget(shell);
4650 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4651 XtGetValues(boardWidget, args, j);
4654 XtSetArg(args[j], XtNheight, &ew_height); j++;
4655 XtGetValues(edit, args, j);
4658 XtSetArg(args[j], XtNheight, &pw_height); j++;
4659 XtGetValues(shell, args, j);
4660 h = pw_height + (lines - 1) * ew_height;
4663 XSync(xDisplay, False);
4665 /* This code seems to tickle an X bug if it is executed too soon
4666 after xboard starts up. The coordinates get transformed as if
4667 the main window was positioned at (0, 0).
4669 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4671 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4672 RootWindowOfScreen(XtScreen(shellWidget)),
4673 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4677 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4680 XtSetArg(args[j], XtNheight, h); j++;
4681 XtSetArg(args[j], XtNwidth, w); j++;
4682 XtSetArg(args[j], XtNx, x); j++;
4683 XtSetArg(args[j], XtNy, y); j++;
4684 XtSetValues(shell, args, j);
4690 static int savedIndex; /* gross that this is global */
4692 void EditCommentPopUp(index, title, text)
4701 if (text == NULL) text = "";
4703 if (editShell == NULL) {
4705 CommentCreate(title, text, True, EditCommentCallback, 4);
4706 XtRealizeWidget(editShell);
4707 CatchDeleteWindow(editShell, "EditCommentPopDown");
4709 edit = XtNameToWidget(editShell, "*form.text");
4711 XtSetArg(args[j], XtNstring, text); j++;
4712 XtSetValues(edit, args, j);
4714 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4715 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4716 XtSetValues(editShell, args, j);
4719 XtPopup(editShell, XtGrabNone);
4723 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4724 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4728 void EditCommentCallback(w, client_data, call_data)
4730 XtPointer client_data, call_data;
4738 XtSetArg(args[j], XtNlabel, &name); j++;
4739 XtGetValues(w, args, j);
4741 if (strcmp(name, _("ok")) == 0) {
4742 edit = XtNameToWidget(editShell, "*form.text");
4744 XtSetArg(args[j], XtNstring, &val); j++;
4745 XtGetValues(edit, args, j);
4746 ReplaceComment(savedIndex, val);
4747 EditCommentPopDown();
4748 } else if (strcmp(name, _("cancel")) == 0) {
4749 EditCommentPopDown();
4750 } else if (strcmp(name, _("clear")) == 0) {
4751 edit = XtNameToWidget(editShell, "*form.text");
4752 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4753 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4757 void EditCommentPopDown()
4762 if (!editUp) return;
4764 XtSetArg(args[j], XtNx, &commentX); j++;
4765 XtSetArg(args[j], XtNy, &commentY); j++;
4766 XtSetArg(args[j], XtNheight, &commentH); j++;
4767 XtSetArg(args[j], XtNwidth, &commentW); j++;
4768 XtGetValues(editShell, args, j);
4769 XtPopdown(editShell);
4772 XtSetArg(args[j], XtNleftBitmap, None); j++;
4773 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4777 void ICSInputBoxPopUp()
4782 char *title = _("ICS Input");
4785 if (ICSInputShell == NULL) {
4786 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
4787 tr = XtParseTranslationTable(ICSInputTranslations);
4788 edit = XtNameToWidget(ICSInputShell, "*form.text");
4789 XtOverrideTranslations(edit, tr);
4790 XtRealizeWidget(ICSInputShell);
4791 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
4794 edit = XtNameToWidget(ICSInputShell, "*form.text");
4796 XtSetArg(args[j], XtNstring, ""); j++;
4797 XtSetValues(edit, args, j);
4799 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4800 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4801 XtSetValues(ICSInputShell, args, j);
4804 XtPopup(ICSInputShell, XtGrabNone);
4805 XtSetKeyboardFocus(ICSInputShell, edit);
4807 ICSInputBoxUp = True;
4809 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4810 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4814 void ICSInputSendText()
4821 edit = XtNameToWidget(ICSInputShell, "*form.text");
4823 XtSetArg(args[j], XtNstring, &val); j++;
4824 XtGetValues(edit, args, j);
4825 SendMultiLineToICS(val);
4826 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4827 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4830 void ICSInputBoxPopDown()
4835 if (!ICSInputBoxUp) return;
4837 XtPopdown(ICSInputShell);
4838 ICSInputBoxUp = False;
4840 XtSetArg(args[j], XtNleftBitmap, None); j++;
4841 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4845 void CommentPopUp(title, text)
4852 if (commentShell == NULL) {
4854 CommentCreate(title, text, False, CommentCallback, 4);
4855 XtRealizeWidget(commentShell);
4856 CatchDeleteWindow(commentShell, "CommentPopDown");
4858 edit = XtNameToWidget(commentShell, "*form.text");
4860 XtSetArg(args[j], XtNstring, text); j++;
4861 XtSetValues(edit, args, j);
4863 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4864 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4865 XtSetValues(commentShell, args, j);
4868 XtPopup(commentShell, XtGrabNone);
4869 XSync(xDisplay, False);
4874 void CommentCallback(w, client_data, call_data)
4876 XtPointer client_data, call_data;
4883 XtSetArg(args[j], XtNlabel, &name); j++;
4884 XtGetValues(w, args, j);
4886 if (strcmp(name, _("close")) == 0) {
4888 } else if (strcmp(name, _("edit")) == 0) {
4895 void CommentPopDown()
4900 if (!commentUp) return;
4902 XtSetArg(args[j], XtNx, &commentX); j++;
4903 XtSetArg(args[j], XtNy, &commentY); j++;
4904 XtSetArg(args[j], XtNwidth, &commentW); j++;
4905 XtSetArg(args[j], XtNheight, &commentH); j++;
4906 XtGetValues(commentShell, args, j);
4907 XtPopdown(commentShell);
4908 XSync(xDisplay, False);
4912 void FileNamePopUp(label, def, proc, openMode)
4919 Widget popup, layout, dialog, edit;
4925 fileProc = proc; /* I can't see a way not */
4926 fileOpenMode = openMode; /* to use globals here */
4927 { // [HGM] use file-selector dialog stolen from Ghostview
4929 int index; // this is not supported yet
4931 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
4932 NULL, openMode, NULL, &name))
4933 (void) (*fileProc)(f, index=0, name);
4937 void FileNamePopDown()
4939 if (!filenameUp) return;
4940 XtPopdown(fileNameShell);
4941 XtDestroyWidget(fileNameShell);
4946 void FileNameCallback(w, client_data, call_data)
4948 XtPointer client_data, call_data;
4953 XtSetArg(args[0], XtNlabel, &name);
4954 XtGetValues(w, args, 1);
4956 if (strcmp(name, _("cancel")) == 0) {
4961 FileNameAction(w, NULL, NULL, NULL);
4964 void FileNameAction(w, event, prms, nprms)
4976 name = XawDialogGetValueString(w = XtParent(w));
4978 if ((name != NULL) && (*name != NULLCHAR)) {
4980 XtPopdown(w = XtParent(XtParent(w)));
4984 p = strrchr(buf, ' ');
4991 fullname = ExpandPathName(buf);
4993 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
4996 f = fopen(fullname, fileOpenMode);
4998 DisplayError(_("Failed to open file"), errno);
5000 (void) (*fileProc)(f, index, buf);
5007 XtPopdown(w = XtParent(XtParent(w)));
5013 void PromotionPopUp()
5016 Widget dialog, layout;
5018 Dimension bw_width, pw_width;
5022 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5023 XtGetValues(boardWidget, args, j);
5026 XtSetArg(args[j], XtNresizable, True); j++;
5027 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5029 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5030 shellWidget, args, j);
5032 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5033 layoutArgs, XtNumber(layoutArgs));
5036 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5037 XtSetArg(args[j], XtNborderWidth, 0); j++;
5038 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5041 if(gameInfo.variant != VariantShogi) {
5042 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5043 (XtPointer) dialog);
5044 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5045 (XtPointer) dialog);
5046 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5047 (XtPointer) dialog);
5048 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5049 (XtPointer) dialog);
5050 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5051 gameInfo.variant == VariantGiveaway) {
5052 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5053 (XtPointer) dialog);
5055 if(gameInfo.variant == VariantCapablanca ||
5056 gameInfo.variant == VariantGothic ||
5057 gameInfo.variant == VariantCapaRandom) {
5058 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5059 (XtPointer) dialog);
5060 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5061 (XtPointer) dialog);
5063 } else // [HGM] shogi
5065 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5066 (XtPointer) dialog);
5067 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5068 (XtPointer) dialog);
5070 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5071 (XtPointer) dialog);
5073 XtRealizeWidget(promotionShell);
5074 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5077 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5078 XtGetValues(promotionShell, args, j);
5080 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5081 lineGap + squareSize/3 +
5082 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5083 0 : 6*(squareSize + lineGap)), &x, &y);
5086 XtSetArg(args[j], XtNx, x); j++;
5087 XtSetArg(args[j], XtNy, y); j++;
5088 XtSetValues(promotionShell, args, j);
5090 XtPopup(promotionShell, XtGrabNone);
5095 void PromotionPopDown()
5097 if (!promotionUp) return;
5098 XtPopdown(promotionShell);
5099 XtDestroyWidget(promotionShell);
5100 promotionUp = False;
5103 void PromotionCallback(w, client_data, call_data)
5105 XtPointer client_data, call_data;
5111 XtSetArg(args[0], XtNlabel, &name);
5112 XtGetValues(w, args, 1);
5116 if (fromX == -1) return;
5118 if (strcmp(name, _("cancel")) == 0) {
5122 } else if (strcmp(name, _("Knight")) == 0) {
5124 } else if (strcmp(name, _("Promote")) == 0) {
5126 } else if (strcmp(name, _("Defer")) == 0) {
5129 promoChar = ToLower(name[0]);
5132 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5134 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5135 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5140 void ErrorCallback(w, client_data, call_data)
5142 XtPointer client_data, call_data;
5145 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5147 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5153 if (!errorUp) return;
5155 XtPopdown(errorShell);
5156 XtDestroyWidget(errorShell);
5157 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5160 void ErrorPopUp(title, label, modal)
5161 char *title, *label;
5165 Widget dialog, layout;
5169 Dimension bw_width, pw_width;
5170 Dimension pw_height;
5174 XtSetArg(args[i], XtNresizable, True); i++;
5175 XtSetArg(args[i], XtNtitle, title); i++;
5177 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5178 shellWidget, args, i);
5180 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5181 layoutArgs, XtNumber(layoutArgs));
5184 XtSetArg(args[i], XtNlabel, label); i++;
5185 XtSetArg(args[i], XtNborderWidth, 0); i++;
5186 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5189 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5191 XtRealizeWidget(errorShell);
5192 CatchDeleteWindow(errorShell, "ErrorPopDown");
5195 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5196 XtGetValues(boardWidget, args, i);
5198 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5199 XtSetArg(args[i], XtNheight, &pw_height); i++;
5200 XtGetValues(errorShell, args, i);
5203 /* This code seems to tickle an X bug if it is executed too soon
5204 after xboard starts up. The coordinates get transformed as if
5205 the main window was positioned at (0, 0).
5207 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5208 0 - pw_height + squareSize / 3, &x, &y);
5210 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5211 RootWindowOfScreen(XtScreen(boardWidget)),
5212 (bw_width - pw_width) / 2,
5213 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5217 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5220 XtSetArg(args[i], XtNx, x); i++;
5221 XtSetArg(args[i], XtNy, y); i++;
5222 XtSetValues(errorShell, args, i);
5225 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5228 /* Disable all user input other than deleting the window */
5229 static int frozen = 0;
5233 /* Grab by a widget that doesn't accept input */
5234 XtAddGrab(messageWidget, TRUE, FALSE);
5238 /* Undo a FreezeUI */
5241 if (!frozen) return;
5242 XtRemoveGrab(messageWidget);
5246 char *ModeToWidgetName(mode)
5250 case BeginningOfGame:
5251 if (appData.icsActive)
5252 return "menuMode.ICS Client";
5253 else if (appData.noChessProgram ||
5254 *appData.cmailGameName != NULLCHAR)
5255 return "menuMode.Edit Game";
5257 return "menuMode.Machine Black";
5258 case MachinePlaysBlack:
5259 return "menuMode.Machine Black";
5260 case MachinePlaysWhite:
5261 return "menuMode.Machine White";
5263 return "menuMode.Analysis Mode";
5265 return "menuMode.Analyze File";
5266 case TwoMachinesPlay:
5267 return "menuMode.Two Machines";
5269 return "menuMode.Edit Game";
5270 case PlayFromGameFile:
5271 return "menuFile.Load Game";
5273 return "menuMode.Edit Position";
5275 return "menuMode.Training";
5276 case IcsPlayingWhite:
5277 case IcsPlayingBlack:
5281 return "menuMode.ICS Client";
5288 void ModeHighlight()
5291 static int oldPausing = FALSE;
5292 static GameMode oldmode = (GameMode) -1;
5295 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5297 if (pausing != oldPausing) {
5298 oldPausing = pausing;
5300 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5302 XtSetArg(args[0], XtNleftBitmap, None);
5304 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5307 if (appData.showButtonBar) {
5308 /* Always toggle, don't set. Previous code messes up when
5309 invoked while the button is pressed, as releasing it
5310 toggles the state again. */
5313 XtSetArg(args[0], XtNbackground, &oldbg);
5314 XtSetArg(args[1], XtNforeground, &oldfg);
5315 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5317 XtSetArg(args[0], XtNbackground, oldfg);
5318 XtSetArg(args[1], XtNforeground, oldbg);
5320 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5324 wname = ModeToWidgetName(oldmode);
5325 if (wname != NULL) {
5326 XtSetArg(args[0], XtNleftBitmap, None);
5327 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5329 wname = ModeToWidgetName(gameMode);
5330 if (wname != NULL) {
5331 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5332 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5336 /* Maybe all the enables should be handled here, not just this one */
5337 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5338 gameMode == Training || gameMode == PlayFromGameFile);
5343 * Button/menu procedures
5345 void ResetProc(w, event, prms, nprms)
5354 int LoadGamePopUp(f, gameNumber, title)
5359 cmailMsgLoaded = FALSE;
5360 if (gameNumber == 0) {
5361 int error = GameListBuild(f);
5363 DisplayError(_("Cannot build game list"), error);
5364 } else if (!ListEmpty(&gameList) &&
5365 ((ListGame *) gameList.tailPred)->number > 1) {
5366 GameListPopUp(f, title);
5372 return LoadGame(f, gameNumber, title, FALSE);
5375 void LoadGameProc(w, event, prms, nprms)
5381 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5384 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5387 void LoadNextGameProc(w, event, prms, nprms)
5396 void LoadPrevGameProc(w, event, prms, nprms)
5405 void ReloadGameProc(w, event, prms, nprms)
5414 void LoadNextPositionProc(w, event, prms, nprms)
5423 void LoadPrevPositionProc(w, event, prms, nprms)
5432 void ReloadPositionProc(w, event, prms, nprms)
5441 void LoadPositionProc(w, event, prms, nprms)
5447 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5450 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5453 void SaveGameProc(w, event, prms, nprms)
5459 FileNamePopUp(_("Save game file name?"),
5460 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5464 void SavePositionProc(w, event, prms, nprms)
5470 FileNamePopUp(_("Save position file name?"),
5471 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5475 void ReloadCmailMsgProc(w, event, prms, nprms)
5481 ReloadCmailMsgEvent(FALSE);
5484 void MailMoveProc(w, event, prms, nprms)
5493 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5494 char *selected_fen_position=NULL;
5497 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5498 Atom *type_return, XtPointer *value_return,
5499 unsigned long *length_return, int *format_return)
5501 char *selection_tmp;
5503 if (!selected_fen_position) return False; /* should never happen */
5504 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5505 /* note: since no XtSelectionDoneProc was registered, Xt will
5506 * automatically call XtFree on the value returned. So have to
5507 * make a copy of it allocated with XtMalloc */
5508 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5509 strcpy(selection_tmp, selected_fen_position);
5511 *value_return=selection_tmp;
5512 *length_return=strlen(selection_tmp);
5513 *type_return=*target;
5514 *format_return = 8; /* bits per byte */
5516 } else if (*target == XA_TARGETS(xDisplay)) {
5517 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5518 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5519 targets_tmp[1] = XA_STRING;
5520 *value_return = targets_tmp;
5521 *type_return = XA_ATOM;
5523 *format_return = 8 * sizeof(Atom);
5524 if (*format_return > 32) {
5525 *length_return *= *format_return / 32;
5526 *format_return = 32;
5534 /* note: when called from menu all parameters are NULL, so no clue what the
5535 * Widget which was clicked on was, or what the click event was
5537 void CopyPositionProc(w, event, prms, nprms)
5544 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5545 * have a notion of a position that is selected but not copied.
5546 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5548 if(gameMode == EditPosition) EditPositionDone(TRUE);
5549 if (selected_fen_position) free(selected_fen_position);
5550 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5551 if (!selected_fen_position) return;
5552 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5554 SendPositionSelection,
5555 NULL/* lose_ownership_proc */ ,
5556 NULL/* transfer_done_proc */);
5557 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5559 SendPositionSelection,
5560 NULL/* lose_ownership_proc */ ,
5561 NULL/* transfer_done_proc */);
5564 /* function called when the data to Paste is ready */
5566 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5567 Atom *type, XtPointer value, unsigned long *len, int *format)
5570 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5571 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5572 EditPositionPasteFEN(fenstr);
5576 /* called when Paste Position button is pressed,
5577 * all parameters will be NULL */
5578 void PastePositionProc(w, event, prms, nprms)
5584 XtGetSelectionValue(menuBarWidget,
5585 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5586 /* (XtSelectionCallbackProc) */ PastePositionCB,
5587 NULL, /* client_data passed to PastePositionCB */
5589 /* better to use the time field from the event that triggered the
5590 * call to this function, but that isn't trivial to get
5598 SendGameSelection(Widget w, Atom *selection, Atom *target,
5599 Atom *type_return, XtPointer *value_return,
5600 unsigned long *length_return, int *format_return)
5602 char *selection_tmp;
5604 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5605 FILE* f = fopen(gameCopyFilename, "r");
5608 if (f == NULL) return False;
5612 selection_tmp = XtMalloc(len + 1);
5613 count = fread(selection_tmp, 1, len, f);
5615 XtFree(selection_tmp);
5618 selection_tmp[len] = NULLCHAR;
5619 *value_return = selection_tmp;
5620 *length_return = len;
5621 *type_return = *target;
5622 *format_return = 8; /* bits per byte */
5624 } else if (*target == XA_TARGETS(xDisplay)) {
5625 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5626 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5627 targets_tmp[1] = XA_STRING;
5628 *value_return = targets_tmp;
5629 *type_return = XA_ATOM;
5631 *format_return = 8 * sizeof(Atom);
5632 if (*format_return > 32) {
5633 *length_return *= *format_return / 32;
5634 *format_return = 32;
5642 /* note: when called from menu all parameters are NULL, so no clue what the
5643 * Widget which was clicked on was, or what the click event was
5645 void CopyGameProc(w, event, prms, nprms)
5653 ret = SaveGameToFile(gameCopyFilename, FALSE);
5657 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5658 * have a notion of a game that is selected but not copied.
5659 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5661 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5664 NULL/* lose_ownership_proc */ ,
5665 NULL/* transfer_done_proc */);
5666 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5669 NULL/* lose_ownership_proc */ ,
5670 NULL/* transfer_done_proc */);
5673 /* function called when the data to Paste is ready */
5675 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5676 Atom *type, XtPointer value, unsigned long *len, int *format)
5679 if (value == NULL || *len == 0) {
5680 return; /* nothing had been selected to copy */
5682 f = fopen(gamePasteFilename, "w");
5684 DisplayError(_("Can't open temp file"), errno);
5687 fwrite(value, 1, *len, f);
5690 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5693 /* called when Paste Game button is pressed,
5694 * all parameters will be NULL */
5695 void PasteGameProc(w, event, prms, nprms)
5701 XtGetSelectionValue(menuBarWidget,
5702 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5703 /* (XtSelectionCallbackProc) */ PasteGameCB,
5704 NULL, /* client_data passed to PasteGameCB */
5706 /* better to use the time field from the event that triggered the
5707 * call to this function, but that isn't trivial to get
5717 SaveGameProc(NULL, NULL, NULL, NULL);
5721 void QuitProc(w, event, prms, nprms)
5730 void PauseProc(w, event, prms, nprms)
5740 void MachineBlackProc(w, event, prms, nprms)
5746 MachineBlackEvent();
5749 void MachineWhiteProc(w, event, prms, nprms)
5755 MachineWhiteEvent();
5758 void AnalyzeModeProc(w, event, prms, nprms)
5766 if (!first.analysisSupport) {
5767 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5768 DisplayError(buf, 0);
5771 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5772 if (appData.icsActive) {
5773 if (gameMode != IcsObserving) {
5774 sprintf(buf,_("You are not observing a game"));
5775 DisplayError(buf, 0);
5777 if (appData.icsEngineAnalyze) {
5778 if (appData.debugMode)
5779 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5785 /* if enable, use want disable icsEngineAnalyze */
5786 if (appData.icsEngineAnalyze) {
5791 appData.icsEngineAnalyze = TRUE;
5792 if (appData.debugMode)
5793 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5795 if (!appData.showThinking)
5796 ShowThinkingProc(w,event,prms,nprms);
5801 void AnalyzeFileProc(w, event, prms, nprms)
5807 if (!first.analysisSupport) {
5809 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5810 DisplayError(buf, 0);
5815 if (!appData.showThinking)
5816 ShowThinkingProc(w,event,prms,nprms);
5819 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
5820 AnalysisPeriodicEvent(1);
5823 void TwoMachinesProc(w, event, prms, nprms)
5832 void IcsClientProc(w, event, prms, nprms)
5841 void EditGameProc(w, event, prms, nprms)
5850 void EditPositionProc(w, event, prms, nprms)
5856 EditPositionEvent();
5859 void TrainingProc(w, event, prms, nprms)
5868 void EditCommentProc(w, event, prms, nprms)
5875 EditCommentPopDown();
5881 void IcsInputBoxProc(w, event, prms, nprms)
5887 if (ICSInputBoxUp) {
5888 ICSInputBoxPopDown();
5894 void AcceptProc(w, event, prms, nprms)
5903 void DeclineProc(w, event, prms, nprms)
5912 void RematchProc(w, event, prms, nprms)
5921 void CallFlagProc(w, event, prms, nprms)
5930 void DrawProc(w, event, prms, nprms)
5939 void AbortProc(w, event, prms, nprms)
5948 void AdjournProc(w, event, prms, nprms)
5957 void ResignProc(w, event, prms, nprms)
5966 void AdjuWhiteProc(w, event, prms, nprms)
5972 UserAdjudicationEvent(+1);
5975 void AdjuBlackProc(w, event, prms, nprms)
5981 UserAdjudicationEvent(-1);
5984 void AdjuDrawProc(w, event, prms, nprms)
5990 UserAdjudicationEvent(0);
5993 void EnterKeyProc(w, event, prms, nprms)
5999 if (ICSInputBoxUp == True)
6003 void StopObservingProc(w, event, prms, nprms)
6009 StopObservingEvent();
6012 void StopExaminingProc(w, event, prms, nprms)
6018 StopExaminingEvent();
6022 void ForwardProc(w, event, prms, nprms)
6032 void BackwardProc(w, event, prms, nprms)
6041 void ToStartProc(w, event, prms, nprms)
6050 void ToEndProc(w, event, prms, nprms)
6059 void RevertProc(w, event, prms, nprms)
6068 void TruncateGameProc(w, event, prms, nprms)
6074 TruncateGameEvent();
6076 void RetractMoveProc(w, event, prms, nprms)
6085 void MoveNowProc(w, event, prms, nprms)
6095 void AlwaysQueenProc(w, event, prms, nprms)
6103 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6105 if (appData.alwaysPromoteToQueen) {
6106 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6108 XtSetArg(args[0], XtNleftBitmap, None);
6110 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6114 void AnimateDraggingProc(w, event, prms, nprms)
6122 appData.animateDragging = !appData.animateDragging;
6124 if (appData.animateDragging) {
6125 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6128 XtSetArg(args[0], XtNleftBitmap, None);
6130 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6134 void AnimateMovingProc(w, event, prms, nprms)
6142 appData.animate = !appData.animate;
6144 if (appData.animate) {
6145 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6148 XtSetArg(args[0], XtNleftBitmap, None);
6150 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6154 void AutocommProc(w, event, prms, nprms)
6162 appData.autoComment = !appData.autoComment;
6164 if (appData.autoComment) {
6165 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6167 XtSetArg(args[0], XtNleftBitmap, None);
6169 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6174 void AutoflagProc(w, event, prms, nprms)
6182 appData.autoCallFlag = !appData.autoCallFlag;
6184 if (appData.autoCallFlag) {
6185 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6187 XtSetArg(args[0], XtNleftBitmap, None);
6189 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6193 void AutoflipProc(w, event, prms, nprms)
6201 appData.autoFlipView = !appData.autoFlipView;
6203 if (appData.autoFlipView) {
6204 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6206 XtSetArg(args[0], XtNleftBitmap, None);
6208 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6212 void AutobsProc(w, event, prms, nprms)
6220 appData.autoObserve = !appData.autoObserve;
6222 if (appData.autoObserve) {
6223 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6225 XtSetArg(args[0], XtNleftBitmap, None);
6227 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6231 void AutoraiseProc(w, event, prms, nprms)
6239 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6241 if (appData.autoRaiseBoard) {
6242 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6244 XtSetArg(args[0], XtNleftBitmap, None);
6246 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6250 void AutosaveProc(w, event, prms, nprms)
6258 appData.autoSaveGames = !appData.autoSaveGames;
6260 if (appData.autoSaveGames) {
6261 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6263 XtSetArg(args[0], XtNleftBitmap, None);
6265 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6269 void BlindfoldProc(w, event, prms, nprms)
6277 appData.blindfold = !appData.blindfold;
6279 if (appData.blindfold) {
6280 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6282 XtSetArg(args[0], XtNleftBitmap, None);
6284 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6287 DrawPosition(True, NULL);
6290 void TestLegalityProc(w, event, prms, nprms)
6298 appData.testLegality = !appData.testLegality;
6300 if (appData.testLegality) {
6301 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6303 XtSetArg(args[0], XtNleftBitmap, None);
6305 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6310 void FlashMovesProc(w, event, prms, nprms)
6318 if (appData.flashCount == 0) {
6319 appData.flashCount = 3;
6321 appData.flashCount = -appData.flashCount;
6324 if (appData.flashCount > 0) {
6325 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6327 XtSetArg(args[0], XtNleftBitmap, None);
6329 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6333 void FlipViewProc(w, event, prms, nprms)
6339 flipView = !flipView;
6340 DrawPosition(True, NULL);
6343 void GetMoveListProc(w, event, prms, nprms)
6351 appData.getMoveList = !appData.getMoveList;
6353 if (appData.getMoveList) {
6354 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6357 XtSetArg(args[0], XtNleftBitmap, None);
6359 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6364 void HighlightDraggingProc(w, event, prms, nprms)
6372 appData.highlightDragging = !appData.highlightDragging;
6374 if (appData.highlightDragging) {
6375 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6377 XtSetArg(args[0], XtNleftBitmap, None);
6379 XtSetValues(XtNameToWidget(menuBarWidget,
6380 "menuOptions.Highlight Dragging"), args, 1);
6384 void HighlightLastMoveProc(w, event, prms, nprms)
6392 appData.highlightLastMove = !appData.highlightLastMove;
6394 if (appData.highlightLastMove) {
6395 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6397 XtSetArg(args[0], XtNleftBitmap, None);
6399 XtSetValues(XtNameToWidget(menuBarWidget,
6400 "menuOptions.Highlight Last Move"), args, 1);
6403 void IcsAlarmProc(w, event, prms, nprms)
6411 appData.icsAlarm = !appData.icsAlarm;
6413 if (appData.icsAlarm) {
6414 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6416 XtSetArg(args[0], XtNleftBitmap, None);
6418 XtSetValues(XtNameToWidget(menuBarWidget,
6419 "menuOptions.ICS Alarm"), args, 1);
6422 void MoveSoundProc(w, event, prms, nprms)
6430 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6432 if (appData.ringBellAfterMoves) {
6433 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6435 XtSetArg(args[0], XtNleftBitmap, None);
6437 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6442 void OldSaveStyleProc(w, event, prms, nprms)
6450 appData.oldSaveStyle = !appData.oldSaveStyle;
6452 if (appData.oldSaveStyle) {
6453 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6455 XtSetArg(args[0], XtNleftBitmap, None);
6457 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6461 void PeriodicUpdatesProc(w, event, prms, nprms)
6469 PeriodicUpdatesEvent(!appData.periodicUpdates);
6471 if (appData.periodicUpdates) {
6472 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6474 XtSetArg(args[0], XtNleftBitmap, None);
6476 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6480 void PonderNextMoveProc(w, event, prms, nprms)
6488 PonderNextMoveEvent(!appData.ponderNextMove);
6490 if (appData.ponderNextMove) {
6491 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6493 XtSetArg(args[0], XtNleftBitmap, None);
6495 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6499 void PopupExitMessageProc(w, event, prms, nprms)
6507 appData.popupExitMessage = !appData.popupExitMessage;
6509 if (appData.popupExitMessage) {
6510 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6512 XtSetArg(args[0], XtNleftBitmap, None);
6514 XtSetValues(XtNameToWidget(menuBarWidget,
6515 "menuOptions.Popup Exit Message"), args, 1);
6518 void PopupMoveErrorsProc(w, event, prms, nprms)
6526 appData.popupMoveErrors = !appData.popupMoveErrors;
6528 if (appData.popupMoveErrors) {
6529 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6531 XtSetArg(args[0], XtNleftBitmap, None);
6533 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6537 void PremoveProc(w, event, prms, nprms)
6545 appData.premove = !appData.premove;
6547 if (appData.premove) {
6548 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6550 XtSetArg(args[0], XtNleftBitmap, None);
6552 XtSetValues(XtNameToWidget(menuBarWidget,
6553 "menuOptions.Premove"), args, 1);
6556 void QuietPlayProc(w, event, prms, nprms)
6564 appData.quietPlay = !appData.quietPlay;
6566 if (appData.quietPlay) {
6567 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6569 XtSetArg(args[0], XtNleftBitmap, None);
6571 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6575 void ShowCoordsProc(w, event, prms, nprms)
6583 appData.showCoords = !appData.showCoords;
6585 if (appData.showCoords) {
6586 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6588 XtSetArg(args[0], XtNleftBitmap, None);
6590 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6593 DrawPosition(True, NULL);
6596 void ShowThinkingProc(w, event, prms, nprms)
6602 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6603 ShowThinkingEvent();
6606 void HideThinkingProc(w, event, prms, nprms)
6614 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6615 ShowThinkingEvent();
6617 if (appData.hideThinkingFromHuman) {
6618 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6620 XtSetArg(args[0], XtNleftBitmap, None);
6622 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6626 void SaveOnExitProc(w, event, prms, nprms)
6634 saveSettingsOnExit = !saveSettingsOnExit;
6636 if (saveSettingsOnExit) {
6637 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6639 XtSetArg(args[0], XtNleftBitmap, None);
6641 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6645 void SaveSettingsProc(w, event, prms, nprms)
6651 SaveSettings(settingsFileName);
6654 void InfoProc(w, event, prms, nprms)
6661 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6666 void ManProc(w, event, prms, nprms)
6674 if (nprms && *nprms > 0)
6678 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6682 void HintProc(w, event, prms, nprms)
6691 void BookProc(w, event, prms, nprms)
6700 void AboutProc(w, event, prms, nprms)
6708 char *zippy = " (with Zippy code)";
6712 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6713 programVersion, zippy,
6714 "Copyright 1991 Digital Equipment Corporation",
6715 "Enhancements Copyright 1992-2009 Free Software Foundation",
6716 "Enhancements Copyright 2005 Alessandro Scotti",
6717 PACKAGE, " is free software and carries NO WARRANTY;",
6718 "see the file COPYING for more information.");
6719 ErrorPopUp(_("About XBoard"), buf, FALSE);
6722 void DebugProc(w, event, prms, nprms)
6728 appData.debugMode = !appData.debugMode;
6731 void AboutGameProc(w, event, prms, nprms)
6740 void NothingProc(w, event, prms, nprms)
6749 void Iconify(w, event, prms, nprms)
6758 XtSetArg(args[0], XtNiconic, True);
6759 XtSetValues(shellWidget, args, 1);
6762 void DisplayMessage(message, extMessage)
6763 char *message, *extMessage;
6765 /* display a message in the message widget */
6774 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
6779 message = extMessage;
6783 /* need to test if messageWidget already exists, since this function
6784 can also be called during the startup, if for example a Xresource
6785 is not set up correctly */
6788 XtSetArg(arg, XtNlabel, message);
6789 XtSetValues(messageWidget, &arg, 1);
6795 void DisplayTitle(text)
6800 char title[MSG_SIZ];
6803 if (text == NULL) text = "";
6805 if (appData.titleInWindow) {
6807 XtSetArg(args[i], XtNlabel, text); i++;
6808 XtSetValues(titleWidget, args, i);
6811 if (*text != NULLCHAR) {
6813 strcpy(title, text);
6814 } else if (appData.icsActive) {
6815 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
6816 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
6817 } else if (appData.cmailGameName[0] != NULLCHAR) {
6818 snprintf(icon, sizeof(icon), "%s", "CMail");
6819 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
6821 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
6822 } else if (gameInfo.variant == VariantGothic) {
6823 strcpy(icon, programName);
6824 strcpy(title, GOTHIC);
6827 } else if (gameInfo.variant == VariantFalcon) {
6828 strcpy(icon, programName);
6829 strcpy(title, FALCON);
6831 } else if (appData.noChessProgram) {
6832 strcpy(icon, programName);
6833 strcpy(title, programName);
6835 strcpy(icon, first.tidy);
6836 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
6839 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
6840 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
6841 XtSetValues(shellWidget, args, i);
6845 void DisplayError(message, error)
6852 if (appData.debugMode || appData.matchMode) {
6853 fprintf(stderr, "%s: %s\n", programName, message);
6856 if (appData.debugMode || appData.matchMode) {
6857 fprintf(stderr, "%s: %s: %s\n",
6858 programName, message, strerror(error));
6860 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6863 ErrorPopUp(_("Error"), message, FALSE);
6867 void DisplayMoveError(message)
6872 DrawPosition(FALSE, NULL);
6873 if (appData.debugMode || appData.matchMode) {
6874 fprintf(stderr, "%s: %s\n", programName, message);
6876 if (appData.popupMoveErrors) {
6877 ErrorPopUp(_("Error"), message, FALSE);
6879 DisplayMessage(message, "");
6884 void DisplayFatalError(message, error, status)
6890 errorExitStatus = status;
6892 fprintf(stderr, "%s: %s\n", programName, message);
6894 fprintf(stderr, "%s: %s: %s\n",
6895 programName, message, strerror(error));
6896 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6899 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
6900 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
6906 void DisplayInformation(message)
6910 ErrorPopUp(_("Information"), message, TRUE);
6913 void DisplayNote(message)
6917 ErrorPopUp(_("Note"), message, FALSE);
6921 NullXErrorCheck(dpy, error_event)
6923 XErrorEvent *error_event;
6928 void DisplayIcsInteractionTitle(message)
6931 if (oldICSInteractionTitle == NULL) {
6932 /* Magic to find the old window title, adapted from vim */
6933 char *wina = getenv("WINDOWID");
6935 Window win = (Window) atoi(wina);
6936 Window root, parent, *children;
6937 unsigned int nchildren;
6938 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
6940 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
6941 if (!XQueryTree(xDisplay, win, &root, &parent,
6942 &children, &nchildren)) break;
6943 if (children) XFree((void *)children);
6944 if (parent == root || parent == 0) break;
6947 XSetErrorHandler(oldHandler);
6949 if (oldICSInteractionTitle == NULL) {
6950 oldICSInteractionTitle = "xterm";
6953 printf("\033]0;%s\007", message);
6957 char pendingReplyPrefix[MSG_SIZ];
6958 ProcRef pendingReplyPR;
6960 void AskQuestionProc(w, event, prms, nprms)
6967 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
6971 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
6974 void AskQuestionPopDown()
6976 if (!askQuestionUp) return;
6977 XtPopdown(askQuestionShell);
6978 XtDestroyWidget(askQuestionShell);
6979 askQuestionUp = False;
6982 void AskQuestionReplyAction(w, event, prms, nprms)
6992 reply = XawDialogGetValueString(w = XtParent(w));
6993 strcpy(buf, pendingReplyPrefix);
6994 if (*buf) strcat(buf, " ");
6997 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
6998 AskQuestionPopDown();
7000 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7003 void AskQuestionCallback(w, client_data, call_data)
7005 XtPointer client_data, call_data;
7010 XtSetArg(args[0], XtNlabel, &name);
7011 XtGetValues(w, args, 1);
7013 if (strcmp(name, _("cancel")) == 0) {
7014 AskQuestionPopDown();
7016 AskQuestionReplyAction(w, NULL, NULL, NULL);
7020 void AskQuestion(title, question, replyPrefix, pr)
7021 char *title, *question, *replyPrefix;
7025 Widget popup, layout, dialog, edit;
7031 strcpy(pendingReplyPrefix, replyPrefix);
7032 pendingReplyPR = pr;
7035 XtSetArg(args[i], XtNresizable, True); i++;
7036 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7037 askQuestionShell = popup =
7038 XtCreatePopupShell(title, transientShellWidgetClass,
7039 shellWidget, args, i);
7042 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7043 layoutArgs, XtNumber(layoutArgs));
7046 XtSetArg(args[i], XtNlabel, question); i++;
7047 XtSetArg(args[i], XtNvalue, ""); i++;
7048 XtSetArg(args[i], XtNborderWidth, 0); i++;
7049 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7052 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7053 (XtPointer) dialog);
7054 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7055 (XtPointer) dialog);
7057 XtRealizeWidget(popup);
7058 CatchDeleteWindow(popup, "AskQuestionPopDown");
7060 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7061 &x, &y, &win_x, &win_y, &mask);
7063 XtSetArg(args[0], XtNx, x - 10);
7064 XtSetArg(args[1], XtNy, y - 30);
7065 XtSetValues(popup, args, 2);
7067 XtPopup(popup, XtGrabExclusive);
7068 askQuestionUp = True;
7070 edit = XtNameToWidget(dialog, "*value");
7071 XtSetKeyboardFocus(popup, edit);
7079 if (*name == NULLCHAR) {
7081 } else if (strcmp(name, "$") == 0) {
7082 putc(BELLCHAR, stderr);
7085 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7093 PlaySound(appData.soundMove);
7099 PlaySound(appData.soundIcsWin);
7105 PlaySound(appData.soundIcsLoss);
7111 PlaySound(appData.soundIcsDraw);
7115 PlayIcsUnfinishedSound()
7117 PlaySound(appData.soundIcsUnfinished);
7123 PlaySound(appData.soundIcsAlarm);
7129 system("stty echo");
7135 system("stty -echo");
7139 Colorize(cc, continuation)
7144 int count, outCount, error;
7146 if (textColors[(int)cc].bg > 0) {
7147 if (textColors[(int)cc].fg > 0) {
7148 sprintf(buf, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7149 textColors[(int)cc].fg, textColors[(int)cc].bg);
7151 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7152 textColors[(int)cc].bg);
7155 if (textColors[(int)cc].fg > 0) {
7156 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7157 textColors[(int)cc].fg);
7159 sprintf(buf, "\033[0;%dm", textColors[(int)cc].attr);
7162 count = strlen(buf);
7163 outCount = OutputToProcess(NoProc, buf, count, &error);
7164 if (outCount < count) {
7165 DisplayFatalError(_("Error writing to display"), error, 1);
7168 if (continuation) return;
7171 PlaySound(appData.soundShout);
7174 PlaySound(appData.soundSShout);
7177 PlaySound(appData.soundChannel1);
7180 PlaySound(appData.soundChannel);
7183 PlaySound(appData.soundKibitz);
7186 PlaySound(appData.soundTell);
7188 case ColorChallenge:
7189 PlaySound(appData.soundChallenge);
7192 PlaySound(appData.soundRequest);
7195 PlaySound(appData.soundSeek);
7206 return getpwuid(getuid())->pw_name;
7209 static char *ExpandPathName(path)
7212 static char static_buf[2000];
7213 char *d, *s, buf[2000];
7219 while (*s && isspace(*s))
7228 if (*(s+1) == '/') {
7229 strcpy(d, getpwuid(getuid())->pw_dir);
7234 *strchr(buf, '/') = 0;
7235 pwd = getpwnam(buf);
7238 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7242 strcpy(d, pwd->pw_dir);
7243 strcat(d, strchr(s+1, '/'));
7254 static char host_name[MSG_SIZ];
7256 #if HAVE_GETHOSTNAME
7257 gethostname(host_name, MSG_SIZ);
7259 #else /* not HAVE_GETHOSTNAME */
7260 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7261 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7263 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7265 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7266 #endif /* not HAVE_GETHOSTNAME */
7269 XtIntervalId delayedEventTimerXID = 0;
7270 DelayedEventCallback delayedEventCallback = 0;
7275 delayedEventTimerXID = 0;
7276 delayedEventCallback();
7280 ScheduleDelayedEvent(cb, millisec)
7281 DelayedEventCallback cb; long millisec;
7283 if(delayedEventTimerXID && delayedEventCallback == cb)
7284 // [HGM] alive: replace, rather than add or flush identical event
7285 XtRemoveTimeOut(delayedEventTimerXID);
7286 delayedEventCallback = cb;
7287 delayedEventTimerXID =
7288 XtAppAddTimeOut(appContext, millisec,
7289 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7292 DelayedEventCallback
7295 if (delayedEventTimerXID) {
7296 return delayedEventCallback;
7303 CancelDelayedEvent()
7305 if (delayedEventTimerXID) {
7306 XtRemoveTimeOut(delayedEventTimerXID);
7307 delayedEventTimerXID = 0;
7311 XtIntervalId loadGameTimerXID = 0;
7313 int LoadGameTimerRunning()
7315 return loadGameTimerXID != 0;
7318 int StopLoadGameTimer()
7320 if (loadGameTimerXID != 0) {
7321 XtRemoveTimeOut(loadGameTimerXID);
7322 loadGameTimerXID = 0;
7330 LoadGameTimerCallback(arg, id)
7334 loadGameTimerXID = 0;
7339 StartLoadGameTimer(millisec)
7343 XtAppAddTimeOut(appContext, millisec,
7344 (XtTimerCallbackProc) LoadGameTimerCallback,
7348 XtIntervalId analysisClockXID = 0;
7351 AnalysisClockCallback(arg, id)
7355 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7356 || appData.icsEngineAnalyze) { // [DM]
7357 AnalysisPeriodicEvent(0);
7358 StartAnalysisClock();
7363 StartAnalysisClock()
7366 XtAppAddTimeOut(appContext, 2000,
7367 (XtTimerCallbackProc) AnalysisClockCallback,
7371 XtIntervalId clockTimerXID = 0;
7373 int ClockTimerRunning()
7375 return clockTimerXID != 0;
7378 int StopClockTimer()
7380 if (clockTimerXID != 0) {
7381 XtRemoveTimeOut(clockTimerXID);
7390 ClockTimerCallback(arg, id)
7399 StartClockTimer(millisec)
7403 XtAppAddTimeOut(appContext, millisec,
7404 (XtTimerCallbackProc) ClockTimerCallback,
7409 DisplayTimerLabel(w, color, timer, highlight)
7418 /* check for low time warning */
7419 Pixel foregroundOrWarningColor = timerForegroundPixel;
7422 appData.lowTimeWarning &&
7423 (timer / 1000) < appData.icsAlarmTime)
7424 foregroundOrWarningColor = lowTimeWarningColor;
7426 if (appData.clockMode) {
7427 sprintf(buf, "%s: %s", color, TimeString(timer));
7428 XtSetArg(args[0], XtNlabel, buf);
7430 sprintf(buf, "%s ", color);
7431 XtSetArg(args[0], XtNlabel, buf);
7436 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7437 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7439 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7440 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7443 XtSetValues(w, args, 3);
7447 DisplayWhiteClock(timeRemaining, highlight)
7453 if(appData.noGUI) return;
7454 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7455 if (highlight && iconPixmap == bIconPixmap) {
7456 iconPixmap = wIconPixmap;
7457 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7458 XtSetValues(shellWidget, args, 1);
7463 DisplayBlackClock(timeRemaining, highlight)
7469 if(appData.noGUI) return;
7470 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7471 if (highlight && iconPixmap == wIconPixmap) {
7472 iconPixmap = bIconPixmap;
7473 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7474 XtSetValues(shellWidget, args, 1);
7492 int StartChildProcess(cmdLine, dir, pr)
7499 int to_prog[2], from_prog[2];
7503 if (appData.debugMode) {
7504 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7507 /* We do NOT feed the cmdLine to the shell; we just
7508 parse it into blank-separated arguments in the
7509 most simple-minded way possible.
7512 strcpy(buf, cmdLine);
7515 while(*p == ' ') p++;
7517 if(*p == '"' || *p == '\'')
7518 p = strchr(++argv[i-1], *p);
7519 else p = strchr(p, ' ');
7520 if (p == NULL) break;
7525 SetUpChildIO(to_prog, from_prog);
7527 if ((pid = fork()) == 0) {
7529 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7530 close(to_prog[1]); // first close the unused pipe ends
7531 close(from_prog[0]);
7532 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7533 dup2(from_prog[1], 1);
7534 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7535 close(from_prog[1]); // and closing again loses one of the pipes!
7536 if(fileno(stderr) >= 2) // better safe than sorry...
7537 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7539 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7544 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7546 execvp(argv[0], argv);
7548 /* If we get here, exec failed */
7553 /* Parent process */
7555 close(from_prog[1]);
7557 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7560 cp->fdFrom = from_prog[0];
7561 cp->fdTo = to_prog[1];
7566 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7567 static RETSIGTYPE AlarmCallBack(int n)
7573 DestroyChildProcess(pr, signalType)
7577 ChildProc *cp = (ChildProc *) pr;
7579 if (cp->kind != CPReal) return;
7581 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7582 signal(SIGALRM, AlarmCallBack);
7584 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7585 kill(cp->pid, SIGKILL); // kill it forcefully
7586 wait((int *) 0); // and wait again
7590 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7592 /* Process is exiting either because of the kill or because of
7593 a quit command sent by the backend; either way, wait for it to die.
7602 InterruptChildProcess(pr)
7605 ChildProc *cp = (ChildProc *) pr;
7607 if (cp->kind != CPReal) return;
7608 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7611 int OpenTelnet(host, port, pr)
7616 char cmdLine[MSG_SIZ];
7618 if (port[0] == NULLCHAR) {
7619 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7621 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7623 return StartChildProcess(cmdLine, "", pr);
7626 int OpenTCP(host, port, pr)
7632 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7633 #else /* !OMIT_SOCKETS */
7635 struct sockaddr_in sa;
7637 unsigned short uport;
7640 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7644 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7645 sa.sin_family = AF_INET;
7646 sa.sin_addr.s_addr = INADDR_ANY;
7647 uport = (unsigned short) 0;
7648 sa.sin_port = htons(uport);
7649 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7653 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7654 if (!(hp = gethostbyname(host))) {
7656 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7657 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7658 hp->h_addrtype = AF_INET;
7660 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7661 hp->h_addr_list[0] = (char *) malloc(4);
7662 hp->h_addr_list[0][0] = b0;
7663 hp->h_addr_list[0][1] = b1;
7664 hp->h_addr_list[0][2] = b2;
7665 hp->h_addr_list[0][3] = b3;
7670 sa.sin_family = hp->h_addrtype;
7671 uport = (unsigned short) atoi(port);
7672 sa.sin_port = htons(uport);
7673 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7675 if (connect(s, (struct sockaddr *) &sa,
7676 sizeof(struct sockaddr_in)) < 0) {
7680 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7687 #endif /* !OMIT_SOCKETS */
7692 int OpenCommPort(name, pr)
7699 fd = open(name, 2, 0);
7700 if (fd < 0) return errno;
7702 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7712 int OpenLoopback(pr)
7718 SetUpChildIO(to, from);
7720 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7723 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7730 int OpenRcmd(host, user, cmd, pr)
7731 char *host, *user, *cmd;
7734 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7738 #define INPUT_SOURCE_BUF_SIZE 8192
7747 char buf[INPUT_SOURCE_BUF_SIZE];
7752 DoInputCallback(closure, source, xid)
7757 InputSource *is = (InputSource *) closure;
7762 if (is->lineByLine) {
7763 count = read(is->fd, is->unused,
7764 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7766 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7769 is->unused += count;
7771 while (p < is->unused) {
7772 q = memchr(p, '\n', is->unused - p);
7773 if (q == NULL) break;
7775 (is->func)(is, is->closure, p, q - p, 0);
7779 while (p < is->unused) {
7784 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
7789 (is->func)(is, is->closure, is->buf, count, error);
7793 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
7800 ChildProc *cp = (ChildProc *) pr;
7802 is = (InputSource *) calloc(1, sizeof(InputSource));
7803 is->lineByLine = lineByLine;
7807 is->fd = fileno(stdin);
7809 is->kind = cp->kind;
7810 is->fd = cp->fdFrom;
7813 is->unused = is->buf;
7816 is->xid = XtAppAddInput(appContext, is->fd,
7817 (XtPointer) (XtInputReadMask),
7818 (XtInputCallbackProc) DoInputCallback,
7820 is->closure = closure;
7821 return (InputSourceRef) is;
7825 RemoveInputSource(isr)
7828 InputSource *is = (InputSource *) isr;
7830 if (is->xid == 0) return;
7831 XtRemoveInput(is->xid);
7835 int OutputToProcess(pr, message, count, outError)
7841 static int line = 0;
7842 ChildProc *cp = (ChildProc *) pr;
7847 if (appData.noJoin || !appData.useInternalWrap)
7848 outCount = fwrite(message, 1, count, stdout);
7851 int width = get_term_width();
7852 int len = wrap(NULL, message, count, width, &line);
7853 char *msg = malloc(len);
7857 outCount = fwrite(message, 1, count, stdout);
7860 dbgchk = wrap(msg, message, count, width, &line);
7861 if (dbgchk != len && appData.debugMode)
7862 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
7863 outCount = fwrite(msg, 1, dbgchk, stdout);
7869 outCount = write(cp->fdTo, message, count);
7879 /* Output message to process, with "ms" milliseconds of delay
7880 between each character. This is needed when sending the logon
7881 script to ICC, which for some reason doesn't like the
7882 instantaneous send. */
7883 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
7890 ChildProc *cp = (ChildProc *) pr;
7895 r = write(cp->fdTo, message++, 1);
7908 /**** Animation code by Hugh Fisher, DCS, ANU.
7910 Known problem: if a window overlapping the board is
7911 moved away while a piece is being animated underneath,
7912 the newly exposed area won't be updated properly.
7913 I can live with this.
7915 Known problem: if you look carefully at the animation
7916 of pieces in mono mode, they are being drawn as solid
7917 shapes without interior detail while moving. Fixing
7918 this would be a major complication for minimal return.
7921 /* Masks for XPM pieces. Black and white pieces can have
7922 different shapes, but in the interest of retaining my
7923 sanity pieces must have the same outline on both light
7924 and dark squares, and all pieces must use the same
7925 background square colors/images. */
7927 static int xpmDone = 0;
7930 CreateAnimMasks (pieceDepth)
7937 unsigned long plane;
7940 /* Need a bitmap just to get a GC with right depth */
7941 buf = XCreatePixmap(xDisplay, xBoardWindow,
7943 values.foreground = 1;
7944 values.background = 0;
7945 /* Don't use XtGetGC, not read only */
7946 maskGC = XCreateGC(xDisplay, buf,
7947 GCForeground | GCBackground, &values);
7948 XFreePixmap(xDisplay, buf);
7950 buf = XCreatePixmap(xDisplay, xBoardWindow,
7951 squareSize, squareSize, pieceDepth);
7952 values.foreground = XBlackPixel(xDisplay, xScreen);
7953 values.background = XWhitePixel(xDisplay, xScreen);
7954 bufGC = XCreateGC(xDisplay, buf,
7955 GCForeground | GCBackground, &values);
7957 for (piece = WhitePawn; piece <= BlackKing; piece++) {
7958 /* Begin with empty mask */
7959 if(!xpmDone) // [HGM] pieces: keep using existing
7960 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
7961 squareSize, squareSize, 1);
7962 XSetFunction(xDisplay, maskGC, GXclear);
7963 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
7964 0, 0, squareSize, squareSize);
7966 /* Take a copy of the piece */
7971 XSetFunction(xDisplay, bufGC, GXcopy);
7972 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
7974 0, 0, squareSize, squareSize, 0, 0);
7976 /* XOR the background (light) over the piece */
7977 XSetFunction(xDisplay, bufGC, GXxor);
7979 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
7980 0, 0, squareSize, squareSize, 0, 0);
7982 XSetForeground(xDisplay, bufGC, lightSquareColor);
7983 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
7986 /* We now have an inverted piece image with the background
7987 erased. Construct mask by just selecting all the non-zero
7988 pixels - no need to reconstruct the original image. */
7989 XSetFunction(xDisplay, maskGC, GXor);
7991 /* Might be quicker to download an XImage and create bitmap
7992 data from it rather than this N copies per piece, but it
7993 only takes a fraction of a second and there is a much
7994 longer delay for loading the pieces. */
7995 for (n = 0; n < pieceDepth; n ++) {
7996 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
7997 0, 0, squareSize, squareSize,
8003 XFreePixmap(xDisplay, buf);
8004 XFreeGC(xDisplay, bufGC);
8005 XFreeGC(xDisplay, maskGC);
8009 InitAnimState (anim, info)
8011 XWindowAttributes * info;
8016 /* Each buffer is square size, same depth as window */
8017 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8018 squareSize, squareSize, info->depth);
8019 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8020 squareSize, squareSize, info->depth);
8022 /* Create a plain GC for blitting */
8023 mask = GCForeground | GCBackground | GCFunction |
8024 GCPlaneMask | GCGraphicsExposures;
8025 values.foreground = XBlackPixel(xDisplay, xScreen);
8026 values.background = XWhitePixel(xDisplay, xScreen);
8027 values.function = GXcopy;
8028 values.plane_mask = AllPlanes;
8029 values.graphics_exposures = False;
8030 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8032 /* Piece will be copied from an existing context at
8033 the start of each new animation/drag. */
8034 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8036 /* Outline will be a read-only copy of an existing */
8037 anim->outlineGC = None;
8043 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8044 XWindowAttributes info;
8046 if (xpmDone && gameInfo.variant == old) return;
8047 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8048 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8050 InitAnimState(&game, &info);
8051 InitAnimState(&player, &info);
8053 /* For XPM pieces, we need bitmaps to use as masks. */
8055 CreateAnimMasks(info.depth);
8061 static Boolean frameWaiting;
8063 static RETSIGTYPE FrameAlarm (sig)
8066 frameWaiting = False;
8067 /* In case System-V style signals. Needed?? */
8068 signal(SIGALRM, FrameAlarm);
8075 struct itimerval delay;
8077 XSync(xDisplay, False);
8080 frameWaiting = True;
8081 signal(SIGALRM, FrameAlarm);
8082 delay.it_interval.tv_sec =
8083 delay.it_value.tv_sec = time / 1000;
8084 delay.it_interval.tv_usec =
8085 delay.it_value.tv_usec = (time % 1000) * 1000;
8086 setitimer(ITIMER_REAL, &delay, NULL);
8087 while (frameWaiting) pause();
8088 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8089 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8090 setitimer(ITIMER_REAL, &delay, NULL);
8100 XSync(xDisplay, False);
8102 usleep(time * 1000);
8107 /* Convert board position to corner of screen rect and color */
8110 ScreenSquare(column, row, pt, color)
8111 int column; int row; XPoint * pt; int * color;
8114 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8115 pt->y = lineGap + row * (squareSize + lineGap);
8117 pt->x = lineGap + column * (squareSize + lineGap);
8118 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8120 *color = SquareColor(row, column);
8123 /* Convert window coords to square */
8126 BoardSquare(x, y, column, row)
8127 int x; int y; int * column; int * row;
8129 *column = EventToSquare(x, BOARD_WIDTH);
8130 if (flipView && *column >= 0)
8131 *column = BOARD_WIDTH - 1 - *column;
8132 *row = EventToSquare(y, BOARD_HEIGHT);
8133 if (!flipView && *row >= 0)
8134 *row = BOARD_HEIGHT - 1 - *row;
8139 #undef Max /* just in case */
8141 #define Max(a, b) ((a) > (b) ? (a) : (b))
8142 #define Min(a, b) ((a) < (b) ? (a) : (b))
8145 SetRect(rect, x, y, width, height)
8146 XRectangle * rect; int x; int y; int width; int height;
8150 rect->width = width;
8151 rect->height = height;
8154 /* Test if two frames overlap. If they do, return
8155 intersection rect within old and location of
8156 that rect within new. */
8159 Intersect(old, new, size, area, pt)
8160 XPoint * old; XPoint * new;
8161 int size; XRectangle * area; XPoint * pt;
8163 if (old->x > new->x + size || new->x > old->x + size ||
8164 old->y > new->y + size || new->y > old->y + size) {
8167 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8168 size - abs(old->x - new->x), size - abs(old->y - new->y));
8169 pt->x = Max(old->x - new->x, 0);
8170 pt->y = Max(old->y - new->y, 0);
8175 /* For two overlapping frames, return the rect(s)
8176 in the old that do not intersect with the new. */
8179 CalcUpdateRects(old, new, size, update, nUpdates)
8180 XPoint * old; XPoint * new; int size;
8181 XRectangle update[]; int * nUpdates;
8185 /* If old = new (shouldn't happen) then nothing to draw */
8186 if (old->x == new->x && old->y == new->y) {
8190 /* Work out what bits overlap. Since we know the rects
8191 are the same size we don't need a full intersect calc. */
8193 /* Top or bottom edge? */
8194 if (new->y > old->y) {
8195 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8197 } else if (old->y > new->y) {
8198 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8199 size, old->y - new->y);
8202 /* Left or right edge - don't overlap any update calculated above. */
8203 if (new->x > old->x) {
8204 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8205 new->x - old->x, size - abs(new->y - old->y));
8207 } else if (old->x > new->x) {
8208 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8209 old->x - new->x, size - abs(new->y - old->y));
8216 /* Generate a series of frame coords from start->mid->finish.
8217 The movement rate doubles until the half way point is
8218 reached, then halves back down to the final destination,
8219 which gives a nice slow in/out effect. The algorithmn
8220 may seem to generate too many intermediates for short
8221 moves, but remember that the purpose is to attract the
8222 viewers attention to the piece about to be moved and
8223 then to where it ends up. Too few frames would be less
8227 Tween(start, mid, finish, factor, frames, nFrames)
8228 XPoint * start; XPoint * mid;
8229 XPoint * finish; int factor;
8230 XPoint frames[]; int * nFrames;
8232 int fraction, n, count;
8236 /* Slow in, stepping 1/16th, then 1/8th, ... */
8238 for (n = 0; n < factor; n++)
8240 for (n = 0; n < factor; n++) {
8241 frames[count].x = start->x + (mid->x - start->x) / fraction;
8242 frames[count].y = start->y + (mid->y - start->y) / fraction;
8244 fraction = fraction / 2;
8248 frames[count] = *mid;
8251 /* Slow out, stepping 1/2, then 1/4, ... */
8253 for (n = 0; n < factor; n++) {
8254 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8255 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8257 fraction = fraction * 2;
8262 /* Draw a piece on the screen without disturbing what's there */
8265 SelectGCMask(piece, clip, outline, mask)
8266 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8270 /* Bitmap for piece being moved. */
8271 if (appData.monoMode) {
8272 *mask = *pieceToSolid(piece);
8273 } else if (useImages) {
8275 *mask = xpmMask[piece];
8277 *mask = ximMaskPm[piece];
8280 *mask = *pieceToSolid(piece);
8283 /* GC for piece being moved. Square color doesn't matter, but
8284 since it gets modified we make a copy of the original. */
8286 if (appData.monoMode)
8291 if (appData.monoMode)
8296 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8298 /* Outline only used in mono mode and is not modified */
8300 *outline = bwPieceGC;
8302 *outline = wbPieceGC;
8306 OverlayPiece(piece, clip, outline, dest)
8307 ChessSquare piece; GC clip; GC outline; Drawable dest;
8312 /* Draw solid rectangle which will be clipped to shape of piece */
8313 XFillRectangle(xDisplay, dest, clip,
8314 0, 0, squareSize, squareSize);
8315 if (appData.monoMode)
8316 /* Also draw outline in contrasting color for black
8317 on black / white on white cases */
8318 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8319 0, 0, squareSize, squareSize, 0, 0, 1);
8321 /* Copy the piece */
8326 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8328 0, 0, squareSize, squareSize,
8333 /* Animate the movement of a single piece */
8336 BeginAnimation(anim, piece, startColor, start)
8344 /* The old buffer is initialised with the start square (empty) */
8345 BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8346 anim->prevFrame = *start;
8348 /* The piece will be drawn using its own bitmap as a matte */
8349 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8350 XSetClipMask(xDisplay, anim->pieceGC, mask);
8354 AnimationFrame(anim, frame, piece)
8359 XRectangle updates[4];
8364 /* Save what we are about to draw into the new buffer */
8365 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8366 frame->x, frame->y, squareSize, squareSize,
8369 /* Erase bits of the previous frame */
8370 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8371 /* Where the new frame overlapped the previous,
8372 the contents in newBuf are wrong. */
8373 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8374 overlap.x, overlap.y,
8375 overlap.width, overlap.height,
8377 /* Repaint the areas in the old that don't overlap new */
8378 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8379 for (i = 0; i < count; i++)
8380 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8381 updates[i].x - anim->prevFrame.x,
8382 updates[i].y - anim->prevFrame.y,
8383 updates[i].width, updates[i].height,
8384 updates[i].x, updates[i].y);
8386 /* Easy when no overlap */
8387 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8388 0, 0, squareSize, squareSize,
8389 anim->prevFrame.x, anim->prevFrame.y);
8392 /* Save this frame for next time round */
8393 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8394 0, 0, squareSize, squareSize,
8396 anim->prevFrame = *frame;
8398 /* Draw piece over original screen contents, not current,
8399 and copy entire rect. Wipes out overlapping piece images. */
8400 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8401 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8402 0, 0, squareSize, squareSize,
8403 frame->x, frame->y);
8407 EndAnimation (anim, finish)
8411 XRectangle updates[4];
8416 /* The main code will redraw the final square, so we
8417 only need to erase the bits that don't overlap. */
8418 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8419 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8420 for (i = 0; i < count; i++)
8421 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8422 updates[i].x - anim->prevFrame.x,
8423 updates[i].y - anim->prevFrame.y,
8424 updates[i].width, updates[i].height,
8425 updates[i].x, updates[i].y);
8427 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8428 0, 0, squareSize, squareSize,
8429 anim->prevFrame.x, anim->prevFrame.y);
8434 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8436 ChessSquare piece; int startColor;
8437 XPoint * start; XPoint * finish;
8438 XPoint frames[]; int nFrames;
8442 BeginAnimation(anim, piece, startColor, start);
8443 for (n = 0; n < nFrames; n++) {
8444 AnimationFrame(anim, &(frames[n]), piece);
8445 FrameDelay(appData.animSpeed);
8447 EndAnimation(anim, finish);
8450 /* Main control logic for deciding what to animate and how */
8453 AnimateMove(board, fromX, fromY, toX, toY)
8462 XPoint start, finish, mid;
8463 XPoint frames[kFactor * 2 + 1];
8464 int nFrames, startColor, endColor;
8466 /* Are we animating? */
8467 if (!appData.animate || appData.blindfold)
8470 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8471 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8472 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8474 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8475 piece = board[fromY][fromX];
8476 if (piece >= EmptySquare) return;
8481 hop = (piece == WhiteKnight || piece == BlackKnight);
8484 if (appData.debugMode) {
8485 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8486 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8487 piece, fromX, fromY, toX, toY); }
8489 ScreenSquare(fromX, fromY, &start, &startColor);
8490 ScreenSquare(toX, toY, &finish, &endColor);
8493 /* Knight: make diagonal movement then straight */
8494 if (abs(toY - fromY) < abs(toX - fromX)) {
8495 mid.x = start.x + (finish.x - start.x) / 2;
8499 mid.y = start.y + (finish.y - start.y) / 2;
8502 mid.x = start.x + (finish.x - start.x) / 2;
8503 mid.y = start.y + (finish.y - start.y) / 2;
8506 /* Don't use as many frames for very short moves */
8507 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8508 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8510 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8511 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8513 /* Be sure end square is redrawn */
8514 damage[toY][toX] = True;
8518 DragPieceBegin(x, y)
8521 int boardX, boardY, color;
8524 /* Are we animating? */
8525 if (!appData.animateDragging || appData.blindfold)
8528 /* Figure out which square we start in and the
8529 mouse position relative to top left corner. */
8530 BoardSquare(x, y, &boardX, &boardY);
8531 player.startBoardX = boardX;
8532 player.startBoardY = boardY;
8533 ScreenSquare(boardX, boardY, &corner, &color);
8534 player.startSquare = corner;
8535 player.startColor = color;
8536 /* As soon as we start dragging, the piece will jump slightly to
8537 be centered over the mouse pointer. */
8538 player.mouseDelta.x = squareSize/2;
8539 player.mouseDelta.y = squareSize/2;
8540 /* Initialise animation */
8541 player.dragPiece = PieceForSquare(boardX, boardY);
8543 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8544 player.dragActive = True;
8545 BeginAnimation(&player, player.dragPiece, color, &corner);
8546 /* Mark this square as needing to be redrawn. Note that
8547 we don't remove the piece though, since logically (ie
8548 as seen by opponent) the move hasn't been made yet. */
8549 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8550 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8551 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8552 corner.x, corner.y, squareSize, squareSize,
8553 0, 0); // [HGM] zh: unstack in stead of grab
8554 damage[boardY][boardX] = True;
8556 player.dragActive = False;
8566 /* Are we animating? */
8567 if (!appData.animateDragging || appData.blindfold)
8571 if (! player.dragActive)
8573 /* Move piece, maintaining same relative position
8574 of mouse within square */
8575 corner.x = x - player.mouseDelta.x;
8576 corner.y = y - player.mouseDelta.y;
8577 AnimationFrame(&player, &corner, player.dragPiece);
8579 if (appData.highlightDragging) {
8581 BoardSquare(x, y, &boardX, &boardY);
8582 SetHighlights(fromX, fromY, boardX, boardY);
8591 int boardX, boardY, color;
8594 /* Are we animating? */
8595 if (!appData.animateDragging || appData.blindfold)
8599 if (! player.dragActive)
8601 /* Last frame in sequence is square piece is
8602 placed on, which may not match mouse exactly. */
8603 BoardSquare(x, y, &boardX, &boardY);
8604 ScreenSquare(boardX, boardY, &corner, &color);
8605 EndAnimation(&player, &corner);
8607 /* Be sure end square is redrawn */
8608 damage[boardY][boardX] = True;
8610 /* This prevents weird things happening with fast successive
8611 clicks which on my Sun at least can cause motion events
8612 without corresponding press/release. */
8613 player.dragActive = False;
8616 /* Handle expose event while piece being dragged */
8621 if (!player.dragActive || appData.blindfold)
8624 /* What we're doing: logically, the move hasn't been made yet,
8625 so the piece is still in it's original square. But visually
8626 it's being dragged around the board. So we erase the square
8627 that the piece is on and draw it at the last known drag point. */
8628 BlankSquare(player.startSquare.x, player.startSquare.y,
8629 player.startColor, EmptySquare, xBoardWindow);
8630 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8631 damage[player.startBoardY][player.startBoardX] = TRUE;
8634 #include <sys/ioctl.h>
8635 int get_term_width()
8637 int fd, default_width;
8640 default_width = 79; // this is FICS default anyway...
8642 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8644 if (!ioctl(fd, TIOCGSIZE, &win))
8645 default_width = win.ts_cols;
8646 #elif defined(TIOCGWINSZ)
8648 if (!ioctl(fd, TIOCGWINSZ, &win))
8649 default_width = win.ws_col;
8651 return default_width;
8654 void update_ics_width()
8656 static int old_width = 0;
8657 int new_width = get_term_width();
8659 if (old_width != new_width)
8660 ics_printf("set width %d\n", new_width);
8661 old_width = new_width;
8664 void NotifyFrontendLogin()