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));
210 #define usleep(t) _sleep2(((t)+500)/1000)
214 # define _(s) gettext (s)
215 # define N_(s) gettext_noop (s)
231 int main P((int argc, char **argv));
232 RETSIGTYPE CmailSigHandler P((int sig));
233 RETSIGTYPE IntSigHandler P((int sig));
234 RETSIGTYPE TermSizeSigHandler P((int sig));
235 void CreateGCs P((void));
236 void CreateXIMPieces P((void));
237 void CreateXPMPieces P((void));
238 void CreatePieces P((void));
239 void CreatePieceMenus P((void));
240 Widget CreateMenuBar P((Menu *mb));
241 Widget CreateButtonBar P ((MenuItem *mi));
242 char *FindFont P((char *pattern, int targetPxlSize));
243 void PieceMenuPopup P((Widget w, XEvent *event,
244 String *params, Cardinal *num_params));
245 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
246 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
247 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
248 u_int wreq, u_int hreq));
249 void CreateGrid P((void));
250 int EventToSquare P((int x, int limit));
251 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
252 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
253 void HandleUserMove P((Widget w, XEvent *event,
254 String *prms, Cardinal *nprms));
255 void AnimateUserMove P((Widget w, XEvent * event,
256 String * params, Cardinal * nParams));
257 void WhiteClock P((Widget w, XEvent *event,
258 String *prms, Cardinal *nprms));
259 void BlackClock P((Widget w, XEvent *event,
260 String *prms, Cardinal *nprms));
261 void DrawPositionProc P((Widget w, XEvent *event,
262 String *prms, Cardinal *nprms));
263 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
265 void CommentPopUp P((char *title, char *label));
266 void CommentPopDown P((void));
267 void CommentCallback P((Widget w, XtPointer client_data,
268 XtPointer call_data));
269 void ICSInputBoxPopUp P((void));
270 void ICSInputBoxPopDown P((void));
271 void FileNamePopUp P((char *label, char *def,
272 FileProc proc, char *openMode));
273 void FileNamePopDown P((void));
274 void FileNameCallback P((Widget w, XtPointer client_data,
275 XtPointer call_data));
276 void FileNameAction P((Widget w, XEvent *event,
277 String *prms, Cardinal *nprms));
278 void AskQuestionReplyAction P((Widget w, XEvent *event,
279 String *prms, Cardinal *nprms));
280 void AskQuestionProc P((Widget w, XEvent *event,
281 String *prms, Cardinal *nprms));
282 void AskQuestionPopDown P((void));
283 void PromotionPopDown P((void));
284 void PromotionCallback P((Widget w, XtPointer client_data,
285 XtPointer call_data));
286 void EditCommentPopDown P((void));
287 void EditCommentCallback P((Widget w, XtPointer client_data,
288 XtPointer call_data));
289 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
290 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
291 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
292 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
294 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
296 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
298 void LoadPositionProc P((Widget w, XEvent *event,
299 String *prms, Cardinal *nprms));
300 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
302 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
304 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
306 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
308 void PastePositionProc P((Widget w, XEvent *event, String *prms,
310 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
311 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
312 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
313 void SavePositionProc P((Widget w, XEvent *event,
314 String *prms, Cardinal *nprms));
315 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
316 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
318 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
319 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
320 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
322 void MachineWhiteProc P((Widget w, XEvent *event,
323 String *prms, Cardinal *nprms));
324 void AnalyzeModeProc P((Widget w, XEvent *event,
325 String *prms, Cardinal *nprms));
326 void AnalyzeFileProc P((Widget w, XEvent *event,
327 String *prms, Cardinal *nprms));
328 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
330 void IcsClientProc P((Widget w, XEvent *event, String *prms,
332 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
333 void EditPositionProc P((Widget w, XEvent *event,
334 String *prms, Cardinal *nprms));
335 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
336 void EditCommentProc P((Widget w, XEvent *event,
337 String *prms, Cardinal *nprms));
338 void IcsInputBoxProc P((Widget w, XEvent *event,
339 String *prms, Cardinal *nprms));
340 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
341 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
342 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
343 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
344 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
345 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
346 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
347 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
348 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
349 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
350 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
351 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
352 void StopObservingProc P((Widget w, XEvent *event, String *prms,
354 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
356 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
357 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
358 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
363 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
365 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
368 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
370 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
372 void AutocommProc P((Widget w, XEvent *event, String *prms,
374 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
375 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
376 void AutobsProc P((Widget w, XEvent *event, String *prms,
378 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
379 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
380 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
383 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
384 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
386 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
388 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
390 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
391 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
392 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
394 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
396 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
398 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
400 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
402 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
403 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
404 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
406 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
408 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
410 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
412 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
413 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
414 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
415 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
416 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
417 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
418 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
419 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
420 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
421 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
422 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
423 void DisplayMove P((int moveNumber));
424 void DisplayTitle P((char *title));
425 void ICSInitScript P((void));
426 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
427 void ErrorPopUp P((char *title, char *text, int modal));
428 void ErrorPopDown P((void));
429 static char *ExpandPathName P((char *path));
430 static void CreateAnimVars P((void));
431 static void DragPieceMove P((int x, int y));
432 static void DrawDragPiece P((void));
433 char *ModeToWidgetName P((GameMode mode));
434 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
435 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
436 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void ShufflePopDown P(());
442 void EnginePopDown P(());
443 void UciPopDown P(());
444 void TimeControlPopDown P(());
445 void NewVariantPopDown P(());
446 void SettingsPopDown P(());
447 void update_ics_width P(());
448 int get_term_width P(());
450 * XBoard depends on Xt R4 or higher
452 int xtVersion = XtSpecificationRelease;
457 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
458 jailSquareColor, highlightSquareColor, premoveHighlightColor;
459 Pixel lowTimeWarningColor;
460 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
461 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
462 wjPieceGC, bjPieceGC, prelineGC, countGC;
463 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
464 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
465 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
466 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
467 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
468 ICSInputShell, fileNameShell, askQuestionShell;
469 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
470 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
471 Font clockFontID, coordFontID, countFontID;
472 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
473 XtAppContext appContext;
475 char *oldICSInteractionTitle;
479 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
481 Position commentX = -1, commentY = -1;
482 Dimension commentW, commentH;
483 typedef unsigned int BoardSize;
485 Boolean chessProgram;
487 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
488 int squareSize, smallLayout = 0, tinyLayout = 0,
489 marginW, marginH, // [HGM] for run-time resizing
490 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
491 ICSInputBoxUp = False, askQuestionUp = False,
492 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
493 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
494 Pixel timerForegroundPixel, timerBackgroundPixel;
495 Pixel buttonForegroundPixel, buttonBackgroundPixel;
496 char *chessDir, *programName, *programVersion,
497 *gameCopyFilename, *gamePasteFilename;
498 Boolean alwaysOnTop = False;
499 Boolean saveSettingsOnExit;
500 char *settingsFileName;
501 char *icsTextMenuString;
503 char *firstChessProgramNames;
504 char *secondChessProgramNames;
506 WindowPlacement wpMain;
507 WindowPlacement wpConsole;
508 WindowPlacement wpComment;
509 WindowPlacement wpMoveHistory;
510 WindowPlacement wpEvalGraph;
511 WindowPlacement wpEngineOutput;
512 WindowPlacement wpGameList;
513 WindowPlacement wpTags;
517 Pixmap pieceBitmap[2][(int)BlackPawn];
518 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
519 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
520 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
521 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
522 int useImages, useImageSqs;
523 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
524 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
525 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
526 XImage *ximLightSquare, *ximDarkSquare;
529 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
530 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
532 #define White(piece) ((int)(piece) < (int)BlackPawn)
534 /* Variables for doing smooth animation. This whole thing
535 would be much easier if the board was double-buffered,
536 but that would require a fairly major rewrite. */
541 GC blitGC, pieceGC, outlineGC;
542 XPoint startSquare, prevFrame, mouseDelta;
546 int startBoardX, startBoardY;
549 /* There can be two pieces being animated at once: a player
550 can begin dragging a piece before the remote opponent has moved. */
552 static AnimState game, player;
554 /* Bitmaps for use as masks when drawing XPM pieces.
555 Need one for each black and white piece. */
556 static Pixmap xpmMask[BlackKing + 1];
558 /* This magic number is the number of intermediate frames used
559 in each half of the animation. For short moves it's reduced
560 by 1. The total number of frames will be factor * 2 + 1. */
563 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
565 MenuItem fileMenu[] = {
566 {N_("New Game"), ResetProc},
567 {N_("New Shuffle Game ..."), ShuffleMenuProc},
568 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
569 {"----", NothingProc},
570 {N_("Load Game"), LoadGameProc},
571 {N_("Load Next Game"), LoadNextGameProc},
572 {N_("Load Previous Game"), LoadPrevGameProc},
573 {N_("Reload Same Game"), ReloadGameProc},
574 {N_("Save Game"), SaveGameProc},
575 {"----", NothingProc},
576 {N_("Copy Game"), CopyGameProc},
577 {N_("Paste Game"), PasteGameProc},
578 {"----", NothingProc},
579 {N_("Load Position"), LoadPositionProc},
580 {N_("Load Next Position"), LoadNextPositionProc},
581 {N_("Load Previous Position"), LoadPrevPositionProc},
582 {N_("Reload Same Position"), ReloadPositionProc},
583 {N_("Save Position"), SavePositionProc},
584 {"----", NothingProc},
585 {N_("Copy Position"), CopyPositionProc},
586 {N_("Paste Position"), PastePositionProc},
587 {"----", NothingProc},
588 {N_("Mail Move"), MailMoveProc},
589 {N_("Reload CMail Message"), ReloadCmailMsgProc},
590 {"----", NothingProc},
591 {N_("Exit"), QuitProc},
595 MenuItem modeMenu[] = {
596 {N_("Machine White"), MachineWhiteProc},
597 {N_("Machine Black"), MachineBlackProc},
598 {N_("Two Machines"), TwoMachinesProc},
599 {N_("Analysis Mode"), AnalyzeModeProc},
600 {N_("Analyze File"), AnalyzeFileProc },
601 {N_("ICS Client"), IcsClientProc},
602 {N_("Edit Game"), EditGameProc},
603 {N_("Edit Position"), EditPositionProc},
604 {N_("Training"), TrainingProc},
605 {"----", NothingProc},
606 {N_("Show Engine Output"), EngineOutputProc},
607 {N_("Show Evaluation Graph"), NothingProc}, // [HGM] evalgr: not functional yet
608 {N_("Show Game List"), ShowGameListProc},
609 {"Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
610 {"----", NothingProc},
611 {N_("Edit Tags"), EditTagsProc},
612 {N_("Edit Comment"), EditCommentProc},
613 {N_("ICS Input Box"), IcsInputBoxProc},
614 {N_("Pause"), PauseProc},
618 MenuItem actionMenu[] = {
619 {N_("Accept"), AcceptProc},
620 {N_("Decline"), DeclineProc},
621 {N_("Rematch"), RematchProc},
622 {"----", NothingProc},
623 {N_("Call Flag"), CallFlagProc},
624 {N_("Draw"), DrawProc},
625 {N_("Adjourn"), AdjournProc},
626 {N_("Abort"), AbortProc},
627 {N_("Resign"), ResignProc},
628 {"----", NothingProc},
629 {N_("Stop Observing"), StopObservingProc},
630 {N_("Stop Examining"), StopExaminingProc},
631 {"----", NothingProc},
632 {N_("Adjudicate to White"), AdjuWhiteProc},
633 {N_("Adjudicate to Black"), AdjuBlackProc},
634 {N_("Adjudicate Draw"), AdjuDrawProc},
638 MenuItem stepMenu[] = {
639 {N_("Backward"), BackwardProc},
640 {N_("Forward"), ForwardProc},
641 {N_("Back to Start"), ToStartProc},
642 {N_("Forward to End"), ToEndProc},
643 {N_("Revert"), RevertProc},
644 {N_("Truncate Game"), TruncateGameProc},
645 {"----", NothingProc},
646 {N_("Move Now"), MoveNowProc},
647 {N_("Retract Move"), RetractMoveProc},
651 MenuItem optionsMenu[] = {
652 {N_("Flip View"), FlipViewProc},
653 {"----", NothingProc},
654 {N_("Adjudications ..."), EngineMenuProc},
655 {N_("General Settings ..."), UciMenuProc},
656 {N_("Engine #1 Settings ..."), FirstSettingsProc},
657 {N_("Engine #2 Settings ..."), SecondSettingsProc},
658 {N_("Time Control ..."), TimeControlProc},
659 {"----", NothingProc},
660 {N_("Always Queen"), AlwaysQueenProc},
661 {N_("Animate Dragging"), AnimateDraggingProc},
662 {N_("Animate Moving"), AnimateMovingProc},
663 {N_("Auto Comment"), AutocommProc},
664 {N_("Auto Flag"), AutoflagProc},
665 {N_("Auto Flip View"), AutoflipProc},
666 {N_("Auto Observe"), AutobsProc},
667 {N_("Auto Raise Board"), AutoraiseProc},
668 {N_("Auto Save"), AutosaveProc},
669 {N_("Blindfold"), BlindfoldProc},
670 {N_("Flash Moves"), FlashMovesProc},
671 {N_("Get Move List"), GetMoveListProc},
673 {N_("Highlight Dragging"), HighlightDraggingProc},
675 {N_("Highlight Last Move"), HighlightLastMoveProc},
676 {N_("Move Sound"), MoveSoundProc},
677 {N_("ICS Alarm"), IcsAlarmProc},
678 {N_("Old Save Style"), OldSaveStyleProc},
679 {N_("Periodic Updates"), PeriodicUpdatesProc},
680 {N_("Ponder Next Move"), PonderNextMoveProc},
681 {N_("Popup Exit Message"), PopupExitMessageProc},
682 {N_("Popup Move Errors"), PopupMoveErrorsProc},
683 {N_("Premove"), PremoveProc},
684 {N_("Quiet Play"), QuietPlayProc},
685 {N_("Show Coords"), ShowCoordsProc},
686 {N_("Hide Thinking"), HideThinkingProc},
687 {N_("Test Legality"), TestLegalityProc},
688 {"----", NothingProc},
689 {N_("Save Settings Now"), SaveSettingsProc},
690 {N_("Save Settings on Exit"), SaveOnExitProc},
694 MenuItem helpMenu[] = {
695 {N_("Info XBoard"), InfoProc},
696 {N_("Man XBoard"), ManProc},
697 {"----", NothingProc},
698 {N_("Hint"), HintProc},
699 {N_("Book"), BookProc},
700 {"----", NothingProc},
701 {N_("About XBoard"), AboutProc},
706 {N_("File"), fileMenu},
707 {N_("Mode"), modeMenu},
708 {N_("Action"), actionMenu},
709 {N_("Step"), stepMenu},
710 {N_("Options"), optionsMenu},
711 {N_("Help"), helpMenu},
715 #define PAUSE_BUTTON N_("P")
716 MenuItem buttonBar[] = {
719 {PAUSE_BUTTON, PauseProc},
725 #define PIECE_MENU_SIZE 18
726 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
727 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
728 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
729 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
730 N_("Empty square"), N_("Clear board") },
731 { N_("Black"), "----", 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") }
736 /* must be in same order as PieceMenuStrings! */
737 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
738 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
739 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
740 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
741 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
742 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
743 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
744 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
745 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
748 #define DROP_MENU_SIZE 6
749 String dropMenuStrings[DROP_MENU_SIZE] = {
750 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
752 /* must be in same order as PieceMenuStrings! */
753 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
754 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
755 WhiteRook, WhiteQueen
763 DropMenuEnables dmEnables[] = {
781 { XtNborderWidth, 0 },
782 { XtNdefaultDistance, 0 },
786 { XtNborderWidth, 0 },
787 { XtNresizable, (XtArgVal) True },
791 { XtNborderWidth, 0 },
797 { XtNjustify, (XtArgVal) XtJustifyRight },
798 { XtNlabel, (XtArgVal) "..." },
799 { XtNresizable, (XtArgVal) True },
800 { XtNresize, (XtArgVal) False }
803 Arg messageArgs[] = {
804 { XtNjustify, (XtArgVal) XtJustifyLeft },
805 { XtNlabel, (XtArgVal) "..." },
806 { XtNresizable, (XtArgVal) True },
807 { XtNresize, (XtArgVal) False }
811 { XtNborderWidth, 0 },
812 { XtNjustify, (XtArgVal) XtJustifyLeft }
815 XtResource clientResources[] = {
816 { "flashCount", "flashCount", XtRInt, sizeof(int),
817 XtOffset(AppDataPtr, flashCount), XtRImmediate,
818 (XtPointer) FLASH_COUNT },
821 XrmOptionDescRec shellOptions[] = {
822 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
823 { "-flash", "flashCount", XrmoptionNoArg, "3" },
824 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
827 XtActionsRec boardActions[] = {
828 { "DrawPosition", DrawPositionProc },
829 { "HandleUserMove", HandleUserMove },
830 { "AnimateUserMove", AnimateUserMove },
831 { "FileNameAction", FileNameAction },
832 { "AskQuestionProc", AskQuestionProc },
833 { "AskQuestionReplyAction", AskQuestionReplyAction },
834 { "PieceMenuPopup", PieceMenuPopup },
835 { "WhiteClock", WhiteClock },
836 { "BlackClock", BlackClock },
837 { "Iconify", Iconify },
838 { "ResetProc", ResetProc },
839 { "LoadGameProc", LoadGameProc },
840 { "LoadNextGameProc", LoadNextGameProc },
841 { "LoadPrevGameProc", LoadPrevGameProc },
842 { "LoadSelectedProc", LoadSelectedProc },
843 { "ReloadGameProc", ReloadGameProc },
844 { "LoadPositionProc", LoadPositionProc },
845 { "LoadNextPositionProc", LoadNextPositionProc },
846 { "LoadPrevPositionProc", LoadPrevPositionProc },
847 { "ReloadPositionProc", ReloadPositionProc },
848 { "CopyPositionProc", CopyPositionProc },
849 { "PastePositionProc", PastePositionProc },
850 { "CopyGameProc", CopyGameProc },
851 { "PasteGameProc", PasteGameProc },
852 { "SaveGameProc", SaveGameProc },
853 { "SavePositionProc", SavePositionProc },
854 { "MailMoveProc", MailMoveProc },
855 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
856 { "QuitProc", QuitProc },
857 { "MachineWhiteProc", MachineWhiteProc },
858 { "MachineBlackProc", MachineBlackProc },
859 { "AnalysisModeProc", AnalyzeModeProc },
860 { "AnalyzeFileProc", AnalyzeFileProc },
861 { "TwoMachinesProc", TwoMachinesProc },
862 { "IcsClientProc", IcsClientProc },
863 { "EditGameProc", EditGameProc },
864 { "EditPositionProc", EditPositionProc },
865 { "TrainingProc", EditPositionProc },
866 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
867 { "ShowGameListProc", ShowGameListProc },
868 { "ShowMoveListProc", HistoryShowProc},
869 { "EditTagsProc", EditCommentProc },
870 { "EditCommentProc", EditCommentProc },
871 { "IcsAlarmProc", IcsAlarmProc },
872 { "IcsInputBoxProc", IcsInputBoxProc },
873 { "PauseProc", PauseProc },
874 { "AcceptProc", AcceptProc },
875 { "DeclineProc", DeclineProc },
876 { "RematchProc", RematchProc },
877 { "CallFlagProc", CallFlagProc },
878 { "DrawProc", DrawProc },
879 { "AdjournProc", AdjournProc },
880 { "AbortProc", AbortProc },
881 { "ResignProc", ResignProc },
882 { "AdjuWhiteProc", AdjuWhiteProc },
883 { "AdjuBlackProc", AdjuBlackProc },
884 { "AdjuDrawProc", AdjuDrawProc },
885 { "EnterKeyProc", EnterKeyProc },
886 { "StopObservingProc", StopObservingProc },
887 { "StopExaminingProc", StopExaminingProc },
888 { "BackwardProc", BackwardProc },
889 { "ForwardProc", ForwardProc },
890 { "ToStartProc", ToStartProc },
891 { "ToEndProc", ToEndProc },
892 { "RevertProc", RevertProc },
893 { "TruncateGameProc", TruncateGameProc },
894 { "MoveNowProc", MoveNowProc },
895 { "RetractMoveProc", RetractMoveProc },
896 { "AlwaysQueenProc", AlwaysQueenProc },
897 { "AnimateDraggingProc", AnimateDraggingProc },
898 { "AnimateMovingProc", AnimateMovingProc },
899 { "AutoflagProc", AutoflagProc },
900 { "AutoflipProc", AutoflipProc },
901 { "AutobsProc", AutobsProc },
902 { "AutoraiseProc", AutoraiseProc },
903 { "AutosaveProc", AutosaveProc },
904 { "BlindfoldProc", BlindfoldProc },
905 { "FlashMovesProc", FlashMovesProc },
906 { "FlipViewProc", FlipViewProc },
907 { "GetMoveListProc", GetMoveListProc },
909 { "HighlightDraggingProc", HighlightDraggingProc },
911 { "HighlightLastMoveProc", HighlightLastMoveProc },
912 { "IcsAlarmProc", IcsAlarmProc },
913 { "MoveSoundProc", MoveSoundProc },
914 { "OldSaveStyleProc", OldSaveStyleProc },
915 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
916 { "PonderNextMoveProc", PonderNextMoveProc },
917 { "PopupExitMessageProc", PopupExitMessageProc },
918 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
919 { "PremoveProc", PremoveProc },
920 { "QuietPlayProc", QuietPlayProc },
921 { "ShowCoordsProc", ShowCoordsProc },
922 { "ShowThinkingProc", ShowThinkingProc },
923 { "HideThinkingProc", HideThinkingProc },
924 { "TestLegalityProc", TestLegalityProc },
925 { "SaveSettingsProc", SaveSettingsProc },
926 { "SaveOnExitProc", SaveOnExitProc },
927 { "InfoProc", InfoProc },
928 { "ManProc", ManProc },
929 { "HintProc", HintProc },
930 { "BookProc", BookProc },
931 { "AboutGameProc", AboutGameProc },
932 { "AboutProc", AboutProc },
933 { "DebugProc", DebugProc },
934 { "NothingProc", NothingProc },
935 { "CommentPopDown", (XtActionProc) CommentPopDown },
936 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
937 { "TagsPopDown", (XtActionProc) TagsPopDown },
938 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
939 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
940 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
941 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
942 { "GameListPopDown", (XtActionProc) GameListPopDown },
943 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
944 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
945 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
946 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
947 { "EnginePopDown", (XtActionProc) EnginePopDown },
948 { "UciPopDown", (XtActionProc) UciPopDown },
949 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
950 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
951 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
954 char globalTranslations[] =
955 ":<Key>R: ResignProc() \n \
956 :<Key>r: ResetProc() \n \
957 :<Key>g: LoadGameProc() \n \
958 :<Key>N: LoadNextGameProc() \n \
959 :<Key>P: LoadPrevGameProc() \n \
960 :<Key>Q: QuitProc() \n \
961 :<Key>F: ToEndProc() \n \
962 :<Key>f: ForwardProc() \n \
963 :<Key>B: ToStartProc() \n \
964 :<Key>b: BackwardProc() \n \
965 :<Key>p: PauseProc() \n \
966 :<Key>d: DrawProc() \n \
967 :<Key>t: CallFlagProc() \n \
968 :<Key>i: Iconify() \n \
969 :<Key>c: Iconify() \n \
970 :<Key>v: FlipViewProc() \n \
971 <KeyDown>Control_L: BackwardProc() \n \
972 <KeyUp>Control_L: ForwardProc() \n \
973 <KeyDown>Control_R: BackwardProc() \n \
974 <KeyUp>Control_R: ForwardProc() \n \
975 Shift<Key>1: AskQuestionProc(\"Direct command\",\
976 \"Send to chess program:\",,1) \n \
977 Shift<Key>2: AskQuestionProc(\"Direct command\",\
978 \"Send to second chess program:\",,2) \n";
980 char boardTranslations[] =
981 "<Btn1Down>: HandleUserMove() \n \
982 <Btn1Up>: HandleUserMove() \n \
983 <Btn1Motion>: AnimateUserMove() \n \
984 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
985 PieceMenuPopup(menuB) \n \
986 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
987 PieceMenuPopup(menuW) \n \
988 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
989 PieceMenuPopup(menuW) \n \
990 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
991 PieceMenuPopup(menuB) \n";
993 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
994 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
996 char ICSInputTranslations[] =
997 "<Key>Return: EnterKeyProc() \n";
999 String xboardResources[] = {
1000 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1001 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1002 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1007 /* Max possible square size */
1008 #define MAXSQSIZE 256
1010 static int xpm_avail[MAXSQSIZE];
1012 #ifdef HAVE_DIR_STRUCT
1014 /* Extract piece size from filename */
1016 xpm_getsize(name, len, ext)
1027 if ((p=strchr(name, '.')) == NULL ||
1028 StrCaseCmp(p+1, ext) != 0)
1034 while (*p && isdigit(*p))
1041 /* Setup xpm_avail */
1043 xpm_getavail(dirname, ext)
1051 for (i=0; i<MAXSQSIZE; ++i)
1054 if (appData.debugMode)
1055 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1057 dir = opendir(dirname);
1060 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1061 programName, dirname);
1065 while ((ent=readdir(dir)) != NULL) {
1066 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1067 if (i > 0 && i < MAXSQSIZE)
1077 xpm_print_avail(fp, ext)
1083 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1084 for (i=1; i<MAXSQSIZE; ++i) {
1090 /* Return XPM piecesize closest to size */
1092 xpm_closest_to(dirname, size, ext)
1098 int sm_diff = MAXSQSIZE;
1102 xpm_getavail(dirname, ext);
1104 if (appData.debugMode)
1105 xpm_print_avail(stderr, ext);
1107 for (i=1; i<MAXSQSIZE; ++i) {
1110 diff = (diff<0) ? -diff : diff;
1111 if (diff < sm_diff) {
1119 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1125 #else /* !HAVE_DIR_STRUCT */
1126 /* If we are on a system without a DIR struct, we can't
1127 read the directory, so we can't collect a list of
1128 filenames, etc., so we can't do any size-fitting. */
1130 xpm_closest_to(dirname, size, ext)
1135 fprintf(stderr, _("\
1136 Warning: No DIR structure found on this system --\n\
1137 Unable to autosize for XPM/XIM pieces.\n\
1138 Please report this error to frankm@hiwaay.net.\n\
1139 Include system type & operating system in message.\n"));
1142 #endif /* HAVE_DIR_STRUCT */
1144 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1145 "magenta", "cyan", "white" };
1149 TextColors textColors[(int)NColorClasses];
1151 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1153 parse_color(str, which)
1157 char *p, buf[100], *d;
1160 if (strlen(str) > 99) /* watch bounds on buf */
1165 for (i=0; i<which; ++i) {
1172 /* Could be looking at something like:
1174 .. in which case we want to stop on a comma also */
1175 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1179 return -1; /* Use default for empty field */
1182 if (which == 2 || isdigit(*p))
1185 while (*p && isalpha(*p))
1190 for (i=0; i<8; ++i) {
1191 if (!StrCaseCmp(buf, cnames[i]))
1192 return which? (i+40) : (i+30);
1194 if (!StrCaseCmp(buf, "default")) return -1;
1196 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1201 parse_cpair(cc, str)
1205 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1206 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1211 /* bg and attr are optional */
1212 textColors[(int)cc].bg = parse_color(str, 1);
1213 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1214 textColors[(int)cc].attr = 0;
1220 /* Arrange to catch delete-window events */
1221 Atom wm_delete_window;
1223 CatchDeleteWindow(Widget w, String procname)
1226 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1227 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1228 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1235 XtSetArg(args[0], XtNiconic, False);
1236 XtSetValues(shellWidget, args, 1);
1238 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1241 //---------------------------------------------------------------------------------------------------------
1242 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1245 #define CW_USEDEFAULT (1<<31)
1246 #define ICS_TEXT_MENU_SIZE 90
1247 #define SetCurrentDirectory chdir
1248 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1250 // these two must some day move to frontend.h, when they are implemented
1251 Boolean EvalGraphIsUp();
1252 Boolean MoveHistoryIsUp();
1254 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1257 // front-end part of option handling
1259 // [HGM] This platform-dependent table provides the location for storing the color info
1262 &appData.whitePieceColor,
1263 &appData.blackPieceColor,
1264 &appData.lightSquareColor,
1265 &appData.darkSquareColor,
1266 &appData.highlightSquareColor,
1267 &appData.premoveHighlightColor,
1280 ParseFont(char *name, int number)
1281 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1283 case 0: // CLOCK_FONT
1284 appData.clockFont = strdup(name);
1286 case 1: // MESSAGE_FONT
1287 appData.font = strdup(name);
1289 case 2: // COORD_FONT
1290 appData.coordFont = strdup(name);
1299 { // only 2 fonts currently
1300 appData.clockFont = CLOCK_FONT_NAME;
1301 appData.coordFont = COORD_FONT_NAME;
1302 appData.font = DEFAULT_FONT_NAME;
1307 { // no-op, until we identify the code for this already in XBoard and move it here
1311 ParseColor(int n, char *name)
1312 { // in XBoard, just copy the color-name string
1313 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1317 ParseTextAttribs(ColorClass cc, char *s)
1319 (&appData.colorShout)[cc] = strdup(s);
1323 ParseBoardSize(void *addr, char *name)
1325 appData.boardSize = strdup(name);
1330 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1334 SetCommPortDefaults()
1335 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1338 // [HGM] args: these three cases taken out to stay in front-end
1340 SaveFontArg(FILE *f, ArgDescriptor *ad)
1343 switch((int)ad->argLoc) {
1344 case 0: // CLOCK_FONT
1345 name = appData.clockFont;
1347 case 1: // MESSAGE_FONT
1348 name = appData.font;
1350 case 2: // COORD_FONT
1351 name = appData.coordFont;
1356 fprintf(f, "/%s=%s\n", ad->argName, name);
1361 { // nothing to do, as the sounds are at all times represented by their text-string names already
1365 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1366 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1367 fprintf(f, "/%s=%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1371 SaveColor(FILE *f, ArgDescriptor *ad)
1372 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1373 if(colorVariable[(int)ad->argLoc])
1374 fprintf(f, "/%s=%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1378 SaveBoardSize(FILE *f, char *name, void *addr)
1379 { // wrapper to shield back-end from BoardSize & sizeInfo
1380 fprintf(f, "/%s=%s\n", name, appData.boardSize);
1384 ParseCommPortSettings(char *s)
1385 { // no such option in XBoard (yet)
1390 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1392 // In XBoard this will have to wait until awareness of window parameters is implemented
1393 GetActualPlacement(hwndMain, &wpMain);
1394 GetActualPlacement(hwndConsole, &wpConsole);
1395 GetActualPlacement(commentDialog, &wpComment);
1396 GetActualPlacement(editTagsDialog, &wpTags);
1397 GetActualPlacement(gameListDialog, &wpGameList);
1398 GetActualPlacement(moveHistoryDialog, &wpMoveHistory);
1399 GetActualPlacement(evalGraphDialog, &wpEvalGraph);
1400 GetActualPlacement(engineOutputDialog, &wpEngineOutput);
1405 PrintCommPortSettings(FILE *f, char *name)
1406 { // This option does not exist in XBoard
1410 MySearchPath(char *installDir, char *name, char *fullname)
1411 { // just append installDir and name. Perhaps ExpandPath should be used here?
1412 name = ExpandPathName(name);
1413 if(name && name[0] == '/') strcpy(fullname, name); else {
1414 sprintf(fullname, "%s%c%s", installDir, '/', name);
1420 MyGetFullPathName(char *name, char *fullname)
1421 { // should use ExpandPath?
1422 name = ExpandPathName(name);
1423 strcpy(fullname, name);
1428 EnsureOnScreen(int *x, int *y, int minX, int minY)
1436 return True; // still have to fix this *****************************************************************************
1447 { // [HGM] args: allows testing if main window is realized from back-end
1448 return xBoardWindow != 0;
1452 PopUpStartupDialog()
1453 { // start menu not implemented in XBoard
1456 ConvertToLine(int argc, char **argv)
1458 static char line[128*1024], buf[1024];
1462 for(i=1; i<argc; i++) {
1463 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1464 && argv[i][0] != '{' )
1465 sprintf(buf, "{%s} ", argv[i]);
1466 else sprintf(buf, "%s ", argv[i]);
1469 line[strlen(line)-1] = NULLCHAR;
1473 //--------------------------------------------------------------------------------------------
1476 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1478 #define BoardSize int
1479 void InitDrawingSizes(BoardSize boardSize, int flags)
1480 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1481 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1483 XtGeometryResult gres;
1486 if(!formWidget) return;
1489 * Enable shell resizing.
1491 shellArgs[0].value = (XtArgVal) &w;
1492 shellArgs[1].value = (XtArgVal) &h;
1493 XtGetValues(shellWidget, shellArgs, 2);
1495 shellArgs[4].value = 2*w; shellArgs[2].value = 10;
1496 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1497 XtSetValues(shellWidget, &shellArgs[2], 4);
1499 XtSetArg(args[0], XtNdefaultDistance, &sep);
1500 XtGetValues(formWidget, args, 1);
1502 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1503 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1506 XtSetArg(args[0], XtNwidth, boardWidth);
1507 XtSetArg(args[1], XtNheight, boardHeight);
1508 XtSetValues(boardWidget, args, 2);
1510 timerWidth = (boardWidth - sep) / 2;
1511 XtSetArg(args[0], XtNwidth, timerWidth);
1512 XtSetValues(whiteTimerWidget, args, 1);
1513 XtSetValues(blackTimerWidget, args, 1);
1515 XawFormDoLayout(formWidget, False);
1517 if (appData.titleInWindow) {
1519 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1520 XtSetArg(args[i], XtNheight, &h); i++;
1521 XtGetValues(titleWidget, args, i);
1523 w = boardWidth - 2*bor;
1525 XtSetArg(args[0], XtNwidth, &w);
1526 XtGetValues(menuBarWidget, args, 1);
1527 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1530 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1531 if (gres != XtGeometryYes && appData.debugMode) {
1533 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1534 programName, gres, w, h, wr, hr);
1538 XawFormDoLayout(formWidget, True);
1541 * Inhibit shell resizing.
1543 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW;
1544 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1545 shellArgs[4].value = shellArgs[2].value = w;
1546 shellArgs[5].value = shellArgs[3].value = h;
1547 XtSetValues(shellWidget, &shellArgs[0], 6);
1549 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1552 for(i=0; i<4; i++) {
1554 for(p=0; p<=(int)WhiteKing; p++)
1555 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1556 if(gameInfo.variant == VariantShogi) {
1557 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1558 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1559 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1560 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1561 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1564 if(gameInfo.variant == VariantGothic) {
1565 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1569 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1570 for(p=0; p<=(int)WhiteKing; p++)
1571 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1572 if(gameInfo.variant == VariantShogi) {
1573 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1574 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1575 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1576 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1577 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1580 if(gameInfo.variant == VariantGothic) {
1581 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1587 for(i=0; i<2; i++) {
1589 for(p=0; p<=(int)WhiteKing; p++)
1590 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1591 if(gameInfo.variant == VariantShogi) {
1592 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1593 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1594 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1595 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1596 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1599 if(gameInfo.variant == VariantGothic) {
1600 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1611 void EscapeExpand(char *p, char *q)
1612 { // [HGM] initstring: routine to shape up string arguments
1613 while(*p++ = *q++) if(p[-1] == '\\')
1615 case 'n': p[-1] = '\n'; break;
1616 case 'r': p[-1] = '\r'; break;
1617 case 't': p[-1] = '\t'; break;
1618 case '\\': p[-1] = '\\'; break;
1619 case 0: *p = 0; return;
1620 default: p[-1] = q[-1]; break;
1629 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1630 XSetWindowAttributes window_attributes;
1632 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1633 XrmValue vFrom, vTo;
1634 XtGeometryResult gres;
1637 int forceMono = False;
1638 //define INDIRECTION
1640 // [HGM] before anything else, expand any indirection files amongst options
1641 char *argvCopy[1000]; // 1000 seems enough
1642 char newArgs[10000]; // holds actual characters
1645 srandom(time(0)); // [HGM] book: make random truly random
1648 for(i=0; i<argc; i++) {
1649 if(j >= 1000-2) { printf(_("too many arguments\n")); exit(-1); }
1650 //fprintf(stderr, "arg %s\n", argv[i]);
1651 if(argv[i][0] != '@') argvCopy[j++] = argv[i]; else {
1653 FILE *f = fopen(argv[i]+1, "rb");
1654 if(f == NULL) { fprintf(stderr, _("ignore %s\n"), argv[i]); continue; } // do not expand non-existing
1655 argvCopy[j++] = newArgs + k; // get ready for first argument from file
1656 while((c = fgetc(f)) != EOF) { // each line of file inserts 1 argument in the list
1658 if(j >= 1000-2) { printf(_("too many arguments\n")); exit(-1); }
1659 newArgs[k++] = 0; // terminate current arg
1660 if(k >= 10000-1) { printf(_("too long arguments\n")); exit(-1); }
1661 argvCopy[j++] = newArgs + k; // get ready for next
1663 if(k >= 10000-1) { printf(_("too long arguments\n")); exit(-1); }
1677 setbuf(stdout, NULL);
1678 setbuf(stderr, NULL);
1681 programName = strrchr(argv[0], '/');
1682 if (programName == NULL)
1683 programName = argv[0];
1688 XtSetLanguageProc(NULL, NULL, NULL);
1689 bindtextdomain(PACKAGE, LOCALEDIR);
1690 textdomain(PACKAGE);
1694 XtAppInitialize(&appContext, "XBoard", shellOptions,
1695 XtNumber(shellOptions),
1696 &argc, argv, xboardResources, NULL, 0);
1697 appData.boardSize = "";
1698 InitAppData(ConvertToLine(argc, argv));
1700 if (p == NULL) p = "/tmp";
1701 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1702 gameCopyFilename = (char*) malloc(i);
1703 gamePasteFilename = (char*) malloc(i);
1704 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1705 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1707 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1708 clientResources, XtNumber(clientResources),
1711 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1712 static char buf[MSG_SIZ];
1713 EscapeExpand(buf, appData.initString);
1714 appData.initString = strdup(buf);
1715 EscapeExpand(buf, appData.secondInitString);
1716 appData.secondInitString = strdup(buf);
1717 EscapeExpand(buf, appData.firstComputerString);
1718 appData.firstComputerString = strdup(buf);
1719 EscapeExpand(buf, appData.secondComputerString);
1720 appData.secondComputerString = strdup(buf);
1723 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1726 if (chdir(chessDir) != 0) {
1727 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1733 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1734 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1735 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1736 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1739 setbuf(debugFP, NULL);
1742 /* [HGM,HR] make sure board size is acceptable */
1743 if(appData.NrFiles > BOARD_FILES ||
1744 appData.NrRanks > BOARD_RANKS )
1745 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1748 /* This feature does not work; animation needs a rewrite */
1749 appData.highlightDragging = FALSE;
1753 xDisplay = XtDisplay(shellWidget);
1754 xScreen = DefaultScreen(xDisplay);
1755 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1757 gameInfo.variant = StringToVariant(appData.variant);
1758 InitPosition(FALSE);
1761 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1763 if (isdigit(appData.boardSize[0])) {
1764 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1765 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1766 &fontPxlSize, &smallLayout, &tinyLayout);
1768 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1769 programName, appData.boardSize);
1773 /* Find some defaults; use the nearest known size */
1774 SizeDefaults *szd, *nearest;
1775 int distance = 99999;
1776 nearest = szd = sizeDefaults;
1777 while (szd->name != NULL) {
1778 if (abs(szd->squareSize - squareSize) < distance) {
1780 distance = abs(szd->squareSize - squareSize);
1781 if (distance == 0) break;
1785 if (i < 2) lineGap = nearest->lineGap;
1786 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1787 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1788 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1789 if (i < 6) smallLayout = nearest->smallLayout;
1790 if (i < 7) tinyLayout = nearest->tinyLayout;
1793 SizeDefaults *szd = sizeDefaults;
1794 if (*appData.boardSize == NULLCHAR) {
1795 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1796 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1799 if (szd->name == NULL) szd--;
1800 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1802 while (szd->name != NULL &&
1803 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1804 if (szd->name == NULL) {
1805 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1806 programName, appData.boardSize);
1810 squareSize = szd->squareSize;
1811 lineGap = szd->lineGap;
1812 clockFontPxlSize = szd->clockFontPxlSize;
1813 coordFontPxlSize = szd->coordFontPxlSize;
1814 fontPxlSize = szd->fontPxlSize;
1815 smallLayout = szd->smallLayout;
1816 tinyLayout = szd->tinyLayout;
1819 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1820 if (strlen(appData.pixmapDirectory) > 0) {
1821 p = ExpandPathName(appData.pixmapDirectory);
1823 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1824 appData.pixmapDirectory);
1827 if (appData.debugMode) {
1828 fprintf(stderr, _("\
1829 XBoard square size (hint): %d\n\
1830 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1832 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1833 if (appData.debugMode) {
1834 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1838 /* [HR] height treated separately (hacked) */
1839 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1840 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1841 if (appData.showJail == 1) {
1842 /* Jail on top and bottom */
1843 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1844 XtSetArg(boardArgs[2], XtNheight,
1845 boardHeight + 2*(lineGap + squareSize));
1846 } else if (appData.showJail == 2) {
1848 XtSetArg(boardArgs[1], XtNwidth,
1849 boardWidth + 2*(lineGap + squareSize));
1850 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1853 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1854 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1858 * Determine what fonts to use.
1860 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1861 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1862 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1863 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1864 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1865 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1866 appData.font = FindFont(appData.font, fontPxlSize);
1867 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1868 countFontStruct = XQueryFont(xDisplay, countFontID);
1869 // appData.font = FindFont(appData.font, fontPxlSize);
1871 xdb = XtDatabase(xDisplay);
1872 XrmPutStringResource(&xdb, "*font", appData.font);
1875 * Detect if there are not enough colors available and adapt.
1877 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1878 appData.monoMode = True;
1881 if (!appData.monoMode) {
1882 vFrom.addr = (caddr_t) appData.lightSquareColor;
1883 vFrom.size = strlen(appData.lightSquareColor);
1884 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1885 if (vTo.addr == NULL) {
1886 appData.monoMode = True;
1889 lightSquareColor = *(Pixel *) vTo.addr;
1892 if (!appData.monoMode) {
1893 vFrom.addr = (caddr_t) appData.darkSquareColor;
1894 vFrom.size = strlen(appData.darkSquareColor);
1895 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1896 if (vTo.addr == NULL) {
1897 appData.monoMode = True;
1900 darkSquareColor = *(Pixel *) vTo.addr;
1903 if (!appData.monoMode) {
1904 vFrom.addr = (caddr_t) appData.whitePieceColor;
1905 vFrom.size = strlen(appData.whitePieceColor);
1906 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1907 if (vTo.addr == NULL) {
1908 appData.monoMode = True;
1911 whitePieceColor = *(Pixel *) vTo.addr;
1914 if (!appData.monoMode) {
1915 vFrom.addr = (caddr_t) appData.blackPieceColor;
1916 vFrom.size = strlen(appData.blackPieceColor);
1917 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1918 if (vTo.addr == NULL) {
1919 appData.monoMode = True;
1922 blackPieceColor = *(Pixel *) vTo.addr;
1926 if (!appData.monoMode) {
1927 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1928 vFrom.size = strlen(appData.highlightSquareColor);
1929 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1930 if (vTo.addr == NULL) {
1931 appData.monoMode = True;
1934 highlightSquareColor = *(Pixel *) vTo.addr;
1938 if (!appData.monoMode) {
1939 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1940 vFrom.size = strlen(appData.premoveHighlightColor);
1941 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1942 if (vTo.addr == NULL) {
1943 appData.monoMode = True;
1946 premoveHighlightColor = *(Pixel *) vTo.addr;
1951 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1954 if (appData.bitmapDirectory == NULL ||
1955 appData.bitmapDirectory[0] == NULLCHAR)
1956 appData.bitmapDirectory = DEF_BITMAP_DIR;
1959 if (appData.lowTimeWarning && !appData.monoMode) {
1960 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
1961 vFrom.size = strlen(appData.lowTimeWarningColor);
1962 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1963 if (vTo.addr == NULL)
1964 appData.monoMode = True;
1966 lowTimeWarningColor = *(Pixel *) vTo.addr;
1969 if (appData.monoMode && appData.debugMode) {
1970 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1971 (unsigned long) XWhitePixel(xDisplay, xScreen),
1972 (unsigned long) XBlackPixel(xDisplay, xScreen));
1975 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1976 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1977 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1978 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1979 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1980 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1981 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1982 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1983 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1984 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1986 if (appData.colorize) {
1988 _("%s: can't parse color names; disabling colorization\n"),
1991 appData.colorize = FALSE;
1993 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
1994 textColors[ColorNone].attr = 0;
1996 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2002 layoutName = "tinyLayout";
2003 } else if (smallLayout) {
2004 layoutName = "smallLayout";
2006 layoutName = "normalLayout";
2008 /* Outer layoutWidget is there only to provide a name for use in
2009 resources that depend on the layout style */
2011 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2012 layoutArgs, XtNumber(layoutArgs));
2014 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2015 formArgs, XtNumber(formArgs));
2016 XtSetArg(args[0], XtNdefaultDistance, &sep);
2017 XtGetValues(formWidget, args, 1);
2020 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2021 XtSetArg(args[0], XtNtop, XtChainTop);
2022 XtSetArg(args[1], XtNbottom, XtChainTop);
2023 XtSetArg(args[2], XtNright, XtChainLeft);
2024 XtSetValues(menuBarWidget, args, 3);
2026 widgetList[j++] = whiteTimerWidget =
2027 XtCreateWidget("whiteTime", labelWidgetClass,
2028 formWidget, timerArgs, XtNumber(timerArgs));
2029 XtSetArg(args[0], XtNfont, clockFontStruct);
2030 XtSetArg(args[1], XtNtop, XtChainTop);
2031 XtSetArg(args[2], XtNbottom, XtChainTop);
2032 XtSetValues(whiteTimerWidget, args, 3);
2034 widgetList[j++] = blackTimerWidget =
2035 XtCreateWidget("blackTime", labelWidgetClass,
2036 formWidget, timerArgs, XtNumber(timerArgs));
2037 XtSetArg(args[0], XtNfont, clockFontStruct);
2038 XtSetArg(args[1], XtNtop, XtChainTop);
2039 XtSetArg(args[2], XtNbottom, XtChainTop);
2040 XtSetValues(blackTimerWidget, args, 3);
2042 if (appData.titleInWindow) {
2043 widgetList[j++] = titleWidget =
2044 XtCreateWidget("title", labelWidgetClass, formWidget,
2045 titleArgs, XtNumber(titleArgs));
2046 XtSetArg(args[0], XtNtop, XtChainTop);
2047 XtSetArg(args[1], XtNbottom, XtChainTop);
2048 XtSetValues(titleWidget, args, 2);
2051 if (appData.showButtonBar) {
2052 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2053 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2054 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2055 XtSetArg(args[2], XtNtop, XtChainTop);
2056 XtSetArg(args[3], XtNbottom, XtChainTop);
2057 XtSetValues(buttonBarWidget, args, 4);
2060 widgetList[j++] = messageWidget =
2061 XtCreateWidget("message", labelWidgetClass, formWidget,
2062 messageArgs, XtNumber(messageArgs));
2063 XtSetArg(args[0], XtNtop, XtChainTop);
2064 XtSetArg(args[1], XtNbottom, XtChainTop);
2065 XtSetValues(messageWidget, args, 2);
2067 widgetList[j++] = boardWidget =
2068 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2069 XtNumber(boardArgs));
2071 XtManageChildren(widgetList, j);
2073 timerWidth = (boardWidth - sep) / 2;
2074 XtSetArg(args[0], XtNwidth, timerWidth);
2075 XtSetValues(whiteTimerWidget, args, 1);
2076 XtSetValues(blackTimerWidget, args, 1);
2078 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2079 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2080 XtGetValues(whiteTimerWidget, args, 2);
2082 if (appData.showButtonBar) {
2083 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2084 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2085 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2089 * formWidget uses these constraints but they are stored
2093 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2094 XtSetValues(menuBarWidget, args, i);
2095 if (appData.titleInWindow) {
2098 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2099 XtSetValues(whiteTimerWidget, args, i);
2101 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2102 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2103 XtSetValues(blackTimerWidget, args, i);
2105 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2106 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2107 XtSetValues(titleWidget, args, i);
2109 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2110 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2111 XtSetValues(messageWidget, args, i);
2112 if (appData.showButtonBar) {
2114 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2115 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2116 XtSetValues(buttonBarWidget, args, i);
2120 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2121 XtSetValues(whiteTimerWidget, args, i);
2123 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2124 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2125 XtSetValues(blackTimerWidget, args, i);
2127 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2128 XtSetValues(titleWidget, args, i);
2130 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2131 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2132 XtSetValues(messageWidget, args, i);
2133 if (appData.showButtonBar) {
2135 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2136 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2137 XtSetValues(buttonBarWidget, args, i);
2142 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2143 XtSetValues(whiteTimerWidget, args, i);
2145 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2146 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2147 XtSetValues(blackTimerWidget, args, i);
2149 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2150 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2151 XtSetValues(messageWidget, args, i);
2152 if (appData.showButtonBar) {
2154 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2155 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2156 XtSetValues(buttonBarWidget, args, i);
2160 XtSetArg(args[0], XtNfromVert, messageWidget);
2161 XtSetArg(args[1], XtNtop, XtChainTop);
2162 XtSetArg(args[2], XtNbottom, XtChainBottom);
2163 XtSetArg(args[3], XtNleft, XtChainLeft);
2164 XtSetArg(args[4], XtNright, XtChainRight);
2165 XtSetValues(boardWidget, args, 5);
2167 XtRealizeWidget(shellWidget);
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);
2436 if (errorExitStatus == -1) {
2437 if (appData.icsActive) {
2438 /* We now wait until we see "login:" from the ICS before
2439 sending the logon script (problems with timestamp otherwise) */
2440 /*ICSInitScript();*/
2441 if (appData.icsInputBox) ICSInputBoxPopUp();
2445 signal(SIGWINCH, TermSizeSigHandler);
2447 signal(SIGINT, IntSigHandler);
2448 signal(SIGTERM, IntSigHandler);
2449 if (*appData.cmailGameName != NULLCHAR) {
2450 signal(SIGUSR1, CmailSigHandler);
2453 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2456 XtAppMainLoop(appContext);
2457 if (appData.debugMode) fclose(debugFP); // [DM] debug
2464 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2465 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2467 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2468 unlink(gameCopyFilename);
2469 unlink(gamePasteFilename);
2472 RETSIGTYPE TermSizeSigHandler(int sig)
2485 CmailSigHandler(sig)
2491 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2493 /* Activate call-back function CmailSigHandlerCallBack() */
2494 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2496 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2500 CmailSigHandlerCallBack(isr, closure, message, count, error)
2508 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2510 /**** end signal code ****/
2520 f = fopen(appData.icsLogon, "r");
2526 strcat(buf, appData.icsLogon);
2527 f = fopen(buf, "r");
2531 ProcessICSInitScript(f);
2538 EditCommentPopDown();
2553 if (!menuBarWidget) return;
2554 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2556 DisplayError("menuStep.Revert", 0);
2558 XtSetSensitive(w, !grey);
2563 SetMenuEnables(enab)
2567 if (!menuBarWidget) return;
2568 while (enab->name != NULL) {
2569 w = XtNameToWidget(menuBarWidget, enab->name);
2571 DisplayError(enab->name, 0);
2573 XtSetSensitive(w, enab->value);
2579 Enables icsEnables[] = {
2580 { "menuFile.Mail Move", False },
2581 { "menuFile.Reload CMail Message", False },
2582 { "menuMode.Machine Black", False },
2583 { "menuMode.Machine White", False },
2584 { "menuMode.Analysis Mode", False },
2585 { "menuMode.Analyze File", False },
2586 { "menuMode.Two Machines", False },
2588 { "menuHelp.Hint", False },
2589 { "menuHelp.Book", False },
2590 { "menuStep.Move Now", False },
2591 { "menuOptions.Periodic Updates", False },
2592 { "menuOptions.Hide Thinking", False },
2593 { "menuOptions.Ponder Next Move", False },
2598 Enables ncpEnables[] = {
2599 { "menuFile.Mail Move", False },
2600 { "menuFile.Reload CMail Message", False },
2601 { "menuMode.Machine White", False },
2602 { "menuMode.Machine Black", False },
2603 { "menuMode.Analysis Mode", False },
2604 { "menuMode.Analyze File", False },
2605 { "menuMode.Two Machines", False },
2606 { "menuMode.ICS Client", False },
2607 { "menuMode.ICS Input Box", False },
2608 { "Action", False },
2609 { "menuStep.Revert", False },
2610 { "menuStep.Move Now", False },
2611 { "menuStep.Retract Move", False },
2612 { "menuOptions.Auto Comment", False },
2613 { "menuOptions.Auto Flag", False },
2614 { "menuOptions.Auto Flip View", False },
2615 { "menuOptions.Auto Observe", False },
2616 { "menuOptions.Auto Raise Board", False },
2617 { "menuOptions.Get Move List", False },
2618 { "menuOptions.ICS Alarm", False },
2619 { "menuOptions.Move Sound", False },
2620 { "menuOptions.Quiet Play", False },
2621 { "menuOptions.Hide Thinking", False },
2622 { "menuOptions.Periodic Updates", False },
2623 { "menuOptions.Ponder Next Move", False },
2624 { "menuHelp.Hint", False },
2625 { "menuHelp.Book", False },
2629 Enables gnuEnables[] = {
2630 { "menuMode.ICS Client", False },
2631 { "menuMode.ICS Input Box", False },
2632 { "menuAction.Accept", False },
2633 { "menuAction.Decline", False },
2634 { "menuAction.Rematch", False },
2635 { "menuAction.Adjourn", False },
2636 { "menuAction.Stop Examining", False },
2637 { "menuAction.Stop Observing", False },
2638 { "menuStep.Revert", False },
2639 { "menuOptions.Auto Comment", False },
2640 { "menuOptions.Auto Observe", False },
2641 { "menuOptions.Auto Raise Board", False },
2642 { "menuOptions.Get Move List", False },
2643 { "menuOptions.Premove", False },
2644 { "menuOptions.Quiet Play", False },
2646 /* The next two options rely on SetCmailMode being called *after* */
2647 /* SetGNUMode so that when GNU is being used to give hints these */
2648 /* menu options are still available */
2650 { "menuFile.Mail Move", False },
2651 { "menuFile.Reload CMail Message", False },
2655 Enables cmailEnables[] = {
2657 { "menuAction.Call Flag", False },
2658 { "menuAction.Draw", True },
2659 { "menuAction.Adjourn", False },
2660 { "menuAction.Abort", False },
2661 { "menuAction.Stop Observing", False },
2662 { "menuAction.Stop Examining", False },
2663 { "menuFile.Mail Move", True },
2664 { "menuFile.Reload CMail Message", True },
2668 Enables trainingOnEnables[] = {
2669 { "menuMode.Edit Comment", False },
2670 { "menuMode.Pause", False },
2671 { "menuStep.Forward", False },
2672 { "menuStep.Backward", False },
2673 { "menuStep.Forward to End", False },
2674 { "menuStep.Back to Start", False },
2675 { "menuStep.Move Now", False },
2676 { "menuStep.Truncate Game", False },
2680 Enables trainingOffEnables[] = {
2681 { "menuMode.Edit Comment", True },
2682 { "menuMode.Pause", True },
2683 { "menuStep.Forward", True },
2684 { "menuStep.Backward", True },
2685 { "menuStep.Forward to End", True },
2686 { "menuStep.Back to Start", True },
2687 { "menuStep.Move Now", True },
2688 { "menuStep.Truncate Game", True },
2692 Enables machineThinkingEnables[] = {
2693 { "menuFile.Load Game", False },
2694 { "menuFile.Load Next Game", False },
2695 { "menuFile.Load Previous Game", False },
2696 { "menuFile.Reload Same Game", False },
2697 { "menuFile.Paste Game", False },
2698 { "menuFile.Load Position", False },
2699 { "menuFile.Load Next Position", False },
2700 { "menuFile.Load Previous Position", False },
2701 { "menuFile.Reload Same Position", False },
2702 { "menuFile.Paste Position", False },
2703 { "menuMode.Machine White", False },
2704 { "menuMode.Machine Black", False },
2705 { "menuMode.Two Machines", False },
2706 { "menuStep.Retract Move", False },
2710 Enables userThinkingEnables[] = {
2711 { "menuFile.Load Game", True },
2712 { "menuFile.Load Next Game", True },
2713 { "menuFile.Load Previous Game", True },
2714 { "menuFile.Reload Same Game", True },
2715 { "menuFile.Paste Game", True },
2716 { "menuFile.Load Position", True },
2717 { "menuFile.Load Next Position", True },
2718 { "menuFile.Load Previous Position", True },
2719 { "menuFile.Reload Same Position", True },
2720 { "menuFile.Paste Position", True },
2721 { "menuMode.Machine White", True },
2722 { "menuMode.Machine Black", True },
2723 { "menuMode.Two Machines", True },
2724 { "menuStep.Retract Move", True },
2730 SetMenuEnables(icsEnables);
2733 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2734 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2741 SetMenuEnables(ncpEnables);
2747 SetMenuEnables(gnuEnables);
2753 SetMenuEnables(cmailEnables);
2759 SetMenuEnables(trainingOnEnables);
2760 if (appData.showButtonBar) {
2761 XtSetSensitive(buttonBarWidget, False);
2767 SetTrainingModeOff()
2769 SetMenuEnables(trainingOffEnables);
2770 if (appData.showButtonBar) {
2771 XtSetSensitive(buttonBarWidget, True);
2776 SetUserThinkingEnables()
2778 if (appData.noChessProgram) return;
2779 SetMenuEnables(userThinkingEnables);
2783 SetMachineThinkingEnables()
2785 if (appData.noChessProgram) return;
2786 SetMenuEnables(machineThinkingEnables);
2788 case MachinePlaysBlack:
2789 case MachinePlaysWhite:
2790 case TwoMachinesPlay:
2791 XtSetSensitive(XtNameToWidget(menuBarWidget,
2792 ModeToWidgetName(gameMode)), True);
2799 #define Abs(n) ((n)<0 ? -(n) : (n))
2802 * Find a font that matches "pattern" that is as close as
2803 * possible to the targetPxlSize. Prefer fonts that are k
2804 * pixels smaller to fonts that are k pixels larger. The
2805 * pattern must be in the X Consortium standard format,
2806 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2807 * The return value should be freed with XtFree when no
2810 char *FindFont(pattern, targetPxlSize)
2814 char **fonts, *p, *best, *scalable, *scalableTail;
2815 int i, j, nfonts, minerr, err, pxlSize;
2818 char **missing_list;
2820 char *def_string, *base_fnt_lst, strInt[3];
2822 XFontStruct **fnt_list;
2824 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2825 sprintf(strInt, "%d", targetPxlSize);
2826 p = strstr(pattern, "--");
2827 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2828 strcat(base_fnt_lst, strInt);
2829 strcat(base_fnt_lst, strchr(p + 2, '-'));
2831 if ((fntSet = XCreateFontSet(xDisplay,
2835 &def_string)) == NULL) {
2837 fprintf(stderr, _("Unable to create font set.\n"));
2841 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2843 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2845 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2846 programName, pattern);
2854 for (i=0; i<nfonts; i++) {
2857 if (*p != '-') continue;
2859 if (*p == NULLCHAR) break;
2860 if (*p++ == '-') j++;
2862 if (j < 7) continue;
2865 scalable = fonts[i];
2868 err = pxlSize - targetPxlSize;
2869 if (Abs(err) < Abs(minerr) ||
2870 (minerr > 0 && err < 0 && -err == minerr)) {
2876 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
2877 /* If the error is too big and there is a scalable font,
2878 use the scalable font. */
2879 int headlen = scalableTail - scalable;
2880 p = (char *) XtMalloc(strlen(scalable) + 10);
2881 while (isdigit(*scalableTail)) scalableTail++;
2882 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
2884 p = (char *) XtMalloc(strlen(best) + 1);
2887 if (appData.debugMode) {
2888 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
2889 pattern, targetPxlSize, p);
2892 if (missing_count > 0)
2893 XFreeStringList(missing_list);
2894 XFreeFontSet(xDisplay, fntSet);
2896 XFreeFontNames(fonts);
2903 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
2904 | GCBackground | GCFunction | GCPlaneMask;
2905 XGCValues gc_values;
2908 gc_values.plane_mask = AllPlanes;
2909 gc_values.line_width = lineGap;
2910 gc_values.line_style = LineSolid;
2911 gc_values.function = GXcopy;
2913 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2914 gc_values.background = XBlackPixel(xDisplay, xScreen);
2915 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2917 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2918 gc_values.background = XWhitePixel(xDisplay, xScreen);
2919 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
2920 XSetFont(xDisplay, coordGC, coordFontID);
2922 // [HGM] make font for holdings counts (white on black0
2923 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2924 gc_values.background = XBlackPixel(xDisplay, xScreen);
2925 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
2926 XSetFont(xDisplay, countGC, countFontID);
2928 if (appData.monoMode) {
2929 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2930 gc_values.background = XWhitePixel(xDisplay, xScreen);
2931 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2933 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2934 gc_values.background = XBlackPixel(xDisplay, xScreen);
2935 lightSquareGC = wbPieceGC
2936 = XtGetGC(shellWidget, value_mask, &gc_values);
2938 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2939 gc_values.background = XWhitePixel(xDisplay, xScreen);
2940 darkSquareGC = bwPieceGC
2941 = XtGetGC(shellWidget, value_mask, &gc_values);
2943 if (DefaultDepth(xDisplay, xScreen) == 1) {
2944 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
2945 gc_values.function = GXcopyInverted;
2946 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
2947 gc_values.function = GXcopy;
2948 if (XBlackPixel(xDisplay, xScreen) == 1) {
2949 bwPieceGC = darkSquareGC;
2950 wbPieceGC = copyInvertedGC;
2952 bwPieceGC = copyInvertedGC;
2953 wbPieceGC = lightSquareGC;
2957 gc_values.foreground = highlightSquareColor;
2958 gc_values.background = highlightSquareColor;
2959 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2961 gc_values.foreground = premoveHighlightColor;
2962 gc_values.background = premoveHighlightColor;
2963 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2965 gc_values.foreground = lightSquareColor;
2966 gc_values.background = darkSquareColor;
2967 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2969 gc_values.foreground = darkSquareColor;
2970 gc_values.background = lightSquareColor;
2971 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2973 gc_values.foreground = jailSquareColor;
2974 gc_values.background = jailSquareColor;
2975 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2977 gc_values.foreground = whitePieceColor;
2978 gc_values.background = darkSquareColor;
2979 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
2981 gc_values.foreground = whitePieceColor;
2982 gc_values.background = lightSquareColor;
2983 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
2985 gc_values.foreground = whitePieceColor;
2986 gc_values.background = jailSquareColor;
2987 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
2989 gc_values.foreground = blackPieceColor;
2990 gc_values.background = darkSquareColor;
2991 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
2993 gc_values.foreground = blackPieceColor;
2994 gc_values.background = lightSquareColor;
2995 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
2997 gc_values.foreground = blackPieceColor;
2998 gc_values.background = jailSquareColor;
2999 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3003 void loadXIM(xim, xmask, filename, dest, mask)
3016 fp = fopen(filename, "rb");
3018 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3025 for (y=0; y<h; ++y) {
3026 for (x=0; x<h; ++x) {
3031 XPutPixel(xim, x, y, blackPieceColor);
3033 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3036 XPutPixel(xim, x, y, darkSquareColor);
3038 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3041 XPutPixel(xim, x, y, whitePieceColor);
3043 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3046 XPutPixel(xim, x, y, lightSquareColor);
3048 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3054 /* create Pixmap of piece */
3055 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3057 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3060 /* create Pixmap of clipmask
3061 Note: We assume the white/black pieces have the same
3062 outline, so we make only 6 masks. This is okay
3063 since the XPM clipmask routines do the same. */
3065 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3067 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3070 /* now create the 1-bit version */
3071 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3074 values.foreground = 1;
3075 values.background = 0;
3077 /* Don't use XtGetGC, not read only */
3078 maskGC = XCreateGC(xDisplay, *mask,
3079 GCForeground | GCBackground, &values);
3080 XCopyPlane(xDisplay, temp, *mask, maskGC,
3081 0, 0, squareSize, squareSize, 0, 0, 1);
3082 XFreePixmap(xDisplay, temp);
3087 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3089 void CreateXIMPieces()
3094 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3099 /* The XSynchronize calls were copied from CreatePieces.
3100 Not sure if needed, but can't hurt */
3101 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3104 /* temp needed by loadXIM() */
3105 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3106 0, 0, ss, ss, AllPlanes, XYPixmap);
3108 if (strlen(appData.pixmapDirectory) == 0) {
3112 if (appData.monoMode) {
3113 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3117 fprintf(stderr, _("\nLoading XIMs...\n"));
3119 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3120 fprintf(stderr, "%d", piece+1);
3121 for (kind=0; kind<4; kind++) {
3122 fprintf(stderr, ".");
3123 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3124 ExpandPathName(appData.pixmapDirectory),
3125 piece <= (int) WhiteKing ? "" : "w",
3126 pieceBitmapNames[piece],
3128 ximPieceBitmap[kind][piece] =
3129 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3130 0, 0, ss, ss, AllPlanes, XYPixmap);
3131 if (appData.debugMode)
3132 fprintf(stderr, _("(File:%s:) "), buf);
3133 loadXIM(ximPieceBitmap[kind][piece],
3135 &(xpmPieceBitmap2[kind][piece]),
3136 &(ximMaskPm2[piece]));
3137 if(piece <= (int)WhiteKing)
3138 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3140 fprintf(stderr," ");
3142 /* Load light and dark squares */
3143 /* If the LSQ and DSQ pieces don't exist, we will
3144 draw them with solid squares. */
3145 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3146 if (access(buf, 0) != 0) {
3150 fprintf(stderr, _("light square "));
3152 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3153 0, 0, ss, ss, AllPlanes, XYPixmap);
3154 if (appData.debugMode)
3155 fprintf(stderr, _("(File:%s:) "), buf);
3157 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3158 fprintf(stderr, _("dark square "));
3159 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3160 ExpandPathName(appData.pixmapDirectory), ss);
3161 if (appData.debugMode)
3162 fprintf(stderr, _("(File:%s:) "), buf);
3164 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3165 0, 0, ss, ss, AllPlanes, XYPixmap);
3166 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3167 xpmJailSquare = xpmLightSquare;
3169 fprintf(stderr, _("Done.\n"));
3171 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3175 void CreateXPMPieces()
3179 u_int ss = squareSize;
3181 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3182 XpmColorSymbol symbols[4];
3184 /* The XSynchronize calls were copied from CreatePieces.
3185 Not sure if needed, but can't hurt */
3186 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3188 /* Setup translations so piece colors match square colors */
3189 symbols[0].name = "light_piece";
3190 symbols[0].value = appData.whitePieceColor;
3191 symbols[1].name = "dark_piece";
3192 symbols[1].value = appData.blackPieceColor;
3193 symbols[2].name = "light_square";
3194 symbols[2].value = appData.lightSquareColor;
3195 symbols[3].name = "dark_square";
3196 symbols[3].value = appData.darkSquareColor;
3198 attr.valuemask = XpmColorSymbols;
3199 attr.colorsymbols = symbols;
3200 attr.numsymbols = 4;
3202 if (appData.monoMode) {
3203 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3207 if (strlen(appData.pixmapDirectory) == 0) {
3208 XpmPieces* pieces = builtInXpms;
3211 while (pieces->size != squareSize && pieces->size) pieces++;
3212 if (!pieces->size) {
3213 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3216 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3217 for (kind=0; kind<4; kind++) {
3219 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3220 pieces->xpm[piece][kind],
3221 &(xpmPieceBitmap2[kind][piece]),
3222 NULL, &attr)) != 0) {
3223 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3227 if(piece <= (int) WhiteKing)
3228 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3232 xpmJailSquare = xpmLightSquare;
3236 fprintf(stderr, _("\nLoading XPMs...\n"));
3239 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3240 fprintf(stderr, "%d ", piece+1);
3241 for (kind=0; kind<4; kind++) {
3242 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3243 ExpandPathName(appData.pixmapDirectory),
3244 piece > (int) WhiteKing ? "w" : "",
3245 pieceBitmapNames[piece],
3247 if (appData.debugMode) {
3248 fprintf(stderr, _("(File:%s:) "), buf);
3250 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3251 &(xpmPieceBitmap2[kind][piece]),
3252 NULL, &attr)) != 0) {
3253 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3254 // [HGM] missing: read of unorthodox piece failed; substitute King.
3255 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3256 ExpandPathName(appData.pixmapDirectory),
3258 if (appData.debugMode) {
3259 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3261 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3262 &(xpmPieceBitmap2[kind][piece]),
3266 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3271 if(piece <= (int) WhiteKing)
3272 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3275 /* Load light and dark squares */
3276 /* If the LSQ and DSQ pieces don't exist, we will
3277 draw them with solid squares. */
3278 fprintf(stderr, _("light square "));
3279 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3280 if (access(buf, 0) != 0) {
3284 if (appData.debugMode)
3285 fprintf(stderr, _("(File:%s:) "), buf);
3287 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3288 &xpmLightSquare, NULL, &attr)) != 0) {
3289 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3292 fprintf(stderr, _("dark square "));
3293 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3294 ExpandPathName(appData.pixmapDirectory), ss);
3295 if (appData.debugMode) {
3296 fprintf(stderr, _("(File:%s:) "), buf);
3298 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3299 &xpmDarkSquare, NULL, &attr)) != 0) {
3300 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3304 xpmJailSquare = xpmLightSquare;
3305 fprintf(stderr, _("Done.\n"));
3307 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3310 #endif /* HAVE_LIBXPM */
3313 /* No built-in bitmaps */
3318 u_int ss = squareSize;
3320 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3323 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3324 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3325 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3326 pieceBitmapNames[piece],
3327 ss, kind == SOLID ? 's' : 'o');
3328 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3329 if(piece <= (int)WhiteKing)
3330 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3334 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3338 /* With built-in bitmaps */
3341 BuiltInBits* bib = builtInBits;
3344 u_int ss = squareSize;
3346 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3349 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3351 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3352 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3353 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3354 pieceBitmapNames[piece],
3355 ss, kind == SOLID ? 's' : 'o');
3356 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3357 bib->bits[kind][piece], ss, ss);
3358 if(piece <= (int)WhiteKing)
3359 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3363 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3368 void ReadBitmap(pm, name, bits, wreq, hreq)
3371 unsigned char bits[];
3377 char msg[MSG_SIZ], fullname[MSG_SIZ];
3379 if (*appData.bitmapDirectory != NULLCHAR) {
3380 strcpy(fullname, appData.bitmapDirectory);
3381 strcat(fullname, "/");
3382 strcat(fullname, name);
3383 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3384 &w, &h, pm, &x_hot, &y_hot);
3385 fprintf(stderr, "load %s\n", name);
3386 if (errcode != BitmapSuccess) {
3388 case BitmapOpenFailed:
3389 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3391 case BitmapFileInvalid:
3392 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3394 case BitmapNoMemory:
3395 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3399 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3403 fprintf(stderr, _("%s: %s...using built-in\n"),
3405 } else if (w != wreq || h != hreq) {
3407 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3408 programName, fullname, w, h, wreq, hreq);
3414 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3423 if (lineGap == 0) return;
3425 /* [HR] Split this into 2 loops for non-square boards. */
3427 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3428 gridSegments[i].x1 = 0;
3429 gridSegments[i].x2 =
3430 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3431 gridSegments[i].y1 = gridSegments[i].y2
3432 = lineGap / 2 + (i * (squareSize + lineGap));
3435 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3436 gridSegments[j + i].y1 = 0;
3437 gridSegments[j + i].y2 =
3438 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3439 gridSegments[j + i].x1 = gridSegments[j + i].x2
3440 = lineGap / 2 + (j * (squareSize + lineGap));
3444 static void MenuBarSelect(w, addr, index)
3449 XtActionProc proc = (XtActionProc) addr;
3451 (proc)(NULL, NULL, NULL, NULL);
3454 void CreateMenuBarPopup(parent, name, mb)
3464 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3467 XtSetArg(args[j], XtNleftMargin, 20); j++;
3468 XtSetArg(args[j], XtNrightMargin, 20); j++;
3470 while (mi->string != NULL) {
3471 if (strcmp(mi->string, "----") == 0) {
3472 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3475 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3476 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3478 XtAddCallback(entry, XtNcallback,
3479 (XtCallbackProc) MenuBarSelect,
3480 (caddr_t) mi->proc);
3486 Widget CreateMenuBar(mb)
3490 Widget anchor, menuBar;
3492 char menuName[MSG_SIZ];
3495 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3496 XtSetArg(args[j], XtNvSpace, 0); j++;
3497 XtSetArg(args[j], XtNborderWidth, 0); j++;
3498 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3499 formWidget, args, j);
3501 while (mb->name != NULL) {
3502 strcpy(menuName, "menu");
3503 strcat(menuName, mb->name);
3505 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3508 shortName[0] = _(mb->name)[0];
3509 shortName[1] = NULLCHAR;
3510 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3513 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3516 XtSetArg(args[j], XtNborderWidth, 0); j++;
3517 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3519 CreateMenuBarPopup(menuBar, menuName, mb);
3525 Widget CreateButtonBar(mi)
3529 Widget button, buttonBar;
3533 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3535 XtSetArg(args[j], XtNhSpace, 0); j++;
3537 XtSetArg(args[j], XtNborderWidth, 0); j++;
3538 XtSetArg(args[j], XtNvSpace, 0); j++;
3539 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3540 formWidget, args, j);
3542 while (mi->string != NULL) {
3545 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3546 XtSetArg(args[j], XtNborderWidth, 0); j++;
3548 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3549 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3550 buttonBar, args, j);
3551 XtAddCallback(button, XtNcallback,
3552 (XtCallbackProc) MenuBarSelect,
3553 (caddr_t) mi->proc);
3560 CreatePieceMenu(name, color)
3567 ChessSquare selection;
3569 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3570 boardWidget, args, 0);
3572 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3573 String item = pieceMenuStrings[color][i];
3575 if (strcmp(item, "----") == 0) {
3576 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3579 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3580 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3582 selection = pieceMenuTranslation[color][i];
3583 XtAddCallback(entry, XtNcallback,
3584 (XtCallbackProc) PieceMenuSelect,
3585 (caddr_t) selection);
3586 if (selection == WhitePawn || selection == BlackPawn) {
3587 XtSetArg(args[0], XtNpopupOnEntry, entry);
3588 XtSetValues(menu, args, 1);
3601 ChessSquare selection;
3603 whitePieceMenu = CreatePieceMenu("menuW", 0);
3604 blackPieceMenu = CreatePieceMenu("menuB", 1);
3606 XtRegisterGrabAction(PieceMenuPopup, True,
3607 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3608 GrabModeAsync, GrabModeAsync);
3610 XtSetArg(args[0], XtNlabel, _("Drop"));
3611 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3612 boardWidget, args, 1);
3613 for (i = 0; i < DROP_MENU_SIZE; i++) {
3614 String item = dropMenuStrings[i];
3616 if (strcmp(item, "----") == 0) {
3617 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3620 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3621 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3623 selection = dropMenuTranslation[i];
3624 XtAddCallback(entry, XtNcallback,
3625 (XtCallbackProc) DropMenuSelect,
3626 (caddr_t) selection);
3631 void SetupDropMenu()
3639 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3640 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3641 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3642 dmEnables[i].piece);
3643 XtSetSensitive(entry, p != NULL || !appData.testLegality
3644 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3645 && !appData.icsActive));
3647 while (p && *p++ == dmEnables[i].piece) count++;
3648 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3650 XtSetArg(args[j], XtNlabel, label); j++;
3651 XtSetValues(entry, args, j);
3655 void PieceMenuPopup(w, event, params, num_params)
3659 Cardinal *num_params;
3662 if (event->type != ButtonPress) return;
3663 if (errorUp) ErrorPopDown();
3667 whichMenu = params[0];
3669 case IcsPlayingWhite:
3670 case IcsPlayingBlack:
3672 case MachinePlaysWhite:
3673 case MachinePlaysBlack:
3674 if (appData.testLegality &&
3675 gameInfo.variant != VariantBughouse &&
3676 gameInfo.variant != VariantCrazyhouse) return;
3678 whichMenu = "menuD";
3684 if (((pmFromX = EventToSquare(event->xbutton.x, BOARD_WIDTH)) < 0) ||
3685 ((pmFromY = EventToSquare(event->xbutton.y, BOARD_HEIGHT)) < 0)) {
3686 pmFromX = pmFromY = -1;
3690 pmFromX = BOARD_WIDTH - 1 - pmFromX;
3692 pmFromY = BOARD_HEIGHT - 1 - pmFromY;
3694 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3697 static void PieceMenuSelect(w, piece, junk)
3702 if (pmFromX < 0 || pmFromY < 0) return;
3703 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3706 static void DropMenuSelect(w, piece, junk)
3711 if (pmFromX < 0 || pmFromY < 0) return;
3712 DropMenuEvent(piece, pmFromX, pmFromY);
3715 void WhiteClock(w, event, prms, nprms)
3721 if (gameMode == EditPosition || gameMode == IcsExamining) {
3722 SetWhiteToPlayEvent();
3723 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3728 void BlackClock(w, event, prms, nprms)
3734 if (gameMode == EditPosition || gameMode == IcsExamining) {
3735 SetBlackToPlayEvent();
3736 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3743 * If the user selects on a border boundary, return -1; if off the board,
3744 * return -2. Otherwise map the event coordinate to the square.
3746 int EventToSquare(x, limit)
3754 if ((x % (squareSize + lineGap)) >= squareSize)
3756 x /= (squareSize + lineGap);
3762 static void do_flash_delay(msec)
3768 static void drawHighlight(file, rank, gc)
3774 if (lineGap == 0 || appData.blindfold) return;
3777 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3778 (squareSize + lineGap);
3779 y = lineGap/2 + rank * (squareSize + lineGap);
3781 x = lineGap/2 + file * (squareSize + lineGap);
3782 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3783 (squareSize + lineGap);
3786 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3787 squareSize+lineGap, squareSize+lineGap);
3790 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3791 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3794 SetHighlights(fromX, fromY, toX, toY)
3795 int fromX, fromY, toX, toY;
3797 if (hi1X != fromX || hi1Y != fromY) {
3798 if (hi1X >= 0 && hi1Y >= 0) {
3799 drawHighlight(hi1X, hi1Y, lineGC);
3801 if (fromX >= 0 && fromY >= 0) {
3802 drawHighlight(fromX, fromY, highlineGC);
3805 if (hi2X != toX || hi2Y != toY) {
3806 if (hi2X >= 0 && hi2Y >= 0) {
3807 drawHighlight(hi2X, hi2Y, lineGC);
3809 if (toX >= 0 && toY >= 0) {
3810 drawHighlight(toX, toY, highlineGC);
3822 SetHighlights(-1, -1, -1, -1);
3827 SetPremoveHighlights(fromX, fromY, toX, toY)
3828 int fromX, fromY, toX, toY;
3830 if (pm1X != fromX || pm1Y != fromY) {
3831 if (pm1X >= 0 && pm1Y >= 0) {
3832 drawHighlight(pm1X, pm1Y, lineGC);
3834 if (fromX >= 0 && fromY >= 0) {
3835 drawHighlight(fromX, fromY, prelineGC);
3838 if (pm2X != toX || pm2Y != toY) {
3839 if (pm2X >= 0 && pm2Y >= 0) {
3840 drawHighlight(pm2X, pm2Y, lineGC);
3842 if (toX >= 0 && toY >= 0) {
3843 drawHighlight(toX, toY, prelineGC);
3853 ClearPremoveHighlights()
3855 SetPremoveHighlights(-1, -1, -1, -1);
3858 static void BlankSquare(x, y, color, piece, dest)
3863 if (useImages && useImageSqs) {
3867 pm = xpmLightSquare;
3872 case 2: /* neutral */
3877 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
3878 squareSize, squareSize, x, y);
3888 case 2: /* neutral */
3893 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
3898 I split out the routines to draw a piece so that I could
3899 make a generic flash routine.
3901 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
3903 int square_color, x, y;
3906 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3907 switch (square_color) {
3909 case 2: /* neutral */
3911 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3912 ? *pieceToOutline(piece)
3913 : *pieceToSolid(piece),
3914 dest, bwPieceGC, 0, 0,
3915 squareSize, squareSize, x, y);
3918 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3919 ? *pieceToSolid(piece)
3920 : *pieceToOutline(piece),
3921 dest, wbPieceGC, 0, 0,
3922 squareSize, squareSize, x, y);
3927 static void monoDrawPiece(piece, square_color, x, y, dest)
3929 int square_color, x, y;
3932 switch (square_color) {
3934 case 2: /* neutral */
3936 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3937 ? *pieceToOutline(piece)
3938 : *pieceToSolid(piece),
3939 dest, bwPieceGC, 0, 0,
3940 squareSize, squareSize, x, y, 1);
3943 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3944 ? *pieceToSolid(piece)
3945 : *pieceToOutline(piece),
3946 dest, wbPieceGC, 0, 0,
3947 squareSize, squareSize, x, y, 1);
3952 static void colorDrawPiece(piece, square_color, x, y, dest)
3954 int square_color, x, y;
3957 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
3958 switch (square_color) {
3960 XCopyPlane(xDisplay, *pieceToSolid(piece),
3961 dest, (int) piece < (int) BlackPawn
3962 ? wlPieceGC : blPieceGC, 0, 0,
3963 squareSize, squareSize, x, y, 1);
3966 XCopyPlane(xDisplay, *pieceToSolid(piece),
3967 dest, (int) piece < (int) BlackPawn
3968 ? wdPieceGC : bdPieceGC, 0, 0,
3969 squareSize, squareSize, x, y, 1);
3971 case 2: /* neutral */
3973 XCopyPlane(xDisplay, *pieceToSolid(piece),
3974 dest, (int) piece < (int) BlackPawn
3975 ? wjPieceGC : bjPieceGC, 0, 0,
3976 squareSize, squareSize, x, y, 1);
3981 static void colorDrawPieceImage(piece, square_color, x, y, dest)
3983 int square_color, x, y;
3988 switch (square_color) {
3990 case 2: /* neutral */
3992 if ((int)piece < (int) BlackPawn) {
4000 if ((int)piece < (int) BlackPawn) {
4008 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4009 dest, wlPieceGC, 0, 0,
4010 squareSize, squareSize, x, y);
4013 typedef void (*DrawFunc)();
4015 DrawFunc ChooseDrawFunc()
4017 if (appData.monoMode) {
4018 if (DefaultDepth(xDisplay, xScreen) == 1) {
4019 return monoDrawPiece_1bit;
4021 return monoDrawPiece;
4025 return colorDrawPieceImage;
4027 return colorDrawPiece;
4031 /* [HR] determine square color depending on chess variant. */
4032 static int SquareColor(row, column)
4037 if (gameInfo.variant == VariantXiangqi) {
4038 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4040 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4042 } else if (row <= 4) {
4048 square_color = ((column + row) % 2) == 1;
4051 /* [hgm] holdings: next line makes all holdings squares light */
4052 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4054 return square_color;
4057 void DrawSquare(row, column, piece, do_flash)
4058 int row, column, do_flash;
4061 int square_color, x, y, direction, font_ascent, font_descent;
4064 XCharStruct overall;
4068 /* Calculate delay in milliseconds (2-delays per complete flash) */
4069 flash_delay = 500 / appData.flashRate;
4072 x = lineGap + ((BOARD_WIDTH-1)-column) *
4073 (squareSize + lineGap);
4074 y = lineGap + row * (squareSize + lineGap);
4076 x = lineGap + column * (squareSize + lineGap);
4077 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4078 (squareSize + lineGap);
4081 square_color = SquareColor(row, column);
4083 if ( // [HGM] holdings: blank out area between board and holdings
4084 column == BOARD_LEFT-1 || column == BOARD_RGHT
4085 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4086 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4087 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4089 // [HGM] print piece counts next to holdings
4090 string[1] = NULLCHAR;
4091 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4092 string[0] = '0' + piece;
4093 XTextExtents(countFontStruct, string, 1, &direction,
4094 &font_ascent, &font_descent, &overall);
4095 if (appData.monoMode) {
4096 XDrawImageString(xDisplay, xBoardWindow, countGC,
4097 x + squareSize - overall.width - 2,
4098 y + font_ascent + 1, string, 1);
4100 XDrawString(xDisplay, xBoardWindow, countGC,
4101 x + squareSize - overall.width - 2,
4102 y + font_ascent + 1, string, 1);
4105 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && 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 + 2, y + font_ascent + 1, string, 1);
4113 XDrawString(xDisplay, xBoardWindow, countGC,
4114 x + 2, y + font_ascent + 1, string, 1);
4118 if (piece == EmptySquare || appData.blindfold) {
4119 BlankSquare(x, y, square_color, piece, xBoardWindow);
4121 drawfunc = ChooseDrawFunc();
4122 if (do_flash && appData.flashCount > 0) {
4123 for (i=0; i<appData.flashCount; ++i) {
4125 drawfunc(piece, square_color, x, y, xBoardWindow);
4126 XSync(xDisplay, False);
4127 do_flash_delay(flash_delay);
4129 BlankSquare(x, y, square_color, piece, xBoardWindow);
4130 XSync(xDisplay, False);
4131 do_flash_delay(flash_delay);
4134 drawfunc(piece, square_color, x, y, xBoardWindow);
4138 string[1] = NULLCHAR;
4139 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4140 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4141 string[0] = 'a' + column - BOARD_LEFT;
4142 XTextExtents(coordFontStruct, string, 1, &direction,
4143 &font_ascent, &font_descent, &overall);
4144 if (appData.monoMode) {
4145 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4146 x + squareSize - overall.width - 2,
4147 y + squareSize - font_descent - 1, string, 1);
4149 XDrawString(xDisplay, xBoardWindow, coordGC,
4150 x + squareSize - overall.width - 2,
4151 y + squareSize - font_descent - 1, string, 1);
4154 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4155 string[0] = ONE + row;
4156 XTextExtents(coordFontStruct, string, 1, &direction,
4157 &font_ascent, &font_descent, &overall);
4158 if (appData.monoMode) {
4159 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4160 x + 2, y + font_ascent + 1, string, 1);
4162 XDrawString(xDisplay, xBoardWindow, coordGC,
4163 x + 2, y + font_ascent + 1, string, 1);
4169 /* Why is this needed on some versions of X? */
4170 void EventProc(widget, unused, event)
4175 if (!XtIsRealized(widget))
4178 switch (event->type) {
4180 if (event->xexpose.count > 0) return; /* no clipping is done */
4181 XDrawPosition(widget, True, NULL);
4189 void DrawPosition(fullRedraw, board)
4190 /*Boolean*/int fullRedraw;
4193 XDrawPosition(boardWidget, fullRedraw, board);
4196 /* Returns 1 if there are "too many" differences between b1 and b2
4197 (i.e. more than 1 move was made) */
4198 static int too_many_diffs(b1, b2)
4204 for (i=0; i<BOARD_HEIGHT; ++i) {
4205 for (j=0; j<BOARD_WIDTH; ++j) {
4206 if (b1[i][j] != b2[i][j]) {
4207 if (++c > 4) /* Castling causes 4 diffs */
4216 /* Matrix describing castling maneuvers */
4217 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4218 static int castling_matrix[4][5] = {
4219 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4220 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4221 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4222 { 7, 7, 4, 5, 6 } /* 0-0, black */
4225 /* Checks whether castling occurred. If it did, *rrow and *rcol
4226 are set to the destination (row,col) of the rook that moved.
4228 Returns 1 if castling occurred, 0 if not.
4230 Note: Only handles a max of 1 castling move, so be sure
4231 to call too_many_diffs() first.
4233 static int check_castle_draw(newb, oldb, rrow, rcol)
4240 /* For each type of castling... */
4241 for (i=0; i<4; ++i) {
4242 r = castling_matrix[i];
4244 /* Check the 4 squares involved in the castling move */
4246 for (j=1; j<=4; ++j) {
4247 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4254 /* All 4 changed, so it must be a castling move */
4263 static int damage[BOARD_RANKS][BOARD_FILES];
4266 * event handler for redrawing the board
4268 void XDrawPosition(w, repaint, board)
4270 /*Boolean*/int repaint;
4274 static int lastFlipView = 0;
4275 static int lastBoardValid = 0;
4276 static Board lastBoard;
4280 if (board == NULL) {
4281 if (!lastBoardValid) return;
4284 if (!lastBoardValid || lastFlipView != flipView) {
4285 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4286 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4291 * It would be simpler to clear the window with XClearWindow()
4292 * but this causes a very distracting flicker.
4295 if (!repaint && lastBoardValid && lastFlipView == flipView) {
4297 /* If too much changes (begin observing new game, etc.), don't
4299 do_flash = too_many_diffs(board, lastBoard) ? 0 : 1;
4301 /* Special check for castling so we don't flash both the king
4302 and the rook (just flash the king). */
4304 if (check_castle_draw(board, lastBoard, &rrow, &rcol)) {
4305 /* Draw rook with NO flashing. King will be drawn flashing later */
4306 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4307 lastBoard[rrow][rcol] = board[rrow][rcol];
4311 /* First pass -- Draw (newly) empty squares and repair damage.
4312 This prevents you from having a piece show up twice while it
4313 is flashing on its new square */
4314 for (i = 0; i < BOARD_HEIGHT; i++)
4315 for (j = 0; j < BOARD_WIDTH; j++)
4316 if ((board[i][j] != lastBoard[i][j] && board[i][j] == EmptySquare)
4318 DrawSquare(i, j, board[i][j], 0);
4319 damage[i][j] = False;
4322 /* Second pass -- Draw piece(s) in new position and flash them */
4323 for (i = 0; i < BOARD_HEIGHT; i++)
4324 for (j = 0; j < BOARD_WIDTH; j++)
4325 if (board[i][j] != lastBoard[i][j]) {
4326 DrawSquare(i, j, board[i][j], do_flash);
4330 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4331 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4333 for (i = 0; i < BOARD_HEIGHT; i++)
4334 for (j = 0; j < BOARD_WIDTH; j++) {
4335 DrawSquare(i, j, board[i][j], 0);
4336 damage[i][j] = False;
4340 CopyBoard(lastBoard, board);
4342 lastFlipView = flipView;
4344 /* Draw highlights */
4345 if (pm1X >= 0 && pm1Y >= 0) {
4346 drawHighlight(pm1X, pm1Y, prelineGC);
4348 if (pm2X >= 0 && pm2Y >= 0) {
4349 drawHighlight(pm2X, pm2Y, prelineGC);
4351 if (hi1X >= 0 && hi1Y >= 0) {
4352 drawHighlight(hi1X, hi1Y, highlineGC);
4354 if (hi2X >= 0 && hi2Y >= 0) {
4355 drawHighlight(hi2X, hi2Y, highlineGC);
4358 /* If piece being dragged around board, must redraw that too */
4361 XSync(xDisplay, False);
4366 * event handler for redrawing the board
4368 void DrawPositionProc(w, event, prms, nprms)
4374 XDrawPosition(w, True, NULL);
4379 * event handler for parsing user moves
4381 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4382 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4383 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4384 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4385 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4386 // and at the end FinishMove() to perform the move after optional promotion popups.
4387 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4388 void HandleUserMove(w, event, prms, nprms)
4394 if (w != boardWidget || errorExitStatus != -1) return;
4397 if (event->type == ButtonPress) {
4398 XtPopdown(promotionShell);
4399 XtDestroyWidget(promotionShell);
4400 promotionUp = False;
4408 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4409 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4410 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4413 void AnimateUserMove (Widget w, XEvent * event,
4414 String * params, Cardinal * nParams)
4416 DragPieceMove(event->xmotion.x, event->xmotion.y);
4419 Widget CommentCreate(name, text, mutable, callback, lines)
4421 int /*Boolean*/ mutable;
4422 XtCallbackProc callback;
4426 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4431 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4432 XtGetValues(boardWidget, args, j);
4435 XtSetArg(args[j], XtNresizable, True); j++;
4438 XtCreatePopupShell(name, topLevelShellWidgetClass,
4439 shellWidget, args, j);
4442 XtCreatePopupShell(name, transientShellWidgetClass,
4443 shellWidget, args, j);
4446 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4447 layoutArgs, XtNumber(layoutArgs));
4449 XtCreateManagedWidget("form", formWidgetClass, layout,
4450 formArgs, XtNumber(formArgs));
4454 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4455 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4457 XtSetArg(args[j], XtNstring, text); j++;
4458 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4459 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4460 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4461 XtSetArg(args[j], XtNright, XtChainRight); j++;
4462 XtSetArg(args[j], XtNresizable, True); j++;
4463 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4464 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4465 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4466 XtSetArg(args[j], XtNautoFill, True); j++;
4467 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4469 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4473 XtSetArg(args[j], XtNfromVert, edit); j++;
4474 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4475 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4476 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4477 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4479 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4480 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4483 XtSetArg(args[j], XtNfromVert, edit); j++;
4484 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4485 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4486 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4487 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4488 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4490 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4491 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4494 XtSetArg(args[j], XtNfromVert, edit); j++;
4495 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4496 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4497 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4498 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4499 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4501 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4502 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4505 XtSetArg(args[j], XtNfromVert, edit); j++;
4506 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4507 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4508 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4509 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4511 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4512 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4515 XtSetArg(args[j], XtNfromVert, edit); j++;
4516 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4517 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4518 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4519 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4520 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4522 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4523 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4526 XtRealizeWidget(shell);
4528 if (commentX == -1) {
4531 Dimension pw_height;
4532 Dimension ew_height;
4535 XtSetArg(args[j], XtNheight, &ew_height); j++;
4536 XtGetValues(edit, args, j);
4539 XtSetArg(args[j], XtNheight, &pw_height); j++;
4540 XtGetValues(shell, args, j);
4541 commentH = pw_height + (lines - 1) * ew_height;
4542 commentW = bw_width - 16;
4544 XSync(xDisplay, False);
4546 /* This code seems to tickle an X bug if it is executed too soon
4547 after xboard starts up. The coordinates get transformed as if
4548 the main window was positioned at (0, 0).
4550 XtTranslateCoords(shellWidget,
4551 (bw_width - commentW) / 2, 0 - commentH / 2,
4552 &commentX, &commentY);
4554 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4555 RootWindowOfScreen(XtScreen(shellWidget)),
4556 (bw_width - commentW) / 2, 0 - commentH / 2,
4561 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4564 XtSetArg(args[j], XtNheight, commentH); j++;
4565 XtSetArg(args[j], XtNwidth, commentW); j++;
4566 XtSetArg(args[j], XtNx, commentX); j++;
4567 XtSetArg(args[j], XtNy, commentY); j++;
4568 XtSetValues(shell, args, j);
4569 XtSetKeyboardFocus(shell, edit);
4574 /* Used for analysis window and ICS input window */
4575 Widget MiscCreate(name, text, mutable, callback, lines)
4577 int /*Boolean*/ mutable;
4578 XtCallbackProc callback;
4582 Widget shell, layout, form, edit;
4584 Dimension bw_width, pw_height, ew_height, w, h;
4590 XtSetArg(args[j], XtNresizable, True); j++;
4593 XtCreatePopupShell(name, topLevelShellWidgetClass,
4594 shellWidget, args, j);
4597 XtCreatePopupShell(name, transientShellWidgetClass,
4598 shellWidget, args, j);
4601 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4602 layoutArgs, XtNumber(layoutArgs));
4604 XtCreateManagedWidget("form", formWidgetClass, layout,
4605 formArgs, XtNumber(formArgs));
4609 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4610 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4612 XtSetArg(args[j], XtNstring, text); j++;
4613 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4614 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4615 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4616 XtSetArg(args[j], XtNright, XtChainRight); j++;
4617 XtSetArg(args[j], XtNresizable, True); j++;
4618 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4619 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4620 XtSetArg(args[j], XtNautoFill, True); j++;
4621 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4623 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4625 XtRealizeWidget(shell);
4628 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4629 XtGetValues(boardWidget, args, j);
4632 XtSetArg(args[j], XtNheight, &ew_height); j++;
4633 XtGetValues(edit, args, j);
4636 XtSetArg(args[j], XtNheight, &pw_height); j++;
4637 XtGetValues(shell, args, j);
4638 h = pw_height + (lines - 1) * ew_height;
4641 XSync(xDisplay, False);
4643 /* This code seems to tickle an X bug if it is executed too soon
4644 after xboard starts up. The coordinates get transformed as if
4645 the main window was positioned at (0, 0).
4647 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4649 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4650 RootWindowOfScreen(XtScreen(shellWidget)),
4651 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4655 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4658 XtSetArg(args[j], XtNheight, h); j++;
4659 XtSetArg(args[j], XtNwidth, w); j++;
4660 XtSetArg(args[j], XtNx, x); j++;
4661 XtSetArg(args[j], XtNy, y); j++;
4662 XtSetValues(shell, args, j);
4668 static int savedIndex; /* gross that this is global */
4670 void EditCommentPopUp(index, title, text)
4679 if (text == NULL) text = "";
4681 if (editShell == NULL) {
4683 CommentCreate(title, text, True, EditCommentCallback, 4);
4684 XtRealizeWidget(editShell);
4685 CatchDeleteWindow(editShell, "EditCommentPopDown");
4687 edit = XtNameToWidget(editShell, "*form.text");
4689 XtSetArg(args[j], XtNstring, text); j++;
4690 XtSetValues(edit, args, j);
4692 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4693 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4694 XtSetValues(editShell, args, j);
4697 XtPopup(editShell, XtGrabNone);
4701 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4702 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4706 void EditCommentCallback(w, client_data, call_data)
4708 XtPointer client_data, call_data;
4716 XtSetArg(args[j], XtNlabel, &name); j++;
4717 XtGetValues(w, args, j);
4719 if (strcmp(name, _("ok")) == 0) {
4720 edit = XtNameToWidget(editShell, "*form.text");
4722 XtSetArg(args[j], XtNstring, &val); j++;
4723 XtGetValues(edit, args, j);
4724 ReplaceComment(savedIndex, val);
4725 EditCommentPopDown();
4726 } else if (strcmp(name, _("cancel")) == 0) {
4727 EditCommentPopDown();
4728 } else if (strcmp(name, _("clear")) == 0) {
4729 edit = XtNameToWidget(editShell, "*form.text");
4730 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4731 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4735 void EditCommentPopDown()
4740 if (!editUp) return;
4742 XtSetArg(args[j], XtNx, &commentX); j++;
4743 XtSetArg(args[j], XtNy, &commentY); j++;
4744 XtSetArg(args[j], XtNheight, &commentH); j++;
4745 XtSetArg(args[j], XtNwidth, &commentW); j++;
4746 XtGetValues(editShell, args, j);
4747 XtPopdown(editShell);
4750 XtSetArg(args[j], XtNleftBitmap, None); j++;
4751 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4755 void ICSInputBoxPopUp()
4760 char *title = _("ICS Input");
4763 if (ICSInputShell == NULL) {
4764 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
4765 tr = XtParseTranslationTable(ICSInputTranslations);
4766 edit = XtNameToWidget(ICSInputShell, "*form.text");
4767 XtOverrideTranslations(edit, tr);
4768 XtRealizeWidget(ICSInputShell);
4769 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
4772 edit = XtNameToWidget(ICSInputShell, "*form.text");
4774 XtSetArg(args[j], XtNstring, ""); j++;
4775 XtSetValues(edit, args, j);
4777 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4778 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4779 XtSetValues(ICSInputShell, args, j);
4782 XtPopup(ICSInputShell, XtGrabNone);
4783 XtSetKeyboardFocus(ICSInputShell, edit);
4785 ICSInputBoxUp = True;
4787 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4788 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4792 void ICSInputSendText()
4799 edit = XtNameToWidget(ICSInputShell, "*form.text");
4801 XtSetArg(args[j], XtNstring, &val); j++;
4802 XtGetValues(edit, args, j);
4803 SendMultiLineToICS(val);
4804 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4805 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4808 void ICSInputBoxPopDown()
4813 if (!ICSInputBoxUp) return;
4815 XtPopdown(ICSInputShell);
4816 ICSInputBoxUp = False;
4818 XtSetArg(args[j], XtNleftBitmap, None); j++;
4819 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4823 void CommentPopUp(title, text)
4830 if (commentShell == NULL) {
4832 CommentCreate(title, text, False, CommentCallback, 4);
4833 XtRealizeWidget(commentShell);
4834 CatchDeleteWindow(commentShell, "CommentPopDown");
4836 edit = XtNameToWidget(commentShell, "*form.text");
4838 XtSetArg(args[j], XtNstring, text); j++;
4839 XtSetValues(edit, args, j);
4841 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4842 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4843 XtSetValues(commentShell, args, j);
4846 XtPopup(commentShell, XtGrabNone);
4847 XSync(xDisplay, False);
4852 void CommentCallback(w, client_data, call_data)
4854 XtPointer client_data, call_data;
4861 XtSetArg(args[j], XtNlabel, &name); j++;
4862 XtGetValues(w, args, j);
4864 if (strcmp(name, _("close")) == 0) {
4866 } else if (strcmp(name, _("edit")) == 0) {
4873 void CommentPopDown()
4878 if (!commentUp) return;
4880 XtSetArg(args[j], XtNx, &commentX); j++;
4881 XtSetArg(args[j], XtNy, &commentY); j++;
4882 XtSetArg(args[j], XtNwidth, &commentW); j++;
4883 XtSetArg(args[j], XtNheight, &commentH); j++;
4884 XtGetValues(commentShell, args, j);
4885 XtPopdown(commentShell);
4886 XSync(xDisplay, False);
4890 void FileNamePopUp(label, def, proc, openMode)
4897 Widget popup, layout, dialog, edit;
4903 fileProc = proc; /* I can't see a way not */
4904 fileOpenMode = openMode; /* to use globals here */
4907 XtSetArg(args[i], XtNresizable, True); i++;
4908 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
4909 XtSetArg(args[i], XtNtitle, XtNewString(_("File name prompt"))); i++;
4910 fileNameShell = popup =
4911 XtCreatePopupShell("File name prompt", transientShellWidgetClass,
4912 shellWidget, args, i);
4915 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
4916 layoutArgs, XtNumber(layoutArgs));
4919 XtSetArg(args[i], XtNlabel, label); i++;
4920 XtSetArg(args[i], XtNvalue, def); i++;
4921 XtSetArg(args[i], XtNborderWidth, 0); i++;
4922 dialog = XtCreateManagedWidget("fileName", dialogWidgetClass,
4925 XawDialogAddButton(dialog, _("ok"), FileNameCallback, (XtPointer) dialog);
4926 XawDialogAddButton(dialog, _("cancel"), FileNameCallback,
4927 (XtPointer) dialog);
4929 XtRealizeWidget(popup);
4930 CatchDeleteWindow(popup, "FileNamePopDown");
4932 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
4933 &x, &y, &win_x, &win_y, &mask);
4935 XtSetArg(args[0], XtNx, x - 10);
4936 XtSetArg(args[1], XtNy, y - 30);
4937 XtSetValues(popup, args, 2);
4939 XtPopup(popup, XtGrabExclusive);
4942 edit = XtNameToWidget(dialog, "*value");
4943 XtSetKeyboardFocus(popup, edit);
4946 void FileNamePopDown()
4948 if (!filenameUp) return;
4949 XtPopdown(fileNameShell);
4950 XtDestroyWidget(fileNameShell);
4955 void FileNameCallback(w, client_data, call_data)
4957 XtPointer client_data, call_data;
4962 XtSetArg(args[0], XtNlabel, &name);
4963 XtGetValues(w, args, 1);
4965 if (strcmp(name, _("cancel")) == 0) {
4970 FileNameAction(w, NULL, NULL, NULL);
4973 void FileNameAction(w, event, prms, nprms)
4985 name = XawDialogGetValueString(w = XtParent(w));
4987 if ((name != NULL) && (*name != NULLCHAR)) {
4989 XtPopdown(w = XtParent(XtParent(w)));
4993 p = strrchr(buf, ' ');
5000 fullname = ExpandPathName(buf);
5002 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5005 f = fopen(fullname, fileOpenMode);
5007 DisplayError(_("Failed to open file"), errno);
5009 (void) (*fileProc)(f, index, buf);
5016 XtPopdown(w = XtParent(XtParent(w)));
5022 void PromotionPopUp()
5025 Widget dialog, layout;
5027 Dimension bw_width, pw_width;
5031 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5032 XtGetValues(boardWidget, args, j);
5035 XtSetArg(args[j], XtNresizable, True); j++;
5036 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5038 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5039 shellWidget, args, j);
5041 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5042 layoutArgs, XtNumber(layoutArgs));
5045 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5046 XtSetArg(args[j], XtNborderWidth, 0); j++;
5047 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5050 if(gameInfo.variant != VariantShogi) {
5051 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5052 (XtPointer) dialog);
5053 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5054 (XtPointer) dialog);
5055 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5056 (XtPointer) dialog);
5057 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5058 (XtPointer) dialog);
5059 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5060 gameInfo.variant == VariantGiveaway) {
5061 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5062 (XtPointer) dialog);
5064 if(gameInfo.variant == VariantCapablanca ||
5065 gameInfo.variant == VariantGothic ||
5066 gameInfo.variant == VariantCapaRandom) {
5067 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5068 (XtPointer) dialog);
5069 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5070 (XtPointer) dialog);
5072 } else // [HGM] shogi
5074 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5075 (XtPointer) dialog);
5076 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5077 (XtPointer) dialog);
5079 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5080 (XtPointer) dialog);
5082 XtRealizeWidget(promotionShell);
5083 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5086 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5087 XtGetValues(promotionShell, args, j);
5089 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5090 lineGap + squareSize/3 +
5091 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5092 0 : 6*(squareSize + lineGap)), &x, &y);
5095 XtSetArg(args[j], XtNx, x); j++;
5096 XtSetArg(args[j], XtNy, y); j++;
5097 XtSetValues(promotionShell, args, j);
5099 XtPopup(promotionShell, XtGrabNone);
5104 void PromotionPopDown()
5106 if (!promotionUp) return;
5107 XtPopdown(promotionShell);
5108 XtDestroyWidget(promotionShell);
5109 promotionUp = False;
5112 void PromotionCallback(w, client_data, call_data)
5114 XtPointer client_data, call_data;
5120 XtSetArg(args[0], XtNlabel, &name);
5121 XtGetValues(w, args, 1);
5125 if (fromX == -1) return;
5127 if (strcmp(name, _("cancel")) == 0) {
5131 } else if (strcmp(name, _("Knight")) == 0) {
5133 } else if (strcmp(name, _("Promote")) == 0) {
5135 } else if (strcmp(name, _("Defer")) == 0) {
5138 promoChar = ToLower(name[0]);
5141 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5143 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5144 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5149 void ErrorCallback(w, client_data, call_data)
5151 XtPointer client_data, call_data;
5154 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5156 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5162 if (!errorUp) return;
5164 XtPopdown(errorShell);
5165 XtDestroyWidget(errorShell);
5166 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5169 void ErrorPopUp(title, label, modal)
5170 char *title, *label;
5174 Widget dialog, layout;
5178 Dimension bw_width, pw_width;
5179 Dimension pw_height;
5183 XtSetArg(args[i], XtNresizable, True); i++;
5184 XtSetArg(args[i], XtNtitle, title); i++;
5186 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5187 shellWidget, args, i);
5189 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5190 layoutArgs, XtNumber(layoutArgs));
5193 XtSetArg(args[i], XtNlabel, label); i++;
5194 XtSetArg(args[i], XtNborderWidth, 0); i++;
5195 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5198 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5200 XtRealizeWidget(errorShell);
5201 CatchDeleteWindow(errorShell, "ErrorPopDown");
5204 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5205 XtGetValues(boardWidget, args, i);
5207 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5208 XtSetArg(args[i], XtNheight, &pw_height); i++;
5209 XtGetValues(errorShell, args, i);
5212 /* This code seems to tickle an X bug if it is executed too soon
5213 after xboard starts up. The coordinates get transformed as if
5214 the main window was positioned at (0, 0).
5216 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5217 0 - pw_height + squareSize / 3, &x, &y);
5219 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5220 RootWindowOfScreen(XtScreen(boardWidget)),
5221 (bw_width - pw_width) / 2,
5222 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5226 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5229 XtSetArg(args[i], XtNx, x); i++;
5230 XtSetArg(args[i], XtNy, y); i++;
5231 XtSetValues(errorShell, args, i);
5234 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5237 /* Disable all user input other than deleting the window */
5238 static int frozen = 0;
5242 /* Grab by a widget that doesn't accept input */
5243 XtAddGrab(messageWidget, TRUE, FALSE);
5247 /* Undo a FreezeUI */
5250 if (!frozen) return;
5251 XtRemoveGrab(messageWidget);
5255 char *ModeToWidgetName(mode)
5259 case BeginningOfGame:
5260 if (appData.icsActive)
5261 return "menuMode.ICS Client";
5262 else if (appData.noChessProgram ||
5263 *appData.cmailGameName != NULLCHAR)
5264 return "menuMode.Edit Game";
5266 return "menuMode.Machine Black";
5267 case MachinePlaysBlack:
5268 return "menuMode.Machine Black";
5269 case MachinePlaysWhite:
5270 return "menuMode.Machine White";
5272 return "menuMode.Analysis Mode";
5274 return "menuMode.Analyze File";
5275 case TwoMachinesPlay:
5276 return "menuMode.Two Machines";
5278 return "menuMode.Edit Game";
5279 case PlayFromGameFile:
5280 return "menuFile.Load Game";
5282 return "menuMode.Edit Position";
5284 return "menuMode.Training";
5285 case IcsPlayingWhite:
5286 case IcsPlayingBlack:
5290 return "menuMode.ICS Client";
5297 void ModeHighlight()
5300 static int oldPausing = FALSE;
5301 static GameMode oldmode = (GameMode) -1;
5304 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5306 if (pausing != oldPausing) {
5307 oldPausing = pausing;
5309 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5311 XtSetArg(args[0], XtNleftBitmap, None);
5313 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5316 if (appData.showButtonBar) {
5317 /* Always toggle, don't set. Previous code messes up when
5318 invoked while the button is pressed, as releasing it
5319 toggles the state again. */
5322 XtSetArg(args[0], XtNbackground, &oldbg);
5323 XtSetArg(args[1], XtNforeground, &oldfg);
5324 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5326 XtSetArg(args[0], XtNbackground, oldfg);
5327 XtSetArg(args[1], XtNforeground, oldbg);
5329 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5333 wname = ModeToWidgetName(oldmode);
5334 if (wname != NULL) {
5335 XtSetArg(args[0], XtNleftBitmap, None);
5336 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5338 wname = ModeToWidgetName(gameMode);
5339 if (wname != NULL) {
5340 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5341 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5345 /* Maybe all the enables should be handled here, not just this one */
5346 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5347 gameMode == Training || gameMode == PlayFromGameFile);
5352 * Button/menu procedures
5354 void ResetProc(w, event, prms, nprms)
5363 int LoadGamePopUp(f, gameNumber, title)
5368 cmailMsgLoaded = FALSE;
5369 if (gameNumber == 0) {
5370 int error = GameListBuild(f);
5372 DisplayError(_("Cannot build game list"), error);
5373 } else if (!ListEmpty(&gameList) &&
5374 ((ListGame *) gameList.tailPred)->number > 1) {
5375 GameListPopUp(f, title);
5381 return LoadGame(f, gameNumber, title, FALSE);
5384 void LoadGameProc(w, event, prms, nprms)
5390 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5393 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5396 void LoadNextGameProc(w, event, prms, nprms)
5405 void LoadPrevGameProc(w, event, prms, nprms)
5414 void ReloadGameProc(w, event, prms, nprms)
5423 void LoadNextPositionProc(w, event, prms, nprms)
5432 void LoadPrevPositionProc(w, event, prms, nprms)
5441 void ReloadPositionProc(w, event, prms, nprms)
5450 void LoadPositionProc(w, event, prms, nprms)
5456 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5459 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5462 void SaveGameProc(w, event, prms, nprms)
5468 FileNamePopUp(_("Save game file name?"),
5469 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5473 void SavePositionProc(w, event, prms, nprms)
5479 FileNamePopUp(_("Save position file name?"),
5480 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5484 void ReloadCmailMsgProc(w, event, prms, nprms)
5490 ReloadCmailMsgEvent(FALSE);
5493 void MailMoveProc(w, event, prms, nprms)
5502 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5503 static char *selected_fen_position=NULL;
5506 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5507 Atom *type_return, XtPointer *value_return,
5508 unsigned long *length_return, int *format_return)
5510 char *selection_tmp;
5512 if (!selected_fen_position) return False; /* should never happen */
5513 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5514 /* note: since no XtSelectionDoneProc was registered, Xt will
5515 * automatically call XtFree on the value returned. So have to
5516 * make a copy of it allocated with XtMalloc */
5517 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5518 strcpy(selection_tmp, selected_fen_position);
5520 *value_return=selection_tmp;
5521 *length_return=strlen(selection_tmp);
5522 *type_return=*target;
5523 *format_return = 8; /* bits per byte */
5525 } else if (*target == XA_TARGETS(xDisplay)) {
5526 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5527 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5528 targets_tmp[1] = XA_STRING;
5529 *value_return = targets_tmp;
5530 *type_return = XA_ATOM;
5532 *format_return = 8 * sizeof(Atom);
5533 if (*format_return > 32) {
5534 *length_return *= *format_return / 32;
5535 *format_return = 32;
5543 /* note: when called from menu all parameters are NULL, so no clue what the
5544 * Widget which was clicked on was, or what the click event was
5546 void CopyPositionProc(w, event, prms, nprms)
5553 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5554 * have a notion of a position that is selected but not copied.
5555 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5557 if (selected_fen_position) free(selected_fen_position);
5558 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5559 if (!selected_fen_position) return;
5560 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5562 SendPositionSelection,
5563 NULL/* lose_ownership_proc */ ,
5564 NULL/* transfer_done_proc */);
5565 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5567 SendPositionSelection,
5568 NULL/* lose_ownership_proc */ ,
5569 NULL/* transfer_done_proc */);
5572 /* function called when the data to Paste is ready */
5574 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5575 Atom *type, XtPointer value, unsigned long *len, int *format)
5578 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5579 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5580 EditPositionPasteFEN(fenstr);
5584 /* called when Paste Position button is pressed,
5585 * all parameters will be NULL */
5586 void PastePositionProc(w, event, prms, nprms)
5592 XtGetSelectionValue(menuBarWidget,
5593 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5594 /* (XtSelectionCallbackProc) */ PastePositionCB,
5595 NULL, /* client_data passed to PastePositionCB */
5597 /* better to use the time field from the event that triggered the
5598 * call to this function, but that isn't trivial to get
5606 SendGameSelection(Widget w, Atom *selection, Atom *target,
5607 Atom *type_return, XtPointer *value_return,
5608 unsigned long *length_return, int *format_return)
5610 char *selection_tmp;
5612 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5613 FILE* f = fopen(gameCopyFilename, "r");
5616 if (f == NULL) return False;
5620 selection_tmp = XtMalloc(len + 1);
5621 count = fread(selection_tmp, 1, len, f);
5623 XtFree(selection_tmp);
5626 selection_tmp[len] = NULLCHAR;
5627 *value_return = selection_tmp;
5628 *length_return = len;
5629 *type_return = *target;
5630 *format_return = 8; /* bits per byte */
5632 } else if (*target == XA_TARGETS(xDisplay)) {
5633 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5634 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5635 targets_tmp[1] = XA_STRING;
5636 *value_return = targets_tmp;
5637 *type_return = XA_ATOM;
5639 *format_return = 8 * sizeof(Atom);
5640 if (*format_return > 32) {
5641 *length_return *= *format_return / 32;
5642 *format_return = 32;
5650 /* note: when called from menu all parameters are NULL, so no clue what the
5651 * Widget which was clicked on was, or what the click event was
5653 void CopyGameProc(w, event, prms, nprms)
5661 ret = SaveGameToFile(gameCopyFilename, FALSE);
5665 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5666 * have a notion of a game that is selected but not copied.
5667 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5669 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5672 NULL/* lose_ownership_proc */ ,
5673 NULL/* transfer_done_proc */);
5674 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5677 NULL/* lose_ownership_proc */ ,
5678 NULL/* transfer_done_proc */);
5681 /* function called when the data to Paste is ready */
5683 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5684 Atom *type, XtPointer value, unsigned long *len, int *format)
5687 if (value == NULL || *len == 0) {
5688 return; /* nothing had been selected to copy */
5690 f = fopen(gamePasteFilename, "w");
5692 DisplayError(_("Can't open temp file"), errno);
5695 fwrite(value, 1, *len, f);
5698 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5701 /* called when Paste Game button is pressed,
5702 * all parameters will be NULL */
5703 void PasteGameProc(w, event, prms, nprms)
5709 XtGetSelectionValue(menuBarWidget,
5710 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5711 /* (XtSelectionCallbackProc) */ PasteGameCB,
5712 NULL, /* client_data passed to PasteGameCB */
5714 /* better to use the time field from the event that triggered the
5715 * call to this function, but that isn't trivial to get
5725 SaveGameProc(NULL, NULL, NULL, NULL);
5729 void QuitProc(w, event, prms, nprms)
5738 void PauseProc(w, event, prms, nprms)
5748 void MachineBlackProc(w, event, prms, nprms)
5754 MachineBlackEvent();
5757 void MachineWhiteProc(w, event, prms, nprms)
5763 MachineWhiteEvent();
5766 void AnalyzeModeProc(w, event, prms, nprms)
5774 if (!first.analysisSupport) {
5775 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5776 DisplayError(buf, 0);
5779 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5780 if (appData.icsActive) {
5781 if (gameMode != IcsObserving) {
5782 sprintf(buf,_("You are not observing a game"));
5783 DisplayError(buf, 0);
5785 if (appData.icsEngineAnalyze) {
5786 if (appData.debugMode)
5787 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5793 /* if enable, use want disable icsEngineAnalyze */
5794 if (appData.icsEngineAnalyze) {
5799 appData.icsEngineAnalyze = TRUE;
5800 if (appData.debugMode)
5801 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5803 if (!appData.showThinking)
5804 ShowThinkingProc(w,event,prms,nprms);
5809 void AnalyzeFileProc(w, event, prms, nprms)
5815 if (!first.analysisSupport) {
5817 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5818 DisplayError(buf, 0);
5823 if (!appData.showThinking)
5824 ShowThinkingProc(w,event,prms,nprms);
5827 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
5828 AnalysisPeriodicEvent(1);
5831 void TwoMachinesProc(w, event, prms, nprms)
5840 void IcsClientProc(w, event, prms, nprms)
5849 void EditGameProc(w, event, prms, nprms)
5858 void EditPositionProc(w, event, prms, nprms)
5864 EditPositionEvent();
5867 void TrainingProc(w, event, prms, nprms)
5876 void EditCommentProc(w, event, prms, nprms)
5883 EditCommentPopDown();
5889 void IcsInputBoxProc(w, event, prms, nprms)
5895 if (ICSInputBoxUp) {
5896 ICSInputBoxPopDown();
5902 void AcceptProc(w, event, prms, nprms)
5911 void DeclineProc(w, event, prms, nprms)
5920 void RematchProc(w, event, prms, nprms)
5929 void CallFlagProc(w, event, prms, nprms)
5938 void DrawProc(w, event, prms, nprms)
5947 void AbortProc(w, event, prms, nprms)
5956 void AdjournProc(w, event, prms, nprms)
5965 void ResignProc(w, event, prms, nprms)
5974 void AdjuWhiteProc(w, event, prms, nprms)
5980 UserAdjudicationEvent(+1);
5983 void AdjuBlackProc(w, event, prms, nprms)
5989 UserAdjudicationEvent(-1);
5992 void AdjuDrawProc(w, event, prms, nprms)
5998 UserAdjudicationEvent(0);
6001 void EnterKeyProc(w, event, prms, nprms)
6007 if (ICSInputBoxUp == True)
6011 void StopObservingProc(w, event, prms, nprms)
6017 StopObservingEvent();
6020 void StopExaminingProc(w, event, prms, nprms)
6026 StopExaminingEvent();
6030 void ForwardProc(w, event, prms, nprms)
6040 void BackwardProc(w, event, prms, nprms)
6049 void ToStartProc(w, event, prms, nprms)
6058 void ToEndProc(w, event, prms, nprms)
6067 void RevertProc(w, event, prms, nprms)
6076 void TruncateGameProc(w, event, prms, nprms)
6082 TruncateGameEvent();
6084 void RetractMoveProc(w, event, prms, nprms)
6093 void MoveNowProc(w, event, prms, nprms)
6103 void AlwaysQueenProc(w, event, prms, nprms)
6111 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6113 if (appData.alwaysPromoteToQueen) {
6114 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6116 XtSetArg(args[0], XtNleftBitmap, None);
6118 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6122 void AnimateDraggingProc(w, event, prms, nprms)
6130 appData.animateDragging = !appData.animateDragging;
6132 if (appData.animateDragging) {
6133 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6136 XtSetArg(args[0], XtNleftBitmap, None);
6138 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6142 void AnimateMovingProc(w, event, prms, nprms)
6150 appData.animate = !appData.animate;
6152 if (appData.animate) {
6153 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6156 XtSetArg(args[0], XtNleftBitmap, None);
6158 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6162 void AutocommProc(w, event, prms, nprms)
6170 appData.autoComment = !appData.autoComment;
6172 if (appData.autoComment) {
6173 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6175 XtSetArg(args[0], XtNleftBitmap, None);
6177 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6182 void AutoflagProc(w, event, prms, nprms)
6190 appData.autoCallFlag = !appData.autoCallFlag;
6192 if (appData.autoCallFlag) {
6193 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6195 XtSetArg(args[0], XtNleftBitmap, None);
6197 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6201 void AutoflipProc(w, event, prms, nprms)
6209 appData.autoFlipView = !appData.autoFlipView;
6211 if (appData.autoFlipView) {
6212 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6214 XtSetArg(args[0], XtNleftBitmap, None);
6216 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6220 void AutobsProc(w, event, prms, nprms)
6228 appData.autoObserve = !appData.autoObserve;
6230 if (appData.autoObserve) {
6231 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6233 XtSetArg(args[0], XtNleftBitmap, None);
6235 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6239 void AutoraiseProc(w, event, prms, nprms)
6247 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6249 if (appData.autoRaiseBoard) {
6250 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6252 XtSetArg(args[0], XtNleftBitmap, None);
6254 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6258 void AutosaveProc(w, event, prms, nprms)
6266 appData.autoSaveGames = !appData.autoSaveGames;
6268 if (appData.autoSaveGames) {
6269 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6271 XtSetArg(args[0], XtNleftBitmap, None);
6273 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6277 void BlindfoldProc(w, event, prms, nprms)
6285 appData.blindfold = !appData.blindfold;
6287 if (appData.blindfold) {
6288 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6290 XtSetArg(args[0], XtNleftBitmap, None);
6292 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6295 DrawPosition(True, NULL);
6298 void TestLegalityProc(w, event, prms, nprms)
6306 appData.testLegality = !appData.testLegality;
6308 if (appData.testLegality) {
6309 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6311 XtSetArg(args[0], XtNleftBitmap, None);
6313 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6318 void FlashMovesProc(w, event, prms, nprms)
6326 if (appData.flashCount == 0) {
6327 appData.flashCount = 3;
6329 appData.flashCount = -appData.flashCount;
6332 if (appData.flashCount > 0) {
6333 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6335 XtSetArg(args[0], XtNleftBitmap, None);
6337 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6341 void FlipViewProc(w, event, prms, nprms)
6347 flipView = !flipView;
6348 DrawPosition(True, NULL);
6351 void GetMoveListProc(w, event, prms, nprms)
6359 appData.getMoveList = !appData.getMoveList;
6361 if (appData.getMoveList) {
6362 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6365 XtSetArg(args[0], XtNleftBitmap, None);
6367 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6372 void HighlightDraggingProc(w, event, prms, nprms)
6380 appData.highlightDragging = !appData.highlightDragging;
6382 if (appData.highlightDragging) {
6383 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6385 XtSetArg(args[0], XtNleftBitmap, None);
6387 XtSetValues(XtNameToWidget(menuBarWidget,
6388 "menuOptions.Highlight Dragging"), args, 1);
6392 void HighlightLastMoveProc(w, event, prms, nprms)
6400 appData.highlightLastMove = !appData.highlightLastMove;
6402 if (appData.highlightLastMove) {
6403 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6405 XtSetArg(args[0], XtNleftBitmap, None);
6407 XtSetValues(XtNameToWidget(menuBarWidget,
6408 "menuOptions.Highlight Last Move"), args, 1);
6411 void IcsAlarmProc(w, event, prms, nprms)
6419 appData.icsAlarm = !appData.icsAlarm;
6421 if (appData.icsAlarm) {
6422 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6424 XtSetArg(args[0], XtNleftBitmap, None);
6426 XtSetValues(XtNameToWidget(menuBarWidget,
6427 "menuOptions.ICS Alarm"), args, 1);
6430 void MoveSoundProc(w, event, prms, nprms)
6438 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6440 if (appData.ringBellAfterMoves) {
6441 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6443 XtSetArg(args[0], XtNleftBitmap, None);
6445 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6450 void OldSaveStyleProc(w, event, prms, nprms)
6458 appData.oldSaveStyle = !appData.oldSaveStyle;
6460 if (appData.oldSaveStyle) {
6461 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6463 XtSetArg(args[0], XtNleftBitmap, None);
6465 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6469 void PeriodicUpdatesProc(w, event, prms, nprms)
6477 PeriodicUpdatesEvent(!appData.periodicUpdates);
6479 if (appData.periodicUpdates) {
6480 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6482 XtSetArg(args[0], XtNleftBitmap, None);
6484 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6488 void PonderNextMoveProc(w, event, prms, nprms)
6496 PonderNextMoveEvent(!appData.ponderNextMove);
6498 if (appData.ponderNextMove) {
6499 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6501 XtSetArg(args[0], XtNleftBitmap, None);
6503 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6507 void PopupExitMessageProc(w, event, prms, nprms)
6515 appData.popupExitMessage = !appData.popupExitMessage;
6517 if (appData.popupExitMessage) {
6518 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6520 XtSetArg(args[0], XtNleftBitmap, None);
6522 XtSetValues(XtNameToWidget(menuBarWidget,
6523 "menuOptions.Popup Exit Message"), args, 1);
6526 void PopupMoveErrorsProc(w, event, prms, nprms)
6534 appData.popupMoveErrors = !appData.popupMoveErrors;
6536 if (appData.popupMoveErrors) {
6537 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6539 XtSetArg(args[0], XtNleftBitmap, None);
6541 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6545 void PremoveProc(w, event, prms, nprms)
6553 appData.premove = !appData.premove;
6555 if (appData.premove) {
6556 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6558 XtSetArg(args[0], XtNleftBitmap, None);
6560 XtSetValues(XtNameToWidget(menuBarWidget,
6561 "menuOptions.Premove"), args, 1);
6564 void QuietPlayProc(w, event, prms, nprms)
6572 appData.quietPlay = !appData.quietPlay;
6574 if (appData.quietPlay) {
6575 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6577 XtSetArg(args[0], XtNleftBitmap, None);
6579 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6583 void ShowCoordsProc(w, event, prms, nprms)
6591 appData.showCoords = !appData.showCoords;
6593 if (appData.showCoords) {
6594 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6596 XtSetArg(args[0], XtNleftBitmap, None);
6598 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6601 DrawPosition(True, NULL);
6604 void ShowThinkingProc(w, event, prms, nprms)
6610 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6611 ShowThinkingEvent();
6614 void HideThinkingProc(w, event, prms, nprms)
6622 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6623 ShowThinkingEvent();
6625 if (appData.hideThinkingFromHuman) {
6626 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6628 XtSetArg(args[0], XtNleftBitmap, None);
6630 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6634 void SaveOnExitProc(w, event, prms, nprms)
6642 saveSettingsOnExit = !saveSettingsOnExit;
6644 if (saveSettingsOnExit) {
6645 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6647 XtSetArg(args[0], XtNleftBitmap, None);
6649 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6653 void SaveSettingsProc(w, event, prms, nprms)
6659 SaveSettings(settingsFileName);
6662 void InfoProc(w, event, prms, nprms)
6669 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6674 void ManProc(w, event, prms, nprms)
6682 if (nprms && *nprms > 0)
6686 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6690 void HintProc(w, event, prms, nprms)
6699 void BookProc(w, event, prms, nprms)
6708 void AboutProc(w, event, prms, nprms)
6716 char *zippy = " (with Zippy code)";
6720 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6721 programVersion, zippy,
6722 "Copyright 1991 Digital Equipment Corporation",
6723 "Enhancements Copyright 1992-2009 Free Software Foundation",
6724 "Enhancements Copyright 2005 Alessandro Scotti",
6725 PACKAGE, " is free software and carries NO WARRANTY;",
6726 "see the file COPYING for more information.");
6727 ErrorPopUp(_("About XBoard"), buf, FALSE);
6730 void DebugProc(w, event, prms, nprms)
6736 appData.debugMode = !appData.debugMode;
6739 void AboutGameProc(w, event, prms, nprms)
6748 void NothingProc(w, event, prms, nprms)
6757 void Iconify(w, event, prms, nprms)
6766 XtSetArg(args[0], XtNiconic, True);
6767 XtSetValues(shellWidget, args, 1);
6770 void DisplayMessage(message, extMessage)
6771 char *message, *extMessage;
6773 /* display a message in the message widget */
6782 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
6787 message = extMessage;
6791 /* need to test if messageWidget already exists, since this function
6792 can also be called during the startup, if for example a Xresource
6793 is not set up correctly */
6796 XtSetArg(arg, XtNlabel, message);
6797 XtSetValues(messageWidget, &arg, 1);
6803 void DisplayTitle(text)
6808 char title[MSG_SIZ];
6811 if (text == NULL) text = "";
6813 if (appData.titleInWindow) {
6815 XtSetArg(args[i], XtNlabel, text); i++;
6816 XtSetValues(titleWidget, args, i);
6819 if (*text != NULLCHAR) {
6821 strcpy(title, text);
6822 } else if (appData.icsActive) {
6823 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
6824 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
6825 } else if (appData.cmailGameName[0] != NULLCHAR) {
6826 snprintf(icon, sizeof(icon), "%s", "CMail");
6827 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
6829 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
6830 } else if (gameInfo.variant == VariantGothic) {
6831 strcpy(icon, programName);
6832 strcpy(title, GOTHIC);
6835 } else if (gameInfo.variant == VariantFalcon) {
6836 strcpy(icon, programName);
6837 strcpy(title, FALCON);
6839 } else if (appData.noChessProgram) {
6840 strcpy(icon, programName);
6841 strcpy(title, programName);
6843 strcpy(icon, first.tidy);
6844 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
6847 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
6848 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
6849 XtSetValues(shellWidget, args, i);
6853 void DisplayError(message, error)
6860 if (appData.debugMode || appData.matchMode) {
6861 fprintf(stderr, "%s: %s\n", programName, message);
6864 if (appData.debugMode || appData.matchMode) {
6865 fprintf(stderr, "%s: %s: %s\n",
6866 programName, message, strerror(error));
6868 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6871 ErrorPopUp(_("Error"), message, FALSE);
6875 void DisplayMoveError(message)
6880 DrawPosition(FALSE, NULL);
6881 if (appData.debugMode || appData.matchMode) {
6882 fprintf(stderr, "%s: %s\n", programName, message);
6884 if (appData.popupMoveErrors) {
6885 ErrorPopUp(_("Error"), message, FALSE);
6887 DisplayMessage(message, "");
6892 void DisplayFatalError(message, error, status)
6898 errorExitStatus = status;
6900 fprintf(stderr, "%s: %s\n", programName, message);
6902 fprintf(stderr, "%s: %s: %s\n",
6903 programName, message, strerror(error));
6904 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6907 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
6908 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
6914 void DisplayInformation(message)
6918 ErrorPopUp(_("Information"), message, TRUE);
6921 void DisplayNote(message)
6925 ErrorPopUp(_("Note"), message, FALSE);
6929 NullXErrorCheck(dpy, error_event)
6931 XErrorEvent *error_event;
6936 void DisplayIcsInteractionTitle(message)
6939 if (oldICSInteractionTitle == NULL) {
6940 /* Magic to find the old window title, adapted from vim */
6941 char *wina = getenv("WINDOWID");
6943 Window win = (Window) atoi(wina);
6944 Window root, parent, *children;
6945 unsigned int nchildren;
6946 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
6948 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
6949 if (!XQueryTree(xDisplay, win, &root, &parent,
6950 &children, &nchildren)) break;
6951 if (children) XFree((void *)children);
6952 if (parent == root || parent == 0) break;
6955 XSetErrorHandler(oldHandler);
6957 if (oldICSInteractionTitle == NULL) {
6958 oldICSInteractionTitle = "xterm";
6961 printf("\033]0;%s\007", message);
6965 char pendingReplyPrefix[MSG_SIZ];
6966 ProcRef pendingReplyPR;
6968 void AskQuestionProc(w, event, prms, nprms)
6975 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
6979 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
6982 void AskQuestionPopDown()
6984 if (!askQuestionUp) return;
6985 XtPopdown(askQuestionShell);
6986 XtDestroyWidget(askQuestionShell);
6987 askQuestionUp = False;
6990 void AskQuestionReplyAction(w, event, prms, nprms)
7000 reply = XawDialogGetValueString(w = XtParent(w));
7001 strcpy(buf, pendingReplyPrefix);
7002 if (*buf) strcat(buf, " ");
7005 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7006 AskQuestionPopDown();
7008 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7011 void AskQuestionCallback(w, client_data, call_data)
7013 XtPointer client_data, call_data;
7018 XtSetArg(args[0], XtNlabel, &name);
7019 XtGetValues(w, args, 1);
7021 if (strcmp(name, _("cancel")) == 0) {
7022 AskQuestionPopDown();
7024 AskQuestionReplyAction(w, NULL, NULL, NULL);
7028 void AskQuestion(title, question, replyPrefix, pr)
7029 char *title, *question, *replyPrefix;
7033 Widget popup, layout, dialog, edit;
7039 strcpy(pendingReplyPrefix, replyPrefix);
7040 pendingReplyPR = pr;
7043 XtSetArg(args[i], XtNresizable, True); i++;
7044 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7045 askQuestionShell = popup =
7046 XtCreatePopupShell(title, transientShellWidgetClass,
7047 shellWidget, args, i);
7050 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7051 layoutArgs, XtNumber(layoutArgs));
7054 XtSetArg(args[i], XtNlabel, question); i++;
7055 XtSetArg(args[i], XtNvalue, ""); i++;
7056 XtSetArg(args[i], XtNborderWidth, 0); i++;
7057 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7060 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7061 (XtPointer) dialog);
7062 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7063 (XtPointer) dialog);
7065 XtRealizeWidget(popup);
7066 CatchDeleteWindow(popup, "AskQuestionPopDown");
7068 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7069 &x, &y, &win_x, &win_y, &mask);
7071 XtSetArg(args[0], XtNx, x - 10);
7072 XtSetArg(args[1], XtNy, y - 30);
7073 XtSetValues(popup, args, 2);
7075 XtPopup(popup, XtGrabExclusive);
7076 askQuestionUp = True;
7078 edit = XtNameToWidget(dialog, "*value");
7079 XtSetKeyboardFocus(popup, edit);
7087 if (*name == NULLCHAR) {
7089 } else if (strcmp(name, "$") == 0) {
7090 putc(BELLCHAR, stderr);
7093 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7101 PlaySound(appData.soundMove);
7107 PlaySound(appData.soundIcsWin);
7113 PlaySound(appData.soundIcsLoss);
7119 PlaySound(appData.soundIcsDraw);
7123 PlayIcsUnfinishedSound()
7125 PlaySound(appData.soundIcsUnfinished);
7131 PlaySound(appData.soundIcsAlarm);
7137 system("stty echo");
7143 system("stty -echo");
7147 Colorize(cc, continuation)
7152 int count, outCount, error;
7154 if (textColors[(int)cc].bg > 0) {
7155 if (textColors[(int)cc].fg > 0) {
7156 sprintf(buf, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7157 textColors[(int)cc].fg, textColors[(int)cc].bg);
7159 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7160 textColors[(int)cc].bg);
7163 if (textColors[(int)cc].fg > 0) {
7164 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7165 textColors[(int)cc].fg);
7167 sprintf(buf, "\033[0;%dm", textColors[(int)cc].attr);
7170 count = strlen(buf);
7171 outCount = OutputToProcess(NoProc, buf, count, &error);
7172 if (outCount < count) {
7173 DisplayFatalError(_("Error writing to display"), error, 1);
7176 if (continuation) return;
7179 PlaySound(appData.soundShout);
7182 PlaySound(appData.soundSShout);
7185 PlaySound(appData.soundChannel1);
7188 PlaySound(appData.soundChannel);
7191 PlaySound(appData.soundKibitz);
7194 PlaySound(appData.soundTell);
7196 case ColorChallenge:
7197 PlaySound(appData.soundChallenge);
7200 PlaySound(appData.soundRequest);
7203 PlaySound(appData.soundSeek);
7214 return getpwuid(getuid())->pw_name;
7217 static char *ExpandPathName(path)
7220 static char static_buf[2000];
7221 char *d, *s, buf[2000];
7227 while (*s && isspace(*s))
7236 if (*(s+1) == '/') {
7237 strcpy(d, getpwuid(getuid())->pw_dir);
7242 *strchr(buf, '/') = 0;
7243 pwd = getpwnam(buf);
7246 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7250 strcpy(d, pwd->pw_dir);
7251 strcat(d, strchr(s+1, '/'));
7262 static char host_name[MSG_SIZ];
7264 #if HAVE_GETHOSTNAME
7265 gethostname(host_name, MSG_SIZ);
7267 #else /* not HAVE_GETHOSTNAME */
7268 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7269 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7271 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7273 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7274 #endif /* not HAVE_GETHOSTNAME */
7277 XtIntervalId delayedEventTimerXID = 0;
7278 DelayedEventCallback delayedEventCallback = 0;
7283 delayedEventTimerXID = 0;
7284 delayedEventCallback();
7288 ScheduleDelayedEvent(cb, millisec)
7289 DelayedEventCallback cb; long millisec;
7291 if(delayedEventTimerXID && delayedEventCallback == cb)
7292 // [HGM] alive: replace, rather than add or flush identical event
7293 XtRemoveTimeOut(delayedEventTimerXID);
7294 delayedEventCallback = cb;
7295 delayedEventTimerXID =
7296 XtAppAddTimeOut(appContext, millisec,
7297 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7300 DelayedEventCallback
7303 if (delayedEventTimerXID) {
7304 return delayedEventCallback;
7311 CancelDelayedEvent()
7313 if (delayedEventTimerXID) {
7314 XtRemoveTimeOut(delayedEventTimerXID);
7315 delayedEventTimerXID = 0;
7319 XtIntervalId loadGameTimerXID = 0;
7321 int LoadGameTimerRunning()
7323 return loadGameTimerXID != 0;
7326 int StopLoadGameTimer()
7328 if (loadGameTimerXID != 0) {
7329 XtRemoveTimeOut(loadGameTimerXID);
7330 loadGameTimerXID = 0;
7338 LoadGameTimerCallback(arg, id)
7342 loadGameTimerXID = 0;
7347 StartLoadGameTimer(millisec)
7351 XtAppAddTimeOut(appContext, millisec,
7352 (XtTimerCallbackProc) LoadGameTimerCallback,
7356 XtIntervalId analysisClockXID = 0;
7359 AnalysisClockCallback(arg, id)
7363 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7364 || appData.icsEngineAnalyze) { // [DM]
7365 AnalysisPeriodicEvent(0);
7366 StartAnalysisClock();
7371 StartAnalysisClock()
7374 XtAppAddTimeOut(appContext, 2000,
7375 (XtTimerCallbackProc) AnalysisClockCallback,
7379 XtIntervalId clockTimerXID = 0;
7381 int ClockTimerRunning()
7383 return clockTimerXID != 0;
7386 int StopClockTimer()
7388 if (clockTimerXID != 0) {
7389 XtRemoveTimeOut(clockTimerXID);
7398 ClockTimerCallback(arg, id)
7407 StartClockTimer(millisec)
7411 XtAppAddTimeOut(appContext, millisec,
7412 (XtTimerCallbackProc) ClockTimerCallback,
7417 DisplayTimerLabel(w, color, timer, highlight)
7426 /* check for low time warning */
7427 Pixel foregroundOrWarningColor = timerForegroundPixel;
7430 appData.lowTimeWarning &&
7431 (timer / 1000) < appData.icsAlarmTime)
7432 foregroundOrWarningColor = lowTimeWarningColor;
7434 if (appData.clockMode) {
7435 sprintf(buf, "%s: %s", color, TimeString(timer));
7436 XtSetArg(args[0], XtNlabel, buf);
7438 sprintf(buf, "%s ", color);
7439 XtSetArg(args[0], XtNlabel, buf);
7444 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7445 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7447 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7448 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7451 XtSetValues(w, args, 3);
7455 DisplayWhiteClock(timeRemaining, highlight)
7461 if(appData.noGUI) return;
7462 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7463 if (highlight && iconPixmap == bIconPixmap) {
7464 iconPixmap = wIconPixmap;
7465 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7466 XtSetValues(shellWidget, args, 1);
7471 DisplayBlackClock(timeRemaining, highlight)
7477 if(appData.noGUI) return;
7478 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7479 if (highlight && iconPixmap == wIconPixmap) {
7480 iconPixmap = bIconPixmap;
7481 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7482 XtSetValues(shellWidget, args, 1);
7500 int StartChildProcess(cmdLine, dir, pr)
7507 int to_prog[2], from_prog[2];
7511 if (appData.debugMode) {
7512 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7515 /* We do NOT feed the cmdLine to the shell; we just
7516 parse it into blank-separated arguments in the
7517 most simple-minded way possible.
7520 strcpy(buf, cmdLine);
7525 if (p == NULL) break;
7530 SetUpChildIO(to_prog, from_prog);
7532 if ((pid = fork()) == 0) {
7534 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7535 close(to_prog[1]); // first close the unused pipe ends
7536 close(from_prog[0]);
7537 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7538 dup2(from_prog[1], 1);
7539 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7540 close(from_prog[1]); // and closing again loses one of the pipes!
7541 if(fileno(stderr) >= 2) // better safe than sorry...
7542 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7544 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7549 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7551 execvp(argv[0], argv);
7553 /* If we get here, exec failed */
7558 /* Parent process */
7560 close(from_prog[1]);
7562 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7565 cp->fdFrom = from_prog[0];
7566 cp->fdTo = to_prog[1];
7571 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7572 static RETSIGTYPE AlarmCallBack(int n)
7578 DestroyChildProcess(pr, signalType)
7582 ChildProc *cp = (ChildProc *) pr;
7584 if (cp->kind != CPReal) return;
7586 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7587 signal(SIGALRM, AlarmCallBack);
7589 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7590 kill(cp->pid, SIGKILL); // kill it forcefully
7591 wait((int *) 0); // and wait again
7595 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7597 /* Process is exiting either because of the kill or because of
7598 a quit command sent by the backend; either way, wait for it to die.
7607 InterruptChildProcess(pr)
7610 ChildProc *cp = (ChildProc *) pr;
7612 if (cp->kind != CPReal) return;
7613 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7616 int OpenTelnet(host, port, pr)
7621 char cmdLine[MSG_SIZ];
7623 if (port[0] == NULLCHAR) {
7624 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7626 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7628 return StartChildProcess(cmdLine, "", pr);
7631 int OpenTCP(host, port, pr)
7637 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7638 #else /* !OMIT_SOCKETS */
7640 struct sockaddr_in sa;
7642 unsigned short uport;
7645 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7649 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7650 sa.sin_family = AF_INET;
7651 sa.sin_addr.s_addr = INADDR_ANY;
7652 uport = (unsigned short) 0;
7653 sa.sin_port = htons(uport);
7654 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7658 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7659 if (!(hp = gethostbyname(host))) {
7661 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7662 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7663 hp->h_addrtype = AF_INET;
7665 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7666 hp->h_addr_list[0] = (char *) malloc(4);
7667 hp->h_addr_list[0][0] = b0;
7668 hp->h_addr_list[0][1] = b1;
7669 hp->h_addr_list[0][2] = b2;
7670 hp->h_addr_list[0][3] = b3;
7675 sa.sin_family = hp->h_addrtype;
7676 uport = (unsigned short) atoi(port);
7677 sa.sin_port = htons(uport);
7678 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7680 if (connect(s, (struct sockaddr *) &sa,
7681 sizeof(struct sockaddr_in)) < 0) {
7685 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7692 #endif /* !OMIT_SOCKETS */
7697 int OpenCommPort(name, pr)
7704 fd = open(name, 2, 0);
7705 if (fd < 0) return errno;
7707 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7717 int OpenLoopback(pr)
7723 SetUpChildIO(to, from);
7725 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7728 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7735 int OpenRcmd(host, user, cmd, pr)
7736 char *host, *user, *cmd;
7739 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7743 #define INPUT_SOURCE_BUF_SIZE 8192
7752 char buf[INPUT_SOURCE_BUF_SIZE];
7757 DoInputCallback(closure, source, xid)
7762 InputSource *is = (InputSource *) closure;
7767 if (is->lineByLine) {
7768 count = read(is->fd, is->unused,
7769 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7771 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7774 is->unused += count;
7776 while (p < is->unused) {
7777 q = memchr(p, '\n', is->unused - p);
7778 if (q == NULL) break;
7780 (is->func)(is, is->closure, p, q - p, 0);
7784 while (p < is->unused) {
7789 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
7794 (is->func)(is, is->closure, is->buf, count, error);
7798 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
7805 ChildProc *cp = (ChildProc *) pr;
7807 is = (InputSource *) calloc(1, sizeof(InputSource));
7808 is->lineByLine = lineByLine;
7812 is->fd = fileno(stdin);
7814 is->kind = cp->kind;
7815 is->fd = cp->fdFrom;
7818 is->unused = is->buf;
7821 is->xid = XtAppAddInput(appContext, is->fd,
7822 (XtPointer) (XtInputReadMask),
7823 (XtInputCallbackProc) DoInputCallback,
7825 is->closure = closure;
7826 return (InputSourceRef) is;
7830 RemoveInputSource(isr)
7833 InputSource *is = (InputSource *) isr;
7835 if (is->xid == 0) return;
7836 XtRemoveInput(is->xid);
7840 int OutputToProcess(pr, message, count, outError)
7846 static int line = 0;
7847 ChildProc *cp = (ChildProc *) pr;
7852 if (appData.noJoin || !appData.useInternalWrap)
7853 outCount = fwrite(message, 1, count, stdout);
7856 int width = get_term_width();
7857 int len = wrap(NULL, message, count, width, &line);
7858 char *msg = malloc(len);
7862 outCount = fwrite(message, 1, count, stdout);
7865 dbgchk = wrap(msg, message, count, width, &line);
7866 if (dbgchk != len && appData.debugMode)
7867 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
7868 outCount = fwrite(msg, 1, dbgchk, stdout);
7874 outCount = write(cp->fdTo, message, count);
7884 /* Output message to process, with "ms" milliseconds of delay
7885 between each character. This is needed when sending the logon
7886 script to ICC, which for some reason doesn't like the
7887 instantaneous send. */
7888 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
7895 ChildProc *cp = (ChildProc *) pr;
7900 r = write(cp->fdTo, message++, 1);
7913 /**** Animation code by Hugh Fisher, DCS, ANU.
7915 Known problem: if a window overlapping the board is
7916 moved away while a piece is being animated underneath,
7917 the newly exposed area won't be updated properly.
7918 I can live with this.
7920 Known problem: if you look carefully at the animation
7921 of pieces in mono mode, they are being drawn as solid
7922 shapes without interior detail while moving. Fixing
7923 this would be a major complication for minimal return.
7926 /* Masks for XPM pieces. Black and white pieces can have
7927 different shapes, but in the interest of retaining my
7928 sanity pieces must have the same outline on both light
7929 and dark squares, and all pieces must use the same
7930 background square colors/images. */
7932 static int xpmDone = 0;
7935 CreateAnimMasks (pieceDepth)
7942 unsigned long plane;
7945 /* Need a bitmap just to get a GC with right depth */
7946 buf = XCreatePixmap(xDisplay, xBoardWindow,
7948 values.foreground = 1;
7949 values.background = 0;
7950 /* Don't use XtGetGC, not read only */
7951 maskGC = XCreateGC(xDisplay, buf,
7952 GCForeground | GCBackground, &values);
7953 XFreePixmap(xDisplay, buf);
7955 buf = XCreatePixmap(xDisplay, xBoardWindow,
7956 squareSize, squareSize, pieceDepth);
7957 values.foreground = XBlackPixel(xDisplay, xScreen);
7958 values.background = XWhitePixel(xDisplay, xScreen);
7959 bufGC = XCreateGC(xDisplay, buf,
7960 GCForeground | GCBackground, &values);
7962 for (piece = WhitePawn; piece <= BlackKing; piece++) {
7963 /* Begin with empty mask */
7964 if(!xpmDone) // [HGM] pieces: keep using existing
7965 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
7966 squareSize, squareSize, 1);
7967 XSetFunction(xDisplay, maskGC, GXclear);
7968 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
7969 0, 0, squareSize, squareSize);
7971 /* Take a copy of the piece */
7976 XSetFunction(xDisplay, bufGC, GXcopy);
7977 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
7979 0, 0, squareSize, squareSize, 0, 0);
7981 /* XOR the background (light) over the piece */
7982 XSetFunction(xDisplay, bufGC, GXxor);
7984 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
7985 0, 0, squareSize, squareSize, 0, 0);
7987 XSetForeground(xDisplay, bufGC, lightSquareColor);
7988 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
7991 /* We now have an inverted piece image with the background
7992 erased. Construct mask by just selecting all the non-zero
7993 pixels - no need to reconstruct the original image. */
7994 XSetFunction(xDisplay, maskGC, GXor);
7996 /* Might be quicker to download an XImage and create bitmap
7997 data from it rather than this N copies per piece, but it
7998 only takes a fraction of a second and there is a much
7999 longer delay for loading the pieces. */
8000 for (n = 0; n < pieceDepth; n ++) {
8001 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8002 0, 0, squareSize, squareSize,
8008 XFreePixmap(xDisplay, buf);
8009 XFreeGC(xDisplay, bufGC);
8010 XFreeGC(xDisplay, maskGC);
8014 InitAnimState (anim, info)
8016 XWindowAttributes * info;
8021 /* Each buffer is square size, same depth as window */
8022 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8023 squareSize, squareSize, info->depth);
8024 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8025 squareSize, squareSize, info->depth);
8027 /* Create a plain GC for blitting */
8028 mask = GCForeground | GCBackground | GCFunction |
8029 GCPlaneMask | GCGraphicsExposures;
8030 values.foreground = XBlackPixel(xDisplay, xScreen);
8031 values.background = XWhitePixel(xDisplay, xScreen);
8032 values.function = GXcopy;
8033 values.plane_mask = AllPlanes;
8034 values.graphics_exposures = False;
8035 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8037 /* Piece will be copied from an existing context at
8038 the start of each new animation/drag. */
8039 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8041 /* Outline will be a read-only copy of an existing */
8042 anim->outlineGC = None;
8048 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8049 XWindowAttributes info;
8051 if (xpmDone && gameInfo.variant == old) return;
8052 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8053 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8055 InitAnimState(&game, &info);
8056 InitAnimState(&player, &info);
8058 /* For XPM pieces, we need bitmaps to use as masks. */
8060 CreateAnimMasks(info.depth);
8066 static Boolean frameWaiting;
8068 static RETSIGTYPE FrameAlarm (sig)
8071 frameWaiting = False;
8072 /* In case System-V style signals. Needed?? */
8073 signal(SIGALRM, FrameAlarm);
8080 struct itimerval delay;
8082 XSync(xDisplay, False);
8085 frameWaiting = True;
8086 signal(SIGALRM, FrameAlarm);
8087 delay.it_interval.tv_sec =
8088 delay.it_value.tv_sec = time / 1000;
8089 delay.it_interval.tv_usec =
8090 delay.it_value.tv_usec = (time % 1000) * 1000;
8091 setitimer(ITIMER_REAL, &delay, NULL);
8092 while (frameWaiting) pause();
8093 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8094 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8095 setitimer(ITIMER_REAL, &delay, NULL);
8105 XSync(xDisplay, False);
8107 usleep(time * 1000);
8112 /* Convert board position to corner of screen rect and color */
8115 ScreenSquare(column, row, pt, color)
8116 int column; int row; XPoint * pt; int * color;
8119 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8120 pt->y = lineGap + row * (squareSize + lineGap);
8122 pt->x = lineGap + column * (squareSize + lineGap);
8123 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8125 *color = SquareColor(row, column);
8128 /* Convert window coords to square */
8131 BoardSquare(x, y, column, row)
8132 int x; int y; int * column; int * row;
8134 *column = EventToSquare(x, BOARD_WIDTH);
8135 if (flipView && *column >= 0)
8136 *column = BOARD_WIDTH - 1 - *column;
8137 *row = EventToSquare(y, BOARD_HEIGHT);
8138 if (!flipView && *row >= 0)
8139 *row = BOARD_HEIGHT - 1 - *row;
8144 #undef Max /* just in case */
8146 #define Max(a, b) ((a) > (b) ? (a) : (b))
8147 #define Min(a, b) ((a) < (b) ? (a) : (b))
8150 SetRect(rect, x, y, width, height)
8151 XRectangle * rect; int x; int y; int width; int height;
8155 rect->width = width;
8156 rect->height = height;
8159 /* Test if two frames overlap. If they do, return
8160 intersection rect within old and location of
8161 that rect within new. */
8164 Intersect(old, new, size, area, pt)
8165 XPoint * old; XPoint * new;
8166 int size; XRectangle * area; XPoint * pt;
8168 if (old->x > new->x + size || new->x > old->x + size ||
8169 old->y > new->y + size || new->y > old->y + size) {
8172 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8173 size - abs(old->x - new->x), size - abs(old->y - new->y));
8174 pt->x = Max(old->x - new->x, 0);
8175 pt->y = Max(old->y - new->y, 0);
8180 /* For two overlapping frames, return the rect(s)
8181 in the old that do not intersect with the new. */
8184 CalcUpdateRects(old, new, size, update, nUpdates)
8185 XPoint * old; XPoint * new; int size;
8186 XRectangle update[]; int * nUpdates;
8190 /* If old = new (shouldn't happen) then nothing to draw */
8191 if (old->x == new->x && old->y == new->y) {
8195 /* Work out what bits overlap. Since we know the rects
8196 are the same size we don't need a full intersect calc. */
8198 /* Top or bottom edge? */
8199 if (new->y > old->y) {
8200 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8202 } else if (old->y > new->y) {
8203 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8204 size, old->y - new->y);
8207 /* Left or right edge - don't overlap any update calculated above. */
8208 if (new->x > old->x) {
8209 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8210 new->x - old->x, size - abs(new->y - old->y));
8212 } else if (old->x > new->x) {
8213 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8214 old->x - new->x, size - abs(new->y - old->y));
8221 /* Generate a series of frame coords from start->mid->finish.
8222 The movement rate doubles until the half way point is
8223 reached, then halves back down to the final destination,
8224 which gives a nice slow in/out effect. The algorithmn
8225 may seem to generate too many intermediates for short
8226 moves, but remember that the purpose is to attract the
8227 viewers attention to the piece about to be moved and
8228 then to where it ends up. Too few frames would be less
8232 Tween(start, mid, finish, factor, frames, nFrames)
8233 XPoint * start; XPoint * mid;
8234 XPoint * finish; int factor;
8235 XPoint frames[]; int * nFrames;
8237 int fraction, n, count;
8241 /* Slow in, stepping 1/16th, then 1/8th, ... */
8243 for (n = 0; n < factor; n++)
8245 for (n = 0; n < factor; n++) {
8246 frames[count].x = start->x + (mid->x - start->x) / fraction;
8247 frames[count].y = start->y + (mid->y - start->y) / fraction;
8249 fraction = fraction / 2;
8253 frames[count] = *mid;
8256 /* Slow out, stepping 1/2, then 1/4, ... */
8258 for (n = 0; n < factor; n++) {
8259 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8260 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8262 fraction = fraction * 2;
8267 /* Draw a piece on the screen without disturbing what's there */
8270 SelectGCMask(piece, clip, outline, mask)
8271 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8275 /* Bitmap for piece being moved. */
8276 if (appData.monoMode) {
8277 *mask = *pieceToSolid(piece);
8278 } else if (useImages) {
8280 *mask = xpmMask[piece];
8282 *mask = ximMaskPm[piece];
8285 *mask = *pieceToSolid(piece);
8288 /* GC for piece being moved. Square color doesn't matter, but
8289 since it gets modified we make a copy of the original. */
8291 if (appData.monoMode)
8296 if (appData.monoMode)
8301 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8303 /* Outline only used in mono mode and is not modified */
8305 *outline = bwPieceGC;
8307 *outline = wbPieceGC;
8311 OverlayPiece(piece, clip, outline, dest)
8312 ChessSquare piece; GC clip; GC outline; Drawable dest;
8317 /* Draw solid rectangle which will be clipped to shape of piece */
8318 XFillRectangle(xDisplay, dest, clip,
8319 0, 0, squareSize, squareSize);
8320 if (appData.monoMode)
8321 /* Also draw outline in contrasting color for black
8322 on black / white on white cases */
8323 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8324 0, 0, squareSize, squareSize, 0, 0, 1);
8326 /* Copy the piece */
8331 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8333 0, 0, squareSize, squareSize,
8338 /* Animate the movement of a single piece */
8341 BeginAnimation(anim, piece, startColor, start)
8349 /* The old buffer is initialised with the start square (empty) */
8350 BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8351 anim->prevFrame = *start;
8353 /* The piece will be drawn using its own bitmap as a matte */
8354 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8355 XSetClipMask(xDisplay, anim->pieceGC, mask);
8359 AnimationFrame(anim, frame, piece)
8364 XRectangle updates[4];
8369 /* Save what we are about to draw into the new buffer */
8370 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8371 frame->x, frame->y, squareSize, squareSize,
8374 /* Erase bits of the previous frame */
8375 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8376 /* Where the new frame overlapped the previous,
8377 the contents in newBuf are wrong. */
8378 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8379 overlap.x, overlap.y,
8380 overlap.width, overlap.height,
8382 /* Repaint the areas in the old that don't overlap new */
8383 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8384 for (i = 0; i < count; i++)
8385 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8386 updates[i].x - anim->prevFrame.x,
8387 updates[i].y - anim->prevFrame.y,
8388 updates[i].width, updates[i].height,
8389 updates[i].x, updates[i].y);
8391 /* Easy when no overlap */
8392 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8393 0, 0, squareSize, squareSize,
8394 anim->prevFrame.x, anim->prevFrame.y);
8397 /* Save this frame for next time round */
8398 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8399 0, 0, squareSize, squareSize,
8401 anim->prevFrame = *frame;
8403 /* Draw piece over original screen contents, not current,
8404 and copy entire rect. Wipes out overlapping piece images. */
8405 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8406 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8407 0, 0, squareSize, squareSize,
8408 frame->x, frame->y);
8412 EndAnimation (anim, finish)
8416 XRectangle updates[4];
8421 /* The main code will redraw the final square, so we
8422 only need to erase the bits that don't overlap. */
8423 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8424 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8425 for (i = 0; i < count; i++)
8426 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8427 updates[i].x - anim->prevFrame.x,
8428 updates[i].y - anim->prevFrame.y,
8429 updates[i].width, updates[i].height,
8430 updates[i].x, updates[i].y);
8432 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8433 0, 0, squareSize, squareSize,
8434 anim->prevFrame.x, anim->prevFrame.y);
8439 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8441 ChessSquare piece; int startColor;
8442 XPoint * start; XPoint * finish;
8443 XPoint frames[]; int nFrames;
8447 BeginAnimation(anim, piece, startColor, start);
8448 for (n = 0; n < nFrames; n++) {
8449 AnimationFrame(anim, &(frames[n]), piece);
8450 FrameDelay(appData.animSpeed);
8452 EndAnimation(anim, finish);
8455 /* Main control logic for deciding what to animate and how */
8458 AnimateMove(board, fromX, fromY, toX, toY)
8467 XPoint start, finish, mid;
8468 XPoint frames[kFactor * 2 + 1];
8469 int nFrames, startColor, endColor;
8471 /* Are we animating? */
8472 if (!appData.animate || appData.blindfold)
8475 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8476 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8477 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8479 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8480 piece = board[fromY][fromX];
8481 if (piece >= EmptySquare) return;
8486 hop = (piece == WhiteKnight || piece == BlackKnight);
8489 if (appData.debugMode) {
8490 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8491 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8492 piece, fromX, fromY, toX, toY); }
8494 ScreenSquare(fromX, fromY, &start, &startColor);
8495 ScreenSquare(toX, toY, &finish, &endColor);
8498 /* Knight: make diagonal movement then straight */
8499 if (abs(toY - fromY) < abs(toX - fromX)) {
8500 mid.x = start.x + (finish.x - start.x) / 2;
8504 mid.y = start.y + (finish.y - start.y) / 2;
8507 mid.x = start.x + (finish.x - start.x) / 2;
8508 mid.y = start.y + (finish.y - start.y) / 2;
8511 /* Don't use as many frames for very short moves */
8512 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8513 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8515 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8516 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8518 /* Be sure end square is redrawn */
8519 damage[toY][toX] = True;
8523 DragPieceBegin(x, y)
8526 int boardX, boardY, color;
8529 /* Are we animating? */
8530 if (!appData.animateDragging || appData.blindfold)
8533 /* Figure out which square we start in and the
8534 mouse position relative to top left corner. */
8535 BoardSquare(x, y, &boardX, &boardY);
8536 player.startBoardX = boardX;
8537 player.startBoardY = boardY;
8538 ScreenSquare(boardX, boardY, &corner, &color);
8539 player.startSquare = corner;
8540 player.startColor = color;
8541 /* As soon as we start dragging, the piece will jump slightly to
8542 be centered over the mouse pointer. */
8543 player.mouseDelta.x = squareSize/2;
8544 player.mouseDelta.y = squareSize/2;
8545 /* Initialise animation */
8546 player.dragPiece = PieceForSquare(boardX, boardY);
8548 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8549 player.dragActive = True;
8550 BeginAnimation(&player, player.dragPiece, color, &corner);
8551 /* Mark this square as needing to be redrawn. Note that
8552 we don't remove the piece though, since logically (ie
8553 as seen by opponent) the move hasn't been made yet. */
8554 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8555 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8556 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8557 corner.x, corner.y, squareSize, squareSize,
8558 0, 0); // [HGM] zh: unstack in stead of grab
8559 damage[boardY][boardX] = True;
8561 player.dragActive = False;
8571 /* Are we animating? */
8572 if (!appData.animateDragging || appData.blindfold)
8576 if (! player.dragActive)
8578 /* Move piece, maintaining same relative position
8579 of mouse within square */
8580 corner.x = x - player.mouseDelta.x;
8581 corner.y = y - player.mouseDelta.y;
8582 AnimationFrame(&player, &corner, player.dragPiece);
8584 if (appData.highlightDragging) {
8586 BoardSquare(x, y, &boardX, &boardY);
8587 SetHighlights(fromX, fromY, boardX, boardY);
8596 int boardX, boardY, color;
8599 /* Are we animating? */
8600 if (!appData.animateDragging || appData.blindfold)
8604 if (! player.dragActive)
8606 /* Last frame in sequence is square piece is
8607 placed on, which may not match mouse exactly. */
8608 BoardSquare(x, y, &boardX, &boardY);
8609 ScreenSquare(boardX, boardY, &corner, &color);
8610 EndAnimation(&player, &corner);
8612 /* Be sure end square is redrawn */
8613 damage[boardY][boardX] = True;
8615 /* This prevents weird things happening with fast successive
8616 clicks which on my Sun at least can cause motion events
8617 without corresponding press/release. */
8618 player.dragActive = False;
8621 /* Handle expose event while piece being dragged */
8626 if (!player.dragActive || appData.blindfold)
8629 /* What we're doing: logically, the move hasn't been made yet,
8630 so the piece is still in it's original square. But visually
8631 it's being dragged around the board. So we erase the square
8632 that the piece is on and draw it at the last known drag point. */
8633 BlankSquare(player.startSquare.x, player.startSquare.y,
8634 player.startColor, EmptySquare, xBoardWindow);
8635 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8636 damage[player.startBoardY][player.startBoardX] = TRUE;
8639 #include <sys/ioctl.h>
8640 int get_term_width()
8642 int fd, default_width;
8645 default_width = 79; // this is FICS default anyway...
8647 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8649 if (!ioctl(fd, TIOCGSIZE, &win))
8650 default_width = win.ts_cols;
8651 #elif defined(TIOCGWINSZ)
8653 if (!ioctl(fd, TIOCGWINSZ, &win))
8654 default_width = win.ws_col;
8656 return default_width;
8659 void update_ics_width()
8661 static int old_width = 0;
8662 int new_width = get_term_width();
8664 if (old_width != new_width)
8665 ics_printf("set width %d\n", new_width);
8666 old_width = new_width;
8669 void NotifyFrontendLogin()