2 * xboard.c -- X front end for XBoard
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
8 * 2007, 2008, 2009 Free Software Foundation, Inc.
10 * The following terms apply to Digital Equipment Corporation's copyright
12 * ------------------------------------------------------------------------
15 * Permission to use, copy, modify, and distribute this software and its
16 * documentation for any purpose and without fee is hereby granted,
17 * provided that the above copyright notice appear in all copies and that
18 * both that copyright notice and this permission notice appear in
19 * supporting documentation, and that the name of Digital not be
20 * used in advertising or publicity pertaining to distribution of the
21 * software without specific, written prior permission.
23 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
30 * ------------------------------------------------------------------------
32 * The following terms apply to the enhanced version of XBoard
33 * distributed by the Free Software Foundation:
34 * ------------------------------------------------------------------------
36 * GNU XBoard is free software: you can redistribute it and/or modify
37 * it under the terms of the GNU General Public License as published by
38 * the Free Software Foundation, either version 3 of the License, or (at
39 * your option) any later version.
41 * GNU XBoard is distributed in the hope that it will be useful, but
42 * WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44 * General Public License for more details.
46 * You should have received a copy of the GNU General Public License
47 * along with this program. If not, see http://www.gnu.org/licenses/. *
49 *------------------------------------------------------------------------
50 ** See the file ChangeLog for a revision history. */
58 #include <sys/types.h>
63 # if HAVE_SYS_SOCKET_H
64 # include <sys/socket.h>
65 # include <netinet/in.h>
67 # else /* not HAVE_SYS_SOCKET_H */
68 # if HAVE_LAN_SOCKET_H
69 # include <lan/socket.h>
71 # include <lan/netdb.h>
72 # else /* not HAVE_LAN_SOCKET_H */
73 # define OMIT_SOCKETS 1
74 # endif /* not HAVE_LAN_SOCKET_H */
75 # endif /* not HAVE_SYS_SOCKET_H */
76 #endif /* !OMIT_SOCKETS */
81 #else /* not STDC_HEADERS */
82 extern char *getenv();
85 # else /* not HAVE_STRING_H */
87 # endif /* not HAVE_STRING_H */
88 #endif /* not STDC_HEADERS */
91 # include <sys/fcntl.h>
92 #else /* not HAVE_SYS_FCNTL_H */
95 # endif /* HAVE_FCNTL_H */
96 #endif /* not HAVE_SYS_FCNTL_H */
98 #if HAVE_SYS_SYSTEMINFO_H
99 # include <sys/systeminfo.h>
100 #endif /* HAVE_SYS_SYSTEMINFO_H */
102 #if TIME_WITH_SYS_TIME
103 # include <sys/time.h>
107 # include <sys/time.h>
118 # include <sys/wait.h>
123 # define NAMLEN(dirent) strlen((dirent)->d_name)
124 # define HAVE_DIR_STRUCT
126 # define dirent direct
127 # define NAMLEN(dirent) (dirent)->d_namlen
129 # include <sys/ndir.h>
130 # define HAVE_DIR_STRUCT
133 # include <sys/dir.h>
134 # define HAVE_DIR_STRUCT
138 # define HAVE_DIR_STRUCT
142 #include <X11/Intrinsic.h>
143 #include <X11/StringDefs.h>
144 #include <X11/Shell.h>
145 #include <X11/cursorfont.h>
146 #include <X11/Xatom.h>
147 #include <X11/Xmu/Atoms.h>
149 #include <X11/Xaw3d/Dialog.h>
150 #include <X11/Xaw3d/Form.h>
151 #include <X11/Xaw3d/List.h>
152 #include <X11/Xaw3d/Label.h>
153 #include <X11/Xaw3d/SimpleMenu.h>
154 #include <X11/Xaw3d/SmeBSB.h>
155 #include <X11/Xaw3d/SmeLine.h>
156 #include <X11/Xaw3d/Box.h>
157 #include <X11/Xaw3d/MenuButton.h>
158 #include <X11/Xaw3d/Text.h>
159 #include <X11/Xaw3d/AsciiText.h>
161 #include <X11/Xaw/Dialog.h>
162 #include <X11/Xaw/Form.h>
163 #include <X11/Xaw/List.h>
164 #include <X11/Xaw/Label.h>
165 #include <X11/Xaw/SimpleMenu.h>
166 #include <X11/Xaw/SmeBSB.h>
167 #include <X11/Xaw/SmeLine.h>
168 #include <X11/Xaw/Box.h>
169 #include <X11/Xaw/MenuButton.h>
170 #include <X11/Xaw/Text.h>
171 #include <X11/Xaw/AsciiText.h>
174 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
179 #include "pixmaps/pixmaps.h"
180 #define IMAGE_EXT "xpm"
182 #define IMAGE_EXT "xim"
183 #include "bitmaps/bitmaps.h"
186 #include "bitmaps/icon_white.bm"
187 #include "bitmaps/icon_black.bm"
188 #include "bitmaps/checkmark.bm"
190 #include "frontend.h"
195 #include "xgamelist.h"
196 #include "xhistory.h"
197 #include "xedittags.h"
200 // must be moved to xengineoutput.h
202 void EngineOutputProc P((Widget w, XEvent *event,
203 String *prms, Cardinal *nprms));
204 void EvalGraphProc P((Widget w, XEvent *event,
205 String *prms, Cardinal *nprms));
212 #define usleep(t) _sleep2(((t)+500)/1000)
216 # define _(s) gettext (s)
217 # define N_(s) gettext_noop (s)
233 int main P((int argc, char **argv));
234 RETSIGTYPE CmailSigHandler P((int sig));
235 RETSIGTYPE IntSigHandler P((int sig));
236 RETSIGTYPE TermSizeSigHandler P((int sig));
237 void CreateGCs P((void));
238 void CreateXIMPieces P((void));
239 void CreateXPMPieces P((void));
240 void CreatePieces P((void));
241 void CreatePieceMenus P((void));
242 Widget CreateMenuBar P((Menu *mb));
243 Widget CreateButtonBar P ((MenuItem *mi));
244 char *FindFont P((char *pattern, int targetPxlSize));
245 void PieceMenuPopup P((Widget w, XEvent *event,
246 String *params, Cardinal *num_params));
247 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
248 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
249 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
250 u_int wreq, u_int hreq));
251 void CreateGrid P((void));
252 int EventToSquare P((int x, int limit));
253 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
254 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
255 void HandleUserMove P((Widget w, XEvent *event,
256 String *prms, Cardinal *nprms));
257 void AnimateUserMove P((Widget w, XEvent * event,
258 String * params, Cardinal * nParams));
259 void WhiteClock P((Widget w, XEvent *event,
260 String *prms, Cardinal *nprms));
261 void BlackClock P((Widget w, XEvent *event,
262 String *prms, Cardinal *nprms));
263 void DrawPositionProc P((Widget w, XEvent *event,
264 String *prms, Cardinal *nprms));
265 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
267 void CommentPopUp P((char *title, char *label));
268 void CommentPopDown P((void));
269 void CommentCallback P((Widget w, XtPointer client_data,
270 XtPointer call_data));
271 void ICSInputBoxPopUp P((void));
272 void ICSInputBoxPopDown P((void));
273 void FileNamePopUp P((char *label, char *def,
274 FileProc proc, char *openMode));
275 void FileNamePopDown P((void));
276 void FileNameCallback P((Widget w, XtPointer client_data,
277 XtPointer call_data));
278 void FileNameAction P((Widget w, XEvent *event,
279 String *prms, Cardinal *nprms));
280 void AskQuestionReplyAction P((Widget w, XEvent *event,
281 String *prms, Cardinal *nprms));
282 void AskQuestionProc P((Widget w, XEvent *event,
283 String *prms, Cardinal *nprms));
284 void AskQuestionPopDown P((void));
285 void PromotionPopDown P((void));
286 void PromotionCallback P((Widget w, XtPointer client_data,
287 XtPointer call_data));
288 void EditCommentPopDown P((void));
289 void EditCommentCallback P((Widget w, XtPointer client_data,
290 XtPointer call_data));
291 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
292 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
293 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
294 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
296 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
298 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
300 void LoadPositionProc P((Widget w, XEvent *event,
301 String *prms, Cardinal *nprms));
302 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
304 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
306 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
308 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
310 void PastePositionProc P((Widget w, XEvent *event, String *prms,
312 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
313 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
314 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
315 void SavePositionProc P((Widget w, XEvent *event,
316 String *prms, Cardinal *nprms));
317 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
318 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
320 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
321 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
322 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
324 void MachineWhiteProc P((Widget w, XEvent *event,
325 String *prms, Cardinal *nprms));
326 void AnalyzeModeProc P((Widget w, XEvent *event,
327 String *prms, Cardinal *nprms));
328 void AnalyzeFileProc P((Widget w, XEvent *event,
329 String *prms, Cardinal *nprms));
330 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
332 void IcsClientProc P((Widget w, XEvent *event, String *prms,
334 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
335 void EditPositionProc P((Widget w, XEvent *event,
336 String *prms, Cardinal *nprms));
337 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
338 void EditCommentProc P((Widget w, XEvent *event,
339 String *prms, Cardinal *nprms));
340 void IcsInputBoxProc P((Widget w, XEvent *event,
341 String *prms, Cardinal *nprms));
342 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
343 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
344 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
345 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
346 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
347 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
348 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
349 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
350 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
351 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
352 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
353 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
354 void StopObservingProc P((Widget w, XEvent *event, String *prms,
356 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
358 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
365 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
367 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
370 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
372 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
374 void AutocommProc P((Widget w, XEvent *event, String *prms,
376 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
377 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void AutobsProc P((Widget w, XEvent *event, String *prms,
380 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
385 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
386 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
388 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
390 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
392 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
393 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
394 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
396 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
398 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
400 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
402 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
404 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
405 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
406 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
408 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
410 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
412 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
414 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
415 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
416 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
417 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
418 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
419 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
420 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
421 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
422 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
423 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
424 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
425 void DisplayMove P((int moveNumber));
426 void DisplayTitle P((char *title));
427 void ICSInitScript P((void));
428 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
429 void ErrorPopUp P((char *title, char *text, int modal));
430 void ErrorPopDown P((void));
431 static char *ExpandPathName P((char *path));
432 static void CreateAnimVars P((void));
433 static void DragPieceMove P((int x, int y));
434 static void DrawDragPiece P((void));
435 char *ModeToWidgetName P((GameMode mode));
436 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
442 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
443 void ShufflePopDown P(());
444 void EnginePopDown P(());
445 void UciPopDown P(());
446 void TimeControlPopDown P(());
447 void NewVariantPopDown P(());
448 void SettingsPopDown P(());
449 void update_ics_width P(());
450 int get_term_width P(());
451 int CopyMemoProc P(());
452 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
453 char *init_path, char *mode, int (*show_entry)(), char **name_return));
455 * XBoard depends on Xt R4 or higher
457 int xtVersion = XtSpecificationRelease;
462 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
463 jailSquareColor, highlightSquareColor, premoveHighlightColor;
464 Pixel lowTimeWarningColor;
465 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
466 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
467 wjPieceGC, bjPieceGC, prelineGC, countGC;
468 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
469 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
470 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
471 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
472 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
473 ICSInputShell, fileNameShell, askQuestionShell;
474 Widget historyShell, evalGraphShell, gameListShell;
475 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
476 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
477 Font clockFontID, coordFontID, countFontID;
478 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
479 XtAppContext appContext;
481 char *oldICSInteractionTitle;
485 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
487 Position commentX = -1, commentY = -1;
488 Dimension commentW, commentH;
489 typedef unsigned int BoardSize;
491 Boolean chessProgram;
493 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
494 int squareSize, smallLayout = 0, tinyLayout = 0,
495 marginW, marginH, // [HGM] for run-time resizing
496 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
497 ICSInputBoxUp = False, askQuestionUp = False,
498 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
499 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
500 Pixel timerForegroundPixel, timerBackgroundPixel;
501 Pixel buttonForegroundPixel, buttonBackgroundPixel;
502 char *chessDir, *programName, *programVersion,
503 *gameCopyFilename, *gamePasteFilename;
504 Boolean alwaysOnTop = False;
505 Boolean saveSettingsOnExit;
506 char *settingsFileName;
507 char *icsTextMenuString;
509 char *firstChessProgramNames;
510 char *secondChessProgramNames;
512 WindowPlacement wpMain;
513 WindowPlacement wpConsole;
514 WindowPlacement wpComment;
515 WindowPlacement wpMoveHistory;
516 WindowPlacement wpEvalGraph;
517 WindowPlacement wpEngineOutput;
518 WindowPlacement wpGameList;
519 WindowPlacement wpTags;
523 Pixmap pieceBitmap[2][(int)BlackPawn];
524 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
525 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
526 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
527 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
528 int useImages, useImageSqs;
529 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
530 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
531 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
532 XImage *ximLightSquare, *ximDarkSquare;
535 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
536 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
538 #define White(piece) ((int)(piece) < (int)BlackPawn)
540 /* Variables for doing smooth animation. This whole thing
541 would be much easier if the board was double-buffered,
542 but that would require a fairly major rewrite. */
547 GC blitGC, pieceGC, outlineGC;
548 XPoint startSquare, prevFrame, mouseDelta;
552 int startBoardX, startBoardY;
555 /* There can be two pieces being animated at once: a player
556 can begin dragging a piece before the remote opponent has moved. */
558 static AnimState game, player;
560 /* Bitmaps for use as masks when drawing XPM pieces.
561 Need one for each black and white piece. */
562 static Pixmap xpmMask[BlackKing + 1];
564 /* This magic number is the number of intermediate frames used
565 in each half of the animation. For short moves it's reduced
566 by 1. The total number of frames will be factor * 2 + 1. */
569 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
571 MenuItem fileMenu[] = {
572 {N_("New Game"), ResetProc},
573 {N_("New Shuffle Game ..."), ShuffleMenuProc},
574 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
575 {"----", NothingProc},
576 {N_("Load Game"), LoadGameProc},
577 {N_("Load Next Game"), LoadNextGameProc},
578 {N_("Load Previous Game"), LoadPrevGameProc},
579 {N_("Reload Same Game"), ReloadGameProc},
580 {N_("Save Game"), SaveGameProc},
581 {"----", NothingProc},
582 {N_("Copy Game"), CopyGameProc},
583 {N_("Paste Game"), PasteGameProc},
584 {"----", NothingProc},
585 {N_("Load Position"), LoadPositionProc},
586 {N_("Load Next Position"), LoadNextPositionProc},
587 {N_("Load Previous Position"), LoadPrevPositionProc},
588 {N_("Reload Same Position"), ReloadPositionProc},
589 {N_("Save Position"), SavePositionProc},
590 {"----", NothingProc},
591 {N_("Copy Position"), CopyPositionProc},
592 {N_("Paste Position"), PastePositionProc},
593 {"----", NothingProc},
594 {N_("Mail Move"), MailMoveProc},
595 {N_("Reload CMail Message"), ReloadCmailMsgProc},
596 {"----", NothingProc},
597 {N_("Exit"), QuitProc},
601 MenuItem modeMenu[] = {
602 {N_("Machine White"), MachineWhiteProc},
603 {N_("Machine Black"), MachineBlackProc},
604 {N_("Two Machines"), TwoMachinesProc},
605 {N_("Analysis Mode"), AnalyzeModeProc},
606 {N_("Analyze File"), AnalyzeFileProc },
607 {N_("ICS Client"), IcsClientProc},
608 {N_("Edit Game"), EditGameProc},
609 {N_("Edit Position"), EditPositionProc},
610 {N_("Training"), TrainingProc},
611 {"----", NothingProc},
612 {N_("Show Engine Output"), EngineOutputProc},
613 {N_("Show Evaluation Graph"), EvalGraphProc},
614 {N_("Show Game List"), ShowGameListProc},
615 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
616 {"----", NothingProc},
617 {N_("Edit Tags"), EditTagsProc},
618 {N_("Edit Comment"), EditCommentProc},
619 {N_("ICS Input Box"), IcsInputBoxProc},
620 {N_("Pause"), PauseProc},
624 MenuItem actionMenu[] = {
625 {N_("Accept"), AcceptProc},
626 {N_("Decline"), DeclineProc},
627 {N_("Rematch"), RematchProc},
628 {"----", NothingProc},
629 {N_("Call Flag"), CallFlagProc},
630 {N_("Draw"), DrawProc},
631 {N_("Adjourn"), AdjournProc},
632 {N_("Abort"), AbortProc},
633 {N_("Resign"), ResignProc},
634 {"----", NothingProc},
635 {N_("Stop Observing"), StopObservingProc},
636 {N_("Stop Examining"), StopExaminingProc},
637 {"----", NothingProc},
638 {N_("Adjudicate to White"), AdjuWhiteProc},
639 {N_("Adjudicate to Black"), AdjuBlackProc},
640 {N_("Adjudicate Draw"), AdjuDrawProc},
644 MenuItem stepMenu[] = {
645 {N_("Backward"), BackwardProc},
646 {N_("Forward"), ForwardProc},
647 {N_("Back to Start"), ToStartProc},
648 {N_("Forward to End"), ToEndProc},
649 {N_("Revert"), RevertProc},
650 {N_("Truncate Game"), TruncateGameProc},
651 {"----", NothingProc},
652 {N_("Move Now"), MoveNowProc},
653 {N_("Retract Move"), RetractMoveProc},
657 MenuItem optionsMenu[] = {
658 {N_("Flip View"), FlipViewProc},
659 {"----", NothingProc},
660 {N_("Adjudications ..."), EngineMenuProc},
661 {N_("General Settings ..."), UciMenuProc},
662 {N_("Engine #1 Settings ..."), FirstSettingsProc},
663 {N_("Engine #2 Settings ..."), SecondSettingsProc},
664 {N_("Time Control ..."), TimeControlProc},
665 {"----", NothingProc},
666 {N_("Always Queen"), AlwaysQueenProc},
667 {N_("Animate Dragging"), AnimateDraggingProc},
668 {N_("Animate Moving"), AnimateMovingProc},
669 {N_("Auto Comment"), AutocommProc},
670 {N_("Auto Flag"), AutoflagProc},
671 {N_("Auto Flip View"), AutoflipProc},
672 {N_("Auto Observe"), AutobsProc},
673 {N_("Auto Raise Board"), AutoraiseProc},
674 {N_("Auto Save"), AutosaveProc},
675 {N_("Blindfold"), BlindfoldProc},
676 {N_("Flash Moves"), FlashMovesProc},
677 {N_("Get Move List"), GetMoveListProc},
679 {N_("Highlight Dragging"), HighlightDraggingProc},
681 {N_("Highlight Last Move"), HighlightLastMoveProc},
682 {N_("Move Sound"), MoveSoundProc},
683 {N_("ICS Alarm"), IcsAlarmProc},
684 {N_("Old Save Style"), OldSaveStyleProc},
685 {N_("Periodic Updates"), PeriodicUpdatesProc},
686 {N_("Ponder Next Move"), PonderNextMoveProc},
687 {N_("Popup Exit Message"), PopupExitMessageProc},
688 {N_("Popup Move Errors"), PopupMoveErrorsProc},
689 {N_("Premove"), PremoveProc},
690 {N_("Quiet Play"), QuietPlayProc},
691 {N_("Show Coords"), ShowCoordsProc},
692 {N_("Hide Thinking"), HideThinkingProc},
693 {N_("Test Legality"), TestLegalityProc},
694 {"----", NothingProc},
695 {N_("Save Settings Now"), SaveSettingsProc},
696 {N_("Save Settings on Exit"), SaveOnExitProc},
700 MenuItem helpMenu[] = {
701 {N_("Info XBoard"), InfoProc},
702 {N_("Man XBoard"), ManProc},
703 {"----", NothingProc},
704 {N_("Hint"), HintProc},
705 {N_("Book"), BookProc},
706 {"----", NothingProc},
707 {N_("About XBoard"), AboutProc},
712 {N_("File"), fileMenu},
713 {N_("Mode"), modeMenu},
714 {N_("Action"), actionMenu},
715 {N_("Step"), stepMenu},
716 {N_("Options"), optionsMenu},
717 {N_("Help"), helpMenu},
721 #define PAUSE_BUTTON N_("P")
722 MenuItem buttonBar[] = {
725 {PAUSE_BUTTON, PauseProc},
731 #define PIECE_MENU_SIZE 18
732 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
733 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
734 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
735 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
736 N_("Empty square"), N_("Clear board") },
737 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
738 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
739 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
740 N_("Empty square"), N_("Clear board") }
742 /* must be in same order as PieceMenuStrings! */
743 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
744 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
745 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
746 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
747 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
748 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
749 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
750 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
751 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
754 #define DROP_MENU_SIZE 6
755 String dropMenuStrings[DROP_MENU_SIZE] = {
756 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
758 /* must be in same order as PieceMenuStrings! */
759 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
760 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
761 WhiteRook, WhiteQueen
769 DropMenuEnables dmEnables[] = {
787 { XtNborderWidth, 0 },
788 { XtNdefaultDistance, 0 },
792 { XtNborderWidth, 0 },
793 { XtNresizable, (XtArgVal) True },
797 { XtNborderWidth, 0 },
803 { XtNjustify, (XtArgVal) XtJustifyRight },
804 { XtNlabel, (XtArgVal) "..." },
805 { XtNresizable, (XtArgVal) True },
806 { XtNresize, (XtArgVal) False }
809 Arg messageArgs[] = {
810 { XtNjustify, (XtArgVal) XtJustifyLeft },
811 { XtNlabel, (XtArgVal) "..." },
812 { XtNresizable, (XtArgVal) True },
813 { XtNresize, (XtArgVal) False }
817 { XtNborderWidth, 0 },
818 { XtNjustify, (XtArgVal) XtJustifyLeft }
821 XtResource clientResources[] = {
822 { "flashCount", "flashCount", XtRInt, sizeof(int),
823 XtOffset(AppDataPtr, flashCount), XtRImmediate,
824 (XtPointer) FLASH_COUNT },
827 XrmOptionDescRec shellOptions[] = {
828 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
829 { "-flash", "flashCount", XrmoptionNoArg, "3" },
830 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
833 XtActionsRec boardActions[] = {
834 { "DrawPosition", DrawPositionProc },
835 { "HandleUserMove", HandleUserMove },
836 { "AnimateUserMove", AnimateUserMove },
837 { "FileNameAction", FileNameAction },
838 { "AskQuestionProc", AskQuestionProc },
839 { "AskQuestionReplyAction", AskQuestionReplyAction },
840 { "PieceMenuPopup", PieceMenuPopup },
841 { "WhiteClock", WhiteClock },
842 { "BlackClock", BlackClock },
843 { "Iconify", Iconify },
844 { "ResetProc", ResetProc },
845 { "LoadGameProc", LoadGameProc },
846 { "LoadNextGameProc", LoadNextGameProc },
847 { "LoadPrevGameProc", LoadPrevGameProc },
848 { "LoadSelectedProc", LoadSelectedProc },
849 { "ReloadGameProc", ReloadGameProc },
850 { "LoadPositionProc", LoadPositionProc },
851 { "LoadNextPositionProc", LoadNextPositionProc },
852 { "LoadPrevPositionProc", LoadPrevPositionProc },
853 { "ReloadPositionProc", ReloadPositionProc },
854 { "CopyPositionProc", CopyPositionProc },
855 { "PastePositionProc", PastePositionProc },
856 { "CopyGameProc", CopyGameProc },
857 { "PasteGameProc", PasteGameProc },
858 { "SaveGameProc", SaveGameProc },
859 { "SavePositionProc", SavePositionProc },
860 { "MailMoveProc", MailMoveProc },
861 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
862 { "QuitProc", QuitProc },
863 { "MachineWhiteProc", MachineWhiteProc },
864 { "MachineBlackProc", MachineBlackProc },
865 { "AnalysisModeProc", AnalyzeModeProc },
866 { "AnalyzeFileProc", AnalyzeFileProc },
867 { "TwoMachinesProc", TwoMachinesProc },
868 { "IcsClientProc", IcsClientProc },
869 { "EditGameProc", EditGameProc },
870 { "EditPositionProc", EditPositionProc },
871 { "TrainingProc", EditPositionProc },
872 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
873 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
874 { "ShowGameListProc", ShowGameListProc },
875 { "ShowMoveListProc", HistoryShowProc},
876 { "EditTagsProc", EditCommentProc },
877 { "EditCommentProc", EditCommentProc },
878 { "IcsAlarmProc", IcsAlarmProc },
879 { "IcsInputBoxProc", IcsInputBoxProc },
880 { "PauseProc", PauseProc },
881 { "AcceptProc", AcceptProc },
882 { "DeclineProc", DeclineProc },
883 { "RematchProc", RematchProc },
884 { "CallFlagProc", CallFlagProc },
885 { "DrawProc", DrawProc },
886 { "AdjournProc", AdjournProc },
887 { "AbortProc", AbortProc },
888 { "ResignProc", ResignProc },
889 { "AdjuWhiteProc", AdjuWhiteProc },
890 { "AdjuBlackProc", AdjuBlackProc },
891 { "AdjuDrawProc", AdjuDrawProc },
892 { "EnterKeyProc", EnterKeyProc },
893 { "StopObservingProc", StopObservingProc },
894 { "StopExaminingProc", StopExaminingProc },
895 { "BackwardProc", BackwardProc },
896 { "ForwardProc", ForwardProc },
897 { "ToStartProc", ToStartProc },
898 { "ToEndProc", ToEndProc },
899 { "RevertProc", RevertProc },
900 { "TruncateGameProc", TruncateGameProc },
901 { "MoveNowProc", MoveNowProc },
902 { "RetractMoveProc", RetractMoveProc },
903 { "AlwaysQueenProc", AlwaysQueenProc },
904 { "AnimateDraggingProc", AnimateDraggingProc },
905 { "AnimateMovingProc", AnimateMovingProc },
906 { "AutoflagProc", AutoflagProc },
907 { "AutoflipProc", AutoflipProc },
908 { "AutobsProc", AutobsProc },
909 { "AutoraiseProc", AutoraiseProc },
910 { "AutosaveProc", AutosaveProc },
911 { "BlindfoldProc", BlindfoldProc },
912 { "FlashMovesProc", FlashMovesProc },
913 { "FlipViewProc", FlipViewProc },
914 { "GetMoveListProc", GetMoveListProc },
916 { "HighlightDraggingProc", HighlightDraggingProc },
918 { "HighlightLastMoveProc", HighlightLastMoveProc },
919 { "IcsAlarmProc", IcsAlarmProc },
920 { "MoveSoundProc", MoveSoundProc },
921 { "OldSaveStyleProc", OldSaveStyleProc },
922 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
923 { "PonderNextMoveProc", PonderNextMoveProc },
924 { "PopupExitMessageProc", PopupExitMessageProc },
925 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
926 { "PremoveProc", PremoveProc },
927 { "QuietPlayProc", QuietPlayProc },
928 { "ShowCoordsProc", ShowCoordsProc },
929 { "ShowThinkingProc", ShowThinkingProc },
930 { "HideThinkingProc", HideThinkingProc },
931 { "TestLegalityProc", TestLegalityProc },
932 { "SaveSettingsProc", SaveSettingsProc },
933 { "SaveOnExitProc", SaveOnExitProc },
934 { "InfoProc", InfoProc },
935 { "ManProc", ManProc },
936 { "HintProc", HintProc },
937 { "BookProc", BookProc },
938 { "AboutGameProc", AboutGameProc },
939 { "AboutProc", AboutProc },
940 { "DebugProc", DebugProc },
941 { "NothingProc", NothingProc },
942 { "CommentPopDown", (XtActionProc) CommentPopDown },
943 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
944 { "TagsPopDown", (XtActionProc) TagsPopDown },
945 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
946 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
947 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
948 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
949 { "GameListPopDown", (XtActionProc) GameListPopDown },
950 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
951 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
952 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
953 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
954 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
955 { "EnginePopDown", (XtActionProc) EnginePopDown },
956 { "UciPopDown", (XtActionProc) UciPopDown },
957 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
958 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
959 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
960 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
963 char globalTranslations[] =
964 ":<Key>R: ResignProc() \n \
965 :<Key>r: ResetProc() \n \
966 :<Key>g: LoadGameProc() \n \
967 :<Key>N: LoadNextGameProc() \n \
968 :<Key>P: LoadPrevGameProc() \n \
969 :<Key>Q: QuitProc() \n \
970 :<Key>F: ToEndProc() \n \
971 :<Key>f: ForwardProc() \n \
972 :<Key>B: ToStartProc() \n \
973 :<Key>b: BackwardProc() \n \
974 :<Key>p: PauseProc() \n \
975 :<Key>d: DrawProc() \n \
976 :<Key>t: CallFlagProc() \n \
977 :<Key>i: Iconify() \n \
978 :<Key>c: Iconify() \n \
979 :<Key>v: FlipViewProc() \n \
980 <KeyDown>Control_L: BackwardProc() \n \
981 <KeyUp>Control_L: ForwardProc() \n \
982 <KeyDown>Control_R: BackwardProc() \n \
983 <KeyUp>Control_R: ForwardProc() \n \
984 Shift<Key>1: AskQuestionProc(\"Direct command\",\
985 \"Send to chess program:\",,1) \n \
986 Shift<Key>2: AskQuestionProc(\"Direct command\",\
987 \"Send to second chess program:\",,2) \n";
989 char boardTranslations[] =
990 "<Btn1Down>: HandleUserMove() \n \
991 <Btn1Up>: HandleUserMove() \n \
992 <Btn1Motion>: AnimateUserMove() \n \
993 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
994 PieceMenuPopup(menuB) \n \
995 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
996 PieceMenuPopup(menuW) \n \
997 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
998 PieceMenuPopup(menuW) \n \
999 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1000 PieceMenuPopup(menuB) \n";
1002 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1003 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1005 char ICSInputTranslations[] =
1006 "<Key>Return: EnterKeyProc() \n";
1008 String xboardResources[] = {
1009 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1010 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1011 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1016 /* Max possible square size */
1017 #define MAXSQSIZE 256
1019 static int xpm_avail[MAXSQSIZE];
1021 #ifdef HAVE_DIR_STRUCT
1023 /* Extract piece size from filename */
1025 xpm_getsize(name, len, ext)
1036 if ((p=strchr(name, '.')) == NULL ||
1037 StrCaseCmp(p+1, ext) != 0)
1043 while (*p && isdigit(*p))
1050 /* Setup xpm_avail */
1052 xpm_getavail(dirname, ext)
1060 for (i=0; i<MAXSQSIZE; ++i)
1063 if (appData.debugMode)
1064 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1066 dir = opendir(dirname);
1069 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1070 programName, dirname);
1074 while ((ent=readdir(dir)) != NULL) {
1075 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1076 if (i > 0 && i < MAXSQSIZE)
1086 xpm_print_avail(fp, ext)
1092 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1093 for (i=1; i<MAXSQSIZE; ++i) {
1099 /* Return XPM piecesize closest to size */
1101 xpm_closest_to(dirname, size, ext)
1107 int sm_diff = MAXSQSIZE;
1111 xpm_getavail(dirname, ext);
1113 if (appData.debugMode)
1114 xpm_print_avail(stderr, ext);
1116 for (i=1; i<MAXSQSIZE; ++i) {
1119 diff = (diff<0) ? -diff : diff;
1120 if (diff < sm_diff) {
1128 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1134 #else /* !HAVE_DIR_STRUCT */
1135 /* If we are on a system without a DIR struct, we can't
1136 read the directory, so we can't collect a list of
1137 filenames, etc., so we can't do any size-fitting. */
1139 xpm_closest_to(dirname, size, ext)
1144 fprintf(stderr, _("\
1145 Warning: No DIR structure found on this system --\n\
1146 Unable to autosize for XPM/XIM pieces.\n\
1147 Please report this error to frankm@hiwaay.net.\n\
1148 Include system type & operating system in message.\n"));
1151 #endif /* HAVE_DIR_STRUCT */
1153 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1154 "magenta", "cyan", "white" };
1158 TextColors textColors[(int)NColorClasses];
1160 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1162 parse_color(str, which)
1166 char *p, buf[100], *d;
1169 if (strlen(str) > 99) /* watch bounds on buf */
1174 for (i=0; i<which; ++i) {
1181 /* Could be looking at something like:
1183 .. in which case we want to stop on a comma also */
1184 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1188 return -1; /* Use default for empty field */
1191 if (which == 2 || isdigit(*p))
1194 while (*p && isalpha(*p))
1199 for (i=0; i<8; ++i) {
1200 if (!StrCaseCmp(buf, cnames[i]))
1201 return which? (i+40) : (i+30);
1203 if (!StrCaseCmp(buf, "default")) return -1;
1205 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1210 parse_cpair(cc, str)
1214 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1215 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1220 /* bg and attr are optional */
1221 textColors[(int)cc].bg = parse_color(str, 1);
1222 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1223 textColors[(int)cc].attr = 0;
1229 /* Arrange to catch delete-window events */
1230 Atom wm_delete_window;
1232 CatchDeleteWindow(Widget w, String procname)
1235 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1236 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1237 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1244 XtSetArg(args[0], XtNiconic, False);
1245 XtSetValues(shellWidget, args, 1);
1247 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1250 //---------------------------------------------------------------------------------------------------------
1251 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1254 #define CW_USEDEFAULT (1<<31)
1255 #define ICS_TEXT_MENU_SIZE 90
1256 #define DEBUG_FILE "xboard.debug"
1257 #define SetCurrentDirectory chdir
1258 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1262 // these two must some day move to frontend.h, when they are implemented
1263 Boolean GameListIsUp();
1265 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1268 // front-end part of option handling
1270 // [HGM] This platform-dependent table provides the location for storing the color info
1271 extern char *crWhite, * crBlack;
1275 &appData.whitePieceColor,
1276 &appData.blackPieceColor,
1277 &appData.lightSquareColor,
1278 &appData.darkSquareColor,
1279 &appData.highlightSquareColor,
1280 &appData.premoveHighlightColor,
1293 ParseFont(char *name, int number)
1294 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1296 case 0: // CLOCK_FONT
1297 appData.clockFont = strdup(name);
1299 case 1: // MESSAGE_FONT
1300 appData.font = strdup(name);
1302 case 2: // COORD_FONT
1303 appData.coordFont = strdup(name);
1312 { // only 2 fonts currently
1313 appData.clockFont = CLOCK_FONT_NAME;
1314 appData.coordFont = COORD_FONT_NAME;
1315 appData.font = DEFAULT_FONT_NAME;
1320 { // no-op, until we identify the code for this already in XBoard and move it here
1324 ParseColor(int n, char *name)
1325 { // in XBoard, just copy the color-name string
1326 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1330 ParseTextAttribs(ColorClass cc, char *s)
1332 (&appData.colorShout)[cc] = strdup(s);
1336 ParseBoardSize(void *addr, char *name)
1338 appData.boardSize = strdup(name);
1343 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1347 SetCommPortDefaults()
1348 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1351 // [HGM] args: these three cases taken out to stay in front-end
1353 SaveFontArg(FILE *f, ArgDescriptor *ad)
1356 switch((int)ad->argLoc) {
1357 case 0: // CLOCK_FONT
1358 name = appData.clockFont;
1360 case 1: // MESSAGE_FONT
1361 name = appData.font;
1363 case 2: // COORD_FONT
1364 name = appData.coordFont;
1369 // Do not save fonts for now, as the saved font would be board-size specific
1370 // and not suitable for a re-start at another board size
1371 // fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, name);
1376 { // nothing to do, as the sounds are at all times represented by their text-string names already
1380 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1381 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1382 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1386 SaveColor(FILE *f, ArgDescriptor *ad)
1387 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1388 if(colorVariable[(int)ad->argLoc])
1389 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1393 SaveBoardSize(FILE *f, char *name, void *addr)
1394 { // wrapper to shield back-end from BoardSize & sizeInfo
1395 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1399 ParseCommPortSettings(char *s)
1400 { // no such option in XBoard (yet)
1403 extern Widget engineOutputShell;
1404 extern Widget tagsShell, editTagsShell;
1406 GetActualPlacement(Widget wg, WindowPlacement *wp)
1416 XtSetArg(args[i], XtNx, &x); i++;
1417 XtSetArg(args[i], XtNy, &y); i++;
1418 XtSetArg(args[i], XtNwidth, &w); i++;
1419 XtSetArg(args[i], XtNheight, &h); i++;
1420 XtGetValues(wg, args, i);
1429 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1430 // In XBoard this will have to wait until awareness of window parameters is implemented
1431 GetActualPlacement(shellWidget, &wpMain);
1432 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1433 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1434 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1435 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1436 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1437 else GetActualPlacement(editShell, &wpComment);
1438 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1439 else GetActualPlacement(editTagsShell, &wpTags);
1443 PrintCommPortSettings(FILE *f, char *name)
1444 { // This option does not exist in XBoard
1448 MySearchPath(char *installDir, char *name, char *fullname)
1449 { // just append installDir and name. Perhaps ExpandPath should be used here?
1450 name = ExpandPathName(name);
1451 if(name && name[0] == '/') strcpy(fullname, name); else {
1452 sprintf(fullname, "%s%c%s", installDir, '/', name);
1458 MyGetFullPathName(char *name, char *fullname)
1459 { // should use ExpandPath?
1460 name = ExpandPathName(name);
1461 strcpy(fullname, name);
1466 EnsureOnScreen(int *x, int *y, int minX, int minY)
1473 { // [HGM] args: allows testing if main window is realized from back-end
1474 return xBoardWindow != 0;
1478 PopUpStartupDialog()
1479 { // start menu not implemented in XBoard
1482 ConvertToLine(int argc, char **argv)
1484 static char line[128*1024], buf[1024];
1488 for(i=1; i<argc; i++) {
1489 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1490 && argv[i][0] != '{' )
1491 sprintf(buf, "{%s} ", argv[i]);
1492 else sprintf(buf, "%s ", argv[i]);
1495 line[strlen(line)-1] = NULLCHAR;
1499 //--------------------------------------------------------------------------------------------
1502 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1504 #define BoardSize int
1505 void InitDrawingSizes(BoardSize boardSize, int flags)
1506 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1507 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1509 XtGeometryResult gres;
1512 if(!formWidget) return;
1515 * Enable shell resizing.
1517 shellArgs[0].value = (XtArgVal) &w;
1518 shellArgs[1].value = (XtArgVal) &h;
1519 XtGetValues(shellWidget, shellArgs, 2);
1521 shellArgs[4].value = 2*w; shellArgs[2].value = 10;
1522 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1523 XtSetValues(shellWidget, &shellArgs[2], 4);
1525 XtSetArg(args[0], XtNdefaultDistance, &sep);
1526 XtGetValues(formWidget, args, 1);
1528 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1529 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1532 XtSetArg(args[0], XtNwidth, boardWidth);
1533 XtSetArg(args[1], XtNheight, boardHeight);
1534 XtSetValues(boardWidget, args, 2);
1536 timerWidth = (boardWidth - sep) / 2;
1537 XtSetArg(args[0], XtNwidth, timerWidth);
1538 XtSetValues(whiteTimerWidget, args, 1);
1539 XtSetValues(blackTimerWidget, args, 1);
1541 XawFormDoLayout(formWidget, False);
1543 if (appData.titleInWindow) {
1545 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1546 XtSetArg(args[i], XtNheight, &h); i++;
1547 XtGetValues(titleWidget, args, i);
1549 w = boardWidth - 2*bor;
1551 XtSetArg(args[0], XtNwidth, &w);
1552 XtGetValues(menuBarWidget, args, 1);
1553 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1556 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1557 if (gres != XtGeometryYes && appData.debugMode) {
1559 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1560 programName, gres, w, h, wr, hr);
1564 XawFormDoLayout(formWidget, True);
1567 * Inhibit shell resizing.
1569 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW;
1570 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1571 shellArgs[4].value = shellArgs[2].value = w;
1572 shellArgs[5].value = shellArgs[3].value = h;
1573 XtSetValues(shellWidget, &shellArgs[0], 6);
1575 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1578 for(i=0; i<4; i++) {
1580 for(p=0; p<=(int)WhiteKing; p++)
1581 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1582 if(gameInfo.variant == VariantShogi) {
1583 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1584 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1585 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1586 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1587 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1590 if(gameInfo.variant == VariantGothic) {
1591 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1595 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1596 for(p=0; p<=(int)WhiteKing; p++)
1597 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1598 if(gameInfo.variant == VariantShogi) {
1599 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1600 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1601 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1602 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1603 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1606 if(gameInfo.variant == VariantGothic) {
1607 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1613 for(i=0; i<2; i++) {
1615 for(p=0; p<=(int)WhiteKing; p++)
1616 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1617 if(gameInfo.variant == VariantShogi) {
1618 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1619 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1620 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1621 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1622 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1625 if(gameInfo.variant == VariantGothic) {
1626 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1637 void EscapeExpand(char *p, char *q)
1638 { // [HGM] initstring: routine to shape up string arguments
1639 while(*p++ = *q++) if(p[-1] == '\\')
1641 case 'n': p[-1] = '\n'; break;
1642 case 'r': p[-1] = '\r'; break;
1643 case 't': p[-1] = '\t'; break;
1644 case '\\': p[-1] = '\\'; break;
1645 case 0: *p = 0; return;
1646 default: p[-1] = q[-1]; break;
1655 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1656 XSetWindowAttributes window_attributes;
1658 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1659 XrmValue vFrom, vTo;
1660 XtGeometryResult gres;
1663 int forceMono = False;
1665 srandom(time(0)); // [HGM] book: make random truly random
1667 setbuf(stdout, NULL);
1668 setbuf(stderr, NULL);
1671 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1672 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1676 programName = strrchr(argv[0], '/');
1677 if (programName == NULL)
1678 programName = argv[0];
1683 XtSetLanguageProc(NULL, NULL, NULL);
1684 bindtextdomain(PACKAGE, LOCALEDIR);
1685 textdomain(PACKAGE);
1689 XtAppInitialize(&appContext, "XBoard", shellOptions,
1690 XtNumber(shellOptions),
1691 &argc, argv, xboardResources, NULL, 0);
1692 appData.boardSize = "";
1693 InitAppData(ConvertToLine(argc, argv));
1695 if (p == NULL) p = "/tmp";
1696 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1697 gameCopyFilename = (char*) malloc(i);
1698 gamePasteFilename = (char*) malloc(i);
1699 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1700 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1702 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1703 clientResources, XtNumber(clientResources),
1706 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1707 static char buf[MSG_SIZ];
1708 EscapeExpand(buf, appData.initString);
1709 appData.initString = strdup(buf);
1710 EscapeExpand(buf, appData.secondInitString);
1711 appData.secondInitString = strdup(buf);
1712 EscapeExpand(buf, appData.firstComputerString);
1713 appData.firstComputerString = strdup(buf);
1714 EscapeExpand(buf, appData.secondComputerString);
1715 appData.secondComputerString = strdup(buf);
1718 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1721 if (chdir(chessDir) != 0) {
1722 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1728 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1729 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1730 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1731 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1734 setbuf(debugFP, NULL);
1737 /* [HGM,HR] make sure board size is acceptable */
1738 if(appData.NrFiles > BOARD_FILES ||
1739 appData.NrRanks > BOARD_RANKS )
1740 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1743 /* This feature does not work; animation needs a rewrite */
1744 appData.highlightDragging = FALSE;
1748 xDisplay = XtDisplay(shellWidget);
1749 xScreen = DefaultScreen(xDisplay);
1750 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1752 gameInfo.variant = StringToVariant(appData.variant);
1753 InitPosition(FALSE);
1756 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1758 if (isdigit(appData.boardSize[0])) {
1759 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1760 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1761 &fontPxlSize, &smallLayout, &tinyLayout);
1763 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1764 programName, appData.boardSize);
1768 /* Find some defaults; use the nearest known size */
1769 SizeDefaults *szd, *nearest;
1770 int distance = 99999;
1771 nearest = szd = sizeDefaults;
1772 while (szd->name != NULL) {
1773 if (abs(szd->squareSize - squareSize) < distance) {
1775 distance = abs(szd->squareSize - squareSize);
1776 if (distance == 0) break;
1780 if (i < 2) lineGap = nearest->lineGap;
1781 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1782 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1783 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1784 if (i < 6) smallLayout = nearest->smallLayout;
1785 if (i < 7) tinyLayout = nearest->tinyLayout;
1788 SizeDefaults *szd = sizeDefaults;
1789 if (*appData.boardSize == NULLCHAR) {
1790 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1791 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1794 if (szd->name == NULL) szd--;
1795 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1797 while (szd->name != NULL &&
1798 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1799 if (szd->name == NULL) {
1800 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1801 programName, appData.boardSize);
1805 squareSize = szd->squareSize;
1806 lineGap = szd->lineGap;
1807 clockFontPxlSize = szd->clockFontPxlSize;
1808 coordFontPxlSize = szd->coordFontPxlSize;
1809 fontPxlSize = szd->fontPxlSize;
1810 smallLayout = szd->smallLayout;
1811 tinyLayout = szd->tinyLayout;
1814 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1815 if (strlen(appData.pixmapDirectory) > 0) {
1816 p = ExpandPathName(appData.pixmapDirectory);
1818 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1819 appData.pixmapDirectory);
1822 if (appData.debugMode) {
1823 fprintf(stderr, _("\
1824 XBoard square size (hint): %d\n\
1825 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1827 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1828 if (appData.debugMode) {
1829 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1833 /* [HR] height treated separately (hacked) */
1834 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1835 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1836 if (appData.showJail == 1) {
1837 /* Jail on top and bottom */
1838 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1839 XtSetArg(boardArgs[2], XtNheight,
1840 boardHeight + 2*(lineGap + squareSize));
1841 } else if (appData.showJail == 2) {
1843 XtSetArg(boardArgs[1], XtNwidth,
1844 boardWidth + 2*(lineGap + squareSize));
1845 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1848 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1849 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1853 * Determine what fonts to use.
1855 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1856 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1857 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1858 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1859 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1860 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1861 appData.font = FindFont(appData.font, fontPxlSize);
1862 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1863 countFontStruct = XQueryFont(xDisplay, countFontID);
1864 // appData.font = FindFont(appData.font, fontPxlSize);
1866 xdb = XtDatabase(xDisplay);
1867 XrmPutStringResource(&xdb, "*font", appData.font);
1870 * Detect if there are not enough colors available and adapt.
1872 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1873 appData.monoMode = True;
1876 if (!appData.monoMode) {
1877 vFrom.addr = (caddr_t) appData.lightSquareColor;
1878 vFrom.size = strlen(appData.lightSquareColor);
1879 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1880 if (vTo.addr == NULL) {
1881 appData.monoMode = True;
1884 lightSquareColor = *(Pixel *) vTo.addr;
1887 if (!appData.monoMode) {
1888 vFrom.addr = (caddr_t) appData.darkSquareColor;
1889 vFrom.size = strlen(appData.darkSquareColor);
1890 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1891 if (vTo.addr == NULL) {
1892 appData.monoMode = True;
1895 darkSquareColor = *(Pixel *) vTo.addr;
1898 if (!appData.monoMode) {
1899 vFrom.addr = (caddr_t) appData.whitePieceColor;
1900 vFrom.size = strlen(appData.whitePieceColor);
1901 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1902 if (vTo.addr == NULL) {
1903 appData.monoMode = True;
1906 whitePieceColor = *(Pixel *) vTo.addr;
1909 if (!appData.monoMode) {
1910 vFrom.addr = (caddr_t) appData.blackPieceColor;
1911 vFrom.size = strlen(appData.blackPieceColor);
1912 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1913 if (vTo.addr == NULL) {
1914 appData.monoMode = True;
1917 blackPieceColor = *(Pixel *) vTo.addr;
1921 if (!appData.monoMode) {
1922 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1923 vFrom.size = strlen(appData.highlightSquareColor);
1924 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1925 if (vTo.addr == NULL) {
1926 appData.monoMode = True;
1929 highlightSquareColor = *(Pixel *) vTo.addr;
1933 if (!appData.monoMode) {
1934 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1935 vFrom.size = strlen(appData.premoveHighlightColor);
1936 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1937 if (vTo.addr == NULL) {
1938 appData.monoMode = True;
1941 premoveHighlightColor = *(Pixel *) vTo.addr;
1946 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1949 if (appData.bitmapDirectory == NULL ||
1950 appData.bitmapDirectory[0] == NULLCHAR)
1951 appData.bitmapDirectory = DEF_BITMAP_DIR;
1954 if (appData.lowTimeWarning && !appData.monoMode) {
1955 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
1956 vFrom.size = strlen(appData.lowTimeWarningColor);
1957 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1958 if (vTo.addr == NULL)
1959 appData.monoMode = True;
1961 lowTimeWarningColor = *(Pixel *) vTo.addr;
1964 if (appData.monoMode && appData.debugMode) {
1965 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1966 (unsigned long) XWhitePixel(xDisplay, xScreen),
1967 (unsigned long) XBlackPixel(xDisplay, xScreen));
1970 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1971 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1972 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1973 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1974 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1975 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1976 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1977 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1978 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1979 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1981 if (appData.colorize) {
1983 _("%s: can't parse color names; disabling colorization\n"),
1986 appData.colorize = FALSE;
1988 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
1989 textColors[ColorNone].attr = 0;
1991 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
1997 layoutName = "tinyLayout";
1998 } else if (smallLayout) {
1999 layoutName = "smallLayout";
2001 layoutName = "normalLayout";
2003 /* Outer layoutWidget is there only to provide a name for use in
2004 resources that depend on the layout style */
2006 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2007 layoutArgs, XtNumber(layoutArgs));
2009 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2010 formArgs, XtNumber(formArgs));
2011 XtSetArg(args[0], XtNdefaultDistance, &sep);
2012 XtGetValues(formWidget, args, 1);
2015 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2016 XtSetArg(args[0], XtNtop, XtChainTop);
2017 XtSetArg(args[1], XtNbottom, XtChainTop);
2018 XtSetArg(args[2], XtNright, XtChainLeft);
2019 XtSetValues(menuBarWidget, args, 3);
2021 widgetList[j++] = whiteTimerWidget =
2022 XtCreateWidget("whiteTime", labelWidgetClass,
2023 formWidget, timerArgs, XtNumber(timerArgs));
2024 XtSetArg(args[0], XtNfont, clockFontStruct);
2025 XtSetArg(args[1], XtNtop, XtChainTop);
2026 XtSetArg(args[2], XtNbottom, XtChainTop);
2027 XtSetValues(whiteTimerWidget, args, 3);
2029 widgetList[j++] = blackTimerWidget =
2030 XtCreateWidget("blackTime", labelWidgetClass,
2031 formWidget, timerArgs, XtNumber(timerArgs));
2032 XtSetArg(args[0], XtNfont, clockFontStruct);
2033 XtSetArg(args[1], XtNtop, XtChainTop);
2034 XtSetArg(args[2], XtNbottom, XtChainTop);
2035 XtSetValues(blackTimerWidget, args, 3);
2037 if (appData.titleInWindow) {
2038 widgetList[j++] = titleWidget =
2039 XtCreateWidget("title", labelWidgetClass, formWidget,
2040 titleArgs, XtNumber(titleArgs));
2041 XtSetArg(args[0], XtNtop, XtChainTop);
2042 XtSetArg(args[1], XtNbottom, XtChainTop);
2043 XtSetValues(titleWidget, args, 2);
2046 if (appData.showButtonBar) {
2047 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2048 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2049 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2050 XtSetArg(args[2], XtNtop, XtChainTop);
2051 XtSetArg(args[3], XtNbottom, XtChainTop);
2052 XtSetValues(buttonBarWidget, args, 4);
2055 widgetList[j++] = messageWidget =
2056 XtCreateWidget("message", labelWidgetClass, formWidget,
2057 messageArgs, XtNumber(messageArgs));
2058 XtSetArg(args[0], XtNtop, XtChainTop);
2059 XtSetArg(args[1], XtNbottom, XtChainTop);
2060 XtSetValues(messageWidget, args, 2);
2062 widgetList[j++] = boardWidget =
2063 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2064 XtNumber(boardArgs));
2066 XtManageChildren(widgetList, j);
2068 timerWidth = (boardWidth - sep) / 2;
2069 XtSetArg(args[0], XtNwidth, timerWidth);
2070 XtSetValues(whiteTimerWidget, args, 1);
2071 XtSetValues(blackTimerWidget, args, 1);
2073 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2074 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2075 XtGetValues(whiteTimerWidget, args, 2);
2077 if (appData.showButtonBar) {
2078 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2079 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2080 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2084 * formWidget uses these constraints but they are stored
2088 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2089 XtSetValues(menuBarWidget, args, i);
2090 if (appData.titleInWindow) {
2093 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2094 XtSetValues(whiteTimerWidget, args, i);
2096 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2097 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2098 XtSetValues(blackTimerWidget, args, i);
2100 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2101 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2102 XtSetValues(titleWidget, args, i);
2104 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2105 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2106 XtSetValues(messageWidget, args, i);
2107 if (appData.showButtonBar) {
2109 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2110 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2111 XtSetValues(buttonBarWidget, args, i);
2115 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2116 XtSetValues(whiteTimerWidget, args, i);
2118 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2119 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2120 XtSetValues(blackTimerWidget, args, i);
2122 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2123 XtSetValues(titleWidget, args, i);
2125 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2126 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2127 XtSetValues(messageWidget, args, i);
2128 if (appData.showButtonBar) {
2130 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2131 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2132 XtSetValues(buttonBarWidget, args, i);
2137 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2138 XtSetValues(whiteTimerWidget, args, i);
2140 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2141 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2142 XtSetValues(blackTimerWidget, args, i);
2144 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2145 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2146 XtSetValues(messageWidget, args, i);
2147 if (appData.showButtonBar) {
2149 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2150 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2151 XtSetValues(buttonBarWidget, args, i);
2155 XtSetArg(args[0], XtNfromVert, messageWidget);
2156 XtSetArg(args[1], XtNtop, XtChainTop);
2157 XtSetArg(args[2], XtNbottom, XtChainBottom);
2158 XtSetArg(args[3], XtNleft, XtChainLeft);
2159 XtSetArg(args[4], XtNright, XtChainRight);
2160 XtSetValues(boardWidget, args, 5);
2162 XtRealizeWidget(shellWidget);
2165 XtSetArg(args[0], XtNx, wpMain.x);
2166 XtSetArg(args[1], XtNy, wpMain.y);
2167 XtSetValues(shellWidget, args, 2);
2171 * Correct the width of the message and title widgets.
2172 * It is not known why some systems need the extra fudge term.
2173 * The value "2" is probably larger than needed.
2175 XawFormDoLayout(formWidget, False);
2177 #define WIDTH_FUDGE 2
2179 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2180 XtSetArg(args[i], XtNheight, &h); i++;
2181 XtGetValues(messageWidget, args, i);
2182 if (appData.showButtonBar) {
2184 XtSetArg(args[i], XtNwidth, &w); i++;
2185 XtGetValues(buttonBarWidget, args, i);
2186 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2188 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2191 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2192 if (gres != XtGeometryYes && appData.debugMode) {
2193 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2194 programName, gres, w, h, wr, hr);
2197 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2198 /* The size used for the child widget in layout lags one resize behind
2199 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2201 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2202 if (gres != XtGeometryYes && appData.debugMode) {
2203 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2204 programName, gres, w, h, wr, hr);
2207 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2208 XtSetArg(args[1], XtNright, XtChainRight);
2209 XtSetValues(messageWidget, args, 2);
2211 if (appData.titleInWindow) {
2213 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2214 XtSetArg(args[i], XtNheight, &h); i++;
2215 XtGetValues(titleWidget, args, i);
2217 w = boardWidth - 2*bor;
2219 XtSetArg(args[0], XtNwidth, &w);
2220 XtGetValues(menuBarWidget, args, 1);
2221 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2224 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2225 if (gres != XtGeometryYes && appData.debugMode) {
2227 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2228 programName, gres, w, h, wr, hr);
2231 XawFormDoLayout(formWidget, True);
2233 xBoardWindow = XtWindow(boardWidget);
2235 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2236 // not need to go into InitDrawingSizes().
2240 * Create X checkmark bitmap and initialize option menu checks.
2242 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2243 checkmark_bits, checkmark_width, checkmark_height);
2244 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2245 if (appData.alwaysPromoteToQueen) {
2246 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2249 if (appData.animateDragging) {
2250 XtSetValues(XtNameToWidget(menuBarWidget,
2251 "menuOptions.Animate Dragging"),
2254 if (appData.animate) {
2255 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2258 if (appData.autoComment) {
2259 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2262 if (appData.autoCallFlag) {
2263 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2266 if (appData.autoFlipView) {
2267 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2270 if (appData.autoObserve) {
2271 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2274 if (appData.autoRaiseBoard) {
2275 XtSetValues(XtNameToWidget(menuBarWidget,
2276 "menuOptions.Auto Raise Board"), args, 1);
2278 if (appData.autoSaveGames) {
2279 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2282 if (appData.saveGameFile[0] != NULLCHAR) {
2283 /* Can't turn this off from menu */
2284 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2286 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2290 if (appData.blindfold) {
2291 XtSetValues(XtNameToWidget(menuBarWidget,
2292 "menuOptions.Blindfold"), args, 1);
2294 if (appData.flashCount > 0) {
2295 XtSetValues(XtNameToWidget(menuBarWidget,
2296 "menuOptions.Flash Moves"),
2299 if (appData.getMoveList) {
2300 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2304 if (appData.highlightDragging) {
2305 XtSetValues(XtNameToWidget(menuBarWidget,
2306 "menuOptions.Highlight Dragging"),
2310 if (appData.highlightLastMove) {
2311 XtSetValues(XtNameToWidget(menuBarWidget,
2312 "menuOptions.Highlight Last Move"),
2315 if (appData.icsAlarm) {
2316 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2319 if (appData.ringBellAfterMoves) {
2320 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2323 if (appData.oldSaveStyle) {
2324 XtSetValues(XtNameToWidget(menuBarWidget,
2325 "menuOptions.Old Save Style"), args, 1);
2327 if (appData.periodicUpdates) {
2328 XtSetValues(XtNameToWidget(menuBarWidget,
2329 "menuOptions.Periodic Updates"), args, 1);
2331 if (appData.ponderNextMove) {
2332 XtSetValues(XtNameToWidget(menuBarWidget,
2333 "menuOptions.Ponder Next Move"), args, 1);
2335 if (appData.popupExitMessage) {
2336 XtSetValues(XtNameToWidget(menuBarWidget,
2337 "menuOptions.Popup Exit Message"), args, 1);
2339 if (appData.popupMoveErrors) {
2340 XtSetValues(XtNameToWidget(menuBarWidget,
2341 "menuOptions.Popup Move Errors"), args, 1);
2343 if (appData.premove) {
2344 XtSetValues(XtNameToWidget(menuBarWidget,
2345 "menuOptions.Premove"), args, 1);
2347 if (appData.quietPlay) {
2348 XtSetValues(XtNameToWidget(menuBarWidget,
2349 "menuOptions.Quiet Play"), args, 1);
2351 if (appData.showCoords) {
2352 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2355 if (appData.hideThinkingFromHuman) {
2356 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2359 if (appData.testLegality) {
2360 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2363 if (saveSettingsOnExit) {
2364 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2371 ReadBitmap(&wIconPixmap, "icon_white.bm",
2372 icon_white_bits, icon_white_width, icon_white_height);
2373 ReadBitmap(&bIconPixmap, "icon_black.bm",
2374 icon_black_bits, icon_black_width, icon_black_height);
2375 iconPixmap = wIconPixmap;
2377 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2378 XtSetValues(shellWidget, args, i);
2381 * Create a cursor for the board widget.
2383 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2384 XChangeWindowAttributes(xDisplay, xBoardWindow,
2385 CWCursor, &window_attributes);
2388 * Inhibit shell resizing.
2390 shellArgs[0].value = (XtArgVal) &w;
2391 shellArgs[1].value = (XtArgVal) &h;
2392 XtGetValues(shellWidget, shellArgs, 2);
2393 shellArgs[4].value = shellArgs[2].value = w;
2394 shellArgs[5].value = shellArgs[3].value = h;
2395 XtSetValues(shellWidget, &shellArgs[2], 4);
2396 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2397 marginH = h - boardHeight;
2399 CatchDeleteWindow(shellWidget, "QuitProc");
2404 if (appData.bitmapDirectory[0] != NULLCHAR) {
2411 /* Create regular pieces */
2412 if (!useImages) CreatePieces();
2417 if (appData.animate || appData.animateDragging)
2420 XtAugmentTranslations(formWidget,
2421 XtParseTranslationTable(globalTranslations));
2422 XtAugmentTranslations(boardWidget,
2423 XtParseTranslationTable(boardTranslations));
2424 XtAugmentTranslations(whiteTimerWidget,
2425 XtParseTranslationTable(whiteTranslations));
2426 XtAugmentTranslations(blackTimerWidget,
2427 XtParseTranslationTable(blackTranslations));
2429 /* Why is the following needed on some versions of X instead
2430 * of a translation? */
2431 XtAddEventHandler(boardWidget, ExposureMask, False,
2432 (XtEventHandler) EventProc, NULL);
2435 /* [AS] Restore layout */
2436 if( wpMoveHistory.visible ) {
2440 if( wpEvalGraph.visible )
2445 if( wpEngineOutput.visible ) {
2446 EngineOutputPopUp();
2451 if (errorExitStatus == -1) {
2452 if (appData.icsActive) {
2453 /* We now wait until we see "login:" from the ICS before
2454 sending the logon script (problems with timestamp otherwise) */
2455 /*ICSInitScript();*/
2456 if (appData.icsInputBox) ICSInputBoxPopUp();
2460 signal(SIGWINCH, TermSizeSigHandler);
2462 signal(SIGINT, IntSigHandler);
2463 signal(SIGTERM, IntSigHandler);
2464 if (*appData.cmailGameName != NULLCHAR) {
2465 signal(SIGUSR1, CmailSigHandler);
2468 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2471 XtAppMainLoop(appContext);
2472 if (appData.debugMode) fclose(debugFP); // [DM] debug
2479 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2480 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2482 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2483 unlink(gameCopyFilename);
2484 unlink(gamePasteFilename);
2487 RETSIGTYPE TermSizeSigHandler(int sig)
2500 CmailSigHandler(sig)
2506 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2508 /* Activate call-back function CmailSigHandlerCallBack() */
2509 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2511 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2515 CmailSigHandlerCallBack(isr, closure, message, count, error)
2523 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2525 /**** end signal code ****/
2535 f = fopen(appData.icsLogon, "r");
2541 strcat(buf, appData.icsLogon);
2542 f = fopen(buf, "r");
2546 ProcessICSInitScript(f);
2553 EditCommentPopDown();
2568 if (!menuBarWidget) return;
2569 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2571 DisplayError("menuStep.Revert", 0);
2573 XtSetSensitive(w, !grey);
2578 SetMenuEnables(enab)
2582 if (!menuBarWidget) return;
2583 while (enab->name != NULL) {
2584 w = XtNameToWidget(menuBarWidget, enab->name);
2586 DisplayError(enab->name, 0);
2588 XtSetSensitive(w, enab->value);
2594 Enables icsEnables[] = {
2595 { "menuFile.Mail Move", False },
2596 { "menuFile.Reload CMail Message", False },
2597 { "menuMode.Machine Black", False },
2598 { "menuMode.Machine White", False },
2599 { "menuMode.Analysis Mode", False },
2600 { "menuMode.Analyze File", False },
2601 { "menuMode.Two Machines", False },
2603 { "menuHelp.Hint", False },
2604 { "menuHelp.Book", False },
2605 { "menuStep.Move Now", False },
2606 { "menuOptions.Periodic Updates", False },
2607 { "menuOptions.Hide Thinking", False },
2608 { "menuOptions.Ponder Next Move", False },
2613 Enables ncpEnables[] = {
2614 { "menuFile.Mail Move", False },
2615 { "menuFile.Reload CMail Message", False },
2616 { "menuMode.Machine White", False },
2617 { "menuMode.Machine Black", False },
2618 { "menuMode.Analysis Mode", False },
2619 { "menuMode.Analyze File", False },
2620 { "menuMode.Two Machines", False },
2621 { "menuMode.ICS Client", False },
2622 { "menuMode.ICS Input Box", False },
2623 { "Action", False },
2624 { "menuStep.Revert", False },
2625 { "menuStep.Move Now", False },
2626 { "menuStep.Retract Move", False },
2627 { "menuOptions.Auto Comment", False },
2628 { "menuOptions.Auto Flag", False },
2629 { "menuOptions.Auto Flip View", False },
2630 { "menuOptions.Auto Observe", False },
2631 { "menuOptions.Auto Raise Board", False },
2632 { "menuOptions.Get Move List", False },
2633 { "menuOptions.ICS Alarm", False },
2634 { "menuOptions.Move Sound", False },
2635 { "menuOptions.Quiet Play", False },
2636 { "menuOptions.Hide Thinking", False },
2637 { "menuOptions.Periodic Updates", False },
2638 { "menuOptions.Ponder Next Move", False },
2639 { "menuHelp.Hint", False },
2640 { "menuHelp.Book", False },
2644 Enables gnuEnables[] = {
2645 { "menuMode.ICS Client", False },
2646 { "menuMode.ICS Input Box", False },
2647 { "menuAction.Accept", False },
2648 { "menuAction.Decline", False },
2649 { "menuAction.Rematch", False },
2650 { "menuAction.Adjourn", False },
2651 { "menuAction.Stop Examining", False },
2652 { "menuAction.Stop Observing", False },
2653 { "menuStep.Revert", False },
2654 { "menuOptions.Auto Comment", False },
2655 { "menuOptions.Auto Observe", False },
2656 { "menuOptions.Auto Raise Board", False },
2657 { "menuOptions.Get Move List", False },
2658 { "menuOptions.Premove", False },
2659 { "menuOptions.Quiet Play", False },
2661 /* The next two options rely on SetCmailMode being called *after* */
2662 /* SetGNUMode so that when GNU is being used to give hints these */
2663 /* menu options are still available */
2665 { "menuFile.Mail Move", False },
2666 { "menuFile.Reload CMail Message", False },
2670 Enables cmailEnables[] = {
2672 { "menuAction.Call Flag", False },
2673 { "menuAction.Draw", True },
2674 { "menuAction.Adjourn", False },
2675 { "menuAction.Abort", False },
2676 { "menuAction.Stop Observing", False },
2677 { "menuAction.Stop Examining", False },
2678 { "menuFile.Mail Move", True },
2679 { "menuFile.Reload CMail Message", True },
2683 Enables trainingOnEnables[] = {
2684 { "menuMode.Edit Comment", False },
2685 { "menuMode.Pause", False },
2686 { "menuStep.Forward", False },
2687 { "menuStep.Backward", False },
2688 { "menuStep.Forward to End", False },
2689 { "menuStep.Back to Start", False },
2690 { "menuStep.Move Now", False },
2691 { "menuStep.Truncate Game", False },
2695 Enables trainingOffEnables[] = {
2696 { "menuMode.Edit Comment", True },
2697 { "menuMode.Pause", True },
2698 { "menuStep.Forward", True },
2699 { "menuStep.Backward", True },
2700 { "menuStep.Forward to End", True },
2701 { "menuStep.Back to Start", True },
2702 { "menuStep.Move Now", True },
2703 { "menuStep.Truncate Game", True },
2707 Enables machineThinkingEnables[] = {
2708 { "menuFile.Load Game", False },
2709 { "menuFile.Load Next Game", False },
2710 { "menuFile.Load Previous Game", False },
2711 { "menuFile.Reload Same Game", False },
2712 { "menuFile.Paste Game", False },
2713 { "menuFile.Load Position", False },
2714 { "menuFile.Load Next Position", False },
2715 { "menuFile.Load Previous Position", False },
2716 { "menuFile.Reload Same Position", False },
2717 { "menuFile.Paste Position", False },
2718 { "menuMode.Machine White", False },
2719 { "menuMode.Machine Black", False },
2720 { "menuMode.Two Machines", False },
2721 { "menuStep.Retract Move", False },
2725 Enables userThinkingEnables[] = {
2726 { "menuFile.Load Game", True },
2727 { "menuFile.Load Next Game", True },
2728 { "menuFile.Load Previous Game", True },
2729 { "menuFile.Reload Same Game", True },
2730 { "menuFile.Paste Game", True },
2731 { "menuFile.Load Position", True },
2732 { "menuFile.Load Next Position", True },
2733 { "menuFile.Load Previous Position", True },
2734 { "menuFile.Reload Same Position", True },
2735 { "menuFile.Paste Position", True },
2736 { "menuMode.Machine White", True },
2737 { "menuMode.Machine Black", True },
2738 { "menuMode.Two Machines", True },
2739 { "menuStep.Retract Move", True },
2745 SetMenuEnables(icsEnables);
2748 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2749 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2756 SetMenuEnables(ncpEnables);
2762 SetMenuEnables(gnuEnables);
2768 SetMenuEnables(cmailEnables);
2774 SetMenuEnables(trainingOnEnables);
2775 if (appData.showButtonBar) {
2776 XtSetSensitive(buttonBarWidget, False);
2782 SetTrainingModeOff()
2784 SetMenuEnables(trainingOffEnables);
2785 if (appData.showButtonBar) {
2786 XtSetSensitive(buttonBarWidget, True);
2791 SetUserThinkingEnables()
2793 if (appData.noChessProgram) return;
2794 SetMenuEnables(userThinkingEnables);
2798 SetMachineThinkingEnables()
2800 if (appData.noChessProgram) return;
2801 SetMenuEnables(machineThinkingEnables);
2803 case MachinePlaysBlack:
2804 case MachinePlaysWhite:
2805 case TwoMachinesPlay:
2806 XtSetSensitive(XtNameToWidget(menuBarWidget,
2807 ModeToWidgetName(gameMode)), True);
2814 #define Abs(n) ((n)<0 ? -(n) : (n))
2817 * Find a font that matches "pattern" that is as close as
2818 * possible to the targetPxlSize. Prefer fonts that are k
2819 * pixels smaller to fonts that are k pixels larger. The
2820 * pattern must be in the X Consortium standard format,
2821 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2822 * The return value should be freed with XtFree when no
2825 char *FindFont(pattern, targetPxlSize)
2829 char **fonts, *p, *best, *scalable, *scalableTail;
2830 int i, j, nfonts, minerr, err, pxlSize;
2833 char **missing_list;
2835 char *def_string, *base_fnt_lst, strInt[3];
2837 XFontStruct **fnt_list;
2839 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2840 sprintf(strInt, "%d", targetPxlSize);
2841 p = strstr(pattern, "--");
2842 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2843 strcat(base_fnt_lst, strInt);
2844 strcat(base_fnt_lst, strchr(p + 2, '-'));
2846 if ((fntSet = XCreateFontSet(xDisplay,
2850 &def_string)) == NULL) {
2852 fprintf(stderr, _("Unable to create font set.\n"));
2856 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2858 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2860 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2861 programName, pattern);
2869 for (i=0; i<nfonts; i++) {
2872 if (*p != '-') continue;
2874 if (*p == NULLCHAR) break;
2875 if (*p++ == '-') j++;
2877 if (j < 7) continue;
2880 scalable = fonts[i];
2883 err = pxlSize - targetPxlSize;
2884 if (Abs(err) < Abs(minerr) ||
2885 (minerr > 0 && err < 0 && -err == minerr)) {
2891 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
2892 /* If the error is too big and there is a scalable font,
2893 use the scalable font. */
2894 int headlen = scalableTail - scalable;
2895 p = (char *) XtMalloc(strlen(scalable) + 10);
2896 while (isdigit(*scalableTail)) scalableTail++;
2897 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
2899 p = (char *) XtMalloc(strlen(best) + 1);
2902 if (appData.debugMode) {
2903 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
2904 pattern, targetPxlSize, p);
2907 if (missing_count > 0)
2908 XFreeStringList(missing_list);
2909 XFreeFontSet(xDisplay, fntSet);
2911 XFreeFontNames(fonts);
2918 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
2919 | GCBackground | GCFunction | GCPlaneMask;
2920 XGCValues gc_values;
2923 gc_values.plane_mask = AllPlanes;
2924 gc_values.line_width = lineGap;
2925 gc_values.line_style = LineSolid;
2926 gc_values.function = GXcopy;
2928 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2929 gc_values.background = XBlackPixel(xDisplay, xScreen);
2930 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2932 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2933 gc_values.background = XWhitePixel(xDisplay, xScreen);
2934 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
2935 XSetFont(xDisplay, coordGC, coordFontID);
2937 // [HGM] make font for holdings counts (white on black0
2938 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2939 gc_values.background = XBlackPixel(xDisplay, xScreen);
2940 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
2941 XSetFont(xDisplay, countGC, countFontID);
2943 if (appData.monoMode) {
2944 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2945 gc_values.background = XWhitePixel(xDisplay, xScreen);
2946 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2948 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2949 gc_values.background = XBlackPixel(xDisplay, xScreen);
2950 lightSquareGC = wbPieceGC
2951 = XtGetGC(shellWidget, value_mask, &gc_values);
2953 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2954 gc_values.background = XWhitePixel(xDisplay, xScreen);
2955 darkSquareGC = bwPieceGC
2956 = XtGetGC(shellWidget, value_mask, &gc_values);
2958 if (DefaultDepth(xDisplay, xScreen) == 1) {
2959 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
2960 gc_values.function = GXcopyInverted;
2961 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
2962 gc_values.function = GXcopy;
2963 if (XBlackPixel(xDisplay, xScreen) == 1) {
2964 bwPieceGC = darkSquareGC;
2965 wbPieceGC = copyInvertedGC;
2967 bwPieceGC = copyInvertedGC;
2968 wbPieceGC = lightSquareGC;
2972 gc_values.foreground = highlightSquareColor;
2973 gc_values.background = highlightSquareColor;
2974 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2976 gc_values.foreground = premoveHighlightColor;
2977 gc_values.background = premoveHighlightColor;
2978 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2980 gc_values.foreground = lightSquareColor;
2981 gc_values.background = darkSquareColor;
2982 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2984 gc_values.foreground = darkSquareColor;
2985 gc_values.background = lightSquareColor;
2986 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2988 gc_values.foreground = jailSquareColor;
2989 gc_values.background = jailSquareColor;
2990 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2992 gc_values.foreground = whitePieceColor;
2993 gc_values.background = darkSquareColor;
2994 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
2996 gc_values.foreground = whitePieceColor;
2997 gc_values.background = lightSquareColor;
2998 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3000 gc_values.foreground = whitePieceColor;
3001 gc_values.background = jailSquareColor;
3002 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3004 gc_values.foreground = blackPieceColor;
3005 gc_values.background = darkSquareColor;
3006 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3008 gc_values.foreground = blackPieceColor;
3009 gc_values.background = lightSquareColor;
3010 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3012 gc_values.foreground = blackPieceColor;
3013 gc_values.background = jailSquareColor;
3014 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3018 void loadXIM(xim, xmask, filename, dest, mask)
3031 fp = fopen(filename, "rb");
3033 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3040 for (y=0; y<h; ++y) {
3041 for (x=0; x<h; ++x) {
3046 XPutPixel(xim, x, y, blackPieceColor);
3048 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3051 XPutPixel(xim, x, y, darkSquareColor);
3053 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3056 XPutPixel(xim, x, y, whitePieceColor);
3058 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3061 XPutPixel(xim, x, y, lightSquareColor);
3063 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3069 /* create Pixmap of piece */
3070 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3072 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3075 /* create Pixmap of clipmask
3076 Note: We assume the white/black pieces have the same
3077 outline, so we make only 6 masks. This is okay
3078 since the XPM clipmask routines do the same. */
3080 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3082 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3085 /* now create the 1-bit version */
3086 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3089 values.foreground = 1;
3090 values.background = 0;
3092 /* Don't use XtGetGC, not read only */
3093 maskGC = XCreateGC(xDisplay, *mask,
3094 GCForeground | GCBackground, &values);
3095 XCopyPlane(xDisplay, temp, *mask, maskGC,
3096 0, 0, squareSize, squareSize, 0, 0, 1);
3097 XFreePixmap(xDisplay, temp);
3102 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3104 void CreateXIMPieces()
3109 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3114 /* The XSynchronize calls were copied from CreatePieces.
3115 Not sure if needed, but can't hurt */
3116 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3119 /* temp needed by loadXIM() */
3120 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3121 0, 0, ss, ss, AllPlanes, XYPixmap);
3123 if (strlen(appData.pixmapDirectory) == 0) {
3127 if (appData.monoMode) {
3128 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3132 fprintf(stderr, _("\nLoading XIMs...\n"));
3134 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3135 fprintf(stderr, "%d", piece+1);
3136 for (kind=0; kind<4; kind++) {
3137 fprintf(stderr, ".");
3138 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3139 ExpandPathName(appData.pixmapDirectory),
3140 piece <= (int) WhiteKing ? "" : "w",
3141 pieceBitmapNames[piece],
3143 ximPieceBitmap[kind][piece] =
3144 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3145 0, 0, ss, ss, AllPlanes, XYPixmap);
3146 if (appData.debugMode)
3147 fprintf(stderr, _("(File:%s:) "), buf);
3148 loadXIM(ximPieceBitmap[kind][piece],
3150 &(xpmPieceBitmap2[kind][piece]),
3151 &(ximMaskPm2[piece]));
3152 if(piece <= (int)WhiteKing)
3153 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3155 fprintf(stderr," ");
3157 /* Load light and dark squares */
3158 /* If the LSQ and DSQ pieces don't exist, we will
3159 draw them with solid squares. */
3160 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3161 if (access(buf, 0) != 0) {
3165 fprintf(stderr, _("light square "));
3167 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3168 0, 0, ss, ss, AllPlanes, XYPixmap);
3169 if (appData.debugMode)
3170 fprintf(stderr, _("(File:%s:) "), buf);
3172 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3173 fprintf(stderr, _("dark square "));
3174 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3175 ExpandPathName(appData.pixmapDirectory), ss);
3176 if (appData.debugMode)
3177 fprintf(stderr, _("(File:%s:) "), buf);
3179 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3180 0, 0, ss, ss, AllPlanes, XYPixmap);
3181 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3182 xpmJailSquare = xpmLightSquare;
3184 fprintf(stderr, _("Done.\n"));
3186 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3190 void CreateXPMPieces()
3194 u_int ss = squareSize;
3196 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3197 XpmColorSymbol symbols[4];
3199 /* The XSynchronize calls were copied from CreatePieces.
3200 Not sure if needed, but can't hurt */
3201 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3203 /* Setup translations so piece colors match square colors */
3204 symbols[0].name = "light_piece";
3205 symbols[0].value = appData.whitePieceColor;
3206 symbols[1].name = "dark_piece";
3207 symbols[1].value = appData.blackPieceColor;
3208 symbols[2].name = "light_square";
3209 symbols[2].value = appData.lightSquareColor;
3210 symbols[3].name = "dark_square";
3211 symbols[3].value = appData.darkSquareColor;
3213 attr.valuemask = XpmColorSymbols;
3214 attr.colorsymbols = symbols;
3215 attr.numsymbols = 4;
3217 if (appData.monoMode) {
3218 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3222 if (strlen(appData.pixmapDirectory) == 0) {
3223 XpmPieces* pieces = builtInXpms;
3226 while (pieces->size != squareSize && pieces->size) pieces++;
3227 if (!pieces->size) {
3228 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3231 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3232 for (kind=0; kind<4; kind++) {
3234 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3235 pieces->xpm[piece][kind],
3236 &(xpmPieceBitmap2[kind][piece]),
3237 NULL, &attr)) != 0) {
3238 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3242 if(piece <= (int) WhiteKing)
3243 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3247 xpmJailSquare = xpmLightSquare;
3251 fprintf(stderr, _("\nLoading XPMs...\n"));
3254 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3255 fprintf(stderr, "%d ", piece+1);
3256 for (kind=0; kind<4; kind++) {
3257 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3258 ExpandPathName(appData.pixmapDirectory),
3259 piece > (int) WhiteKing ? "w" : "",
3260 pieceBitmapNames[piece],
3262 if (appData.debugMode) {
3263 fprintf(stderr, _("(File:%s:) "), buf);
3265 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3266 &(xpmPieceBitmap2[kind][piece]),
3267 NULL, &attr)) != 0) {
3268 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3269 // [HGM] missing: read of unorthodox piece failed; substitute King.
3270 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3271 ExpandPathName(appData.pixmapDirectory),
3273 if (appData.debugMode) {
3274 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3276 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3277 &(xpmPieceBitmap2[kind][piece]),
3281 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3286 if(piece <= (int) WhiteKing)
3287 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3290 /* Load light and dark squares */
3291 /* If the LSQ and DSQ pieces don't exist, we will
3292 draw them with solid squares. */
3293 fprintf(stderr, _("light square "));
3294 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3295 if (access(buf, 0) != 0) {
3299 if (appData.debugMode)
3300 fprintf(stderr, _("(File:%s:) "), buf);
3302 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3303 &xpmLightSquare, NULL, &attr)) != 0) {
3304 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3307 fprintf(stderr, _("dark square "));
3308 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3309 ExpandPathName(appData.pixmapDirectory), ss);
3310 if (appData.debugMode) {
3311 fprintf(stderr, _("(File:%s:) "), buf);
3313 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3314 &xpmDarkSquare, NULL, &attr)) != 0) {
3315 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3319 xpmJailSquare = xpmLightSquare;
3320 fprintf(stderr, _("Done.\n"));
3322 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3325 #endif /* HAVE_LIBXPM */
3328 /* No built-in bitmaps */
3333 u_int ss = squareSize;
3335 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3338 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3339 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3340 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3341 pieceBitmapNames[piece],
3342 ss, kind == SOLID ? 's' : 'o');
3343 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3344 if(piece <= (int)WhiteKing)
3345 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3349 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3353 /* With built-in bitmaps */
3356 BuiltInBits* bib = builtInBits;
3359 u_int ss = squareSize;
3361 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3364 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3366 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3367 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3368 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3369 pieceBitmapNames[piece],
3370 ss, kind == SOLID ? 's' : 'o');
3371 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3372 bib->bits[kind][piece], ss, ss);
3373 if(piece <= (int)WhiteKing)
3374 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3378 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3383 void ReadBitmap(pm, name, bits, wreq, hreq)
3386 unsigned char bits[];
3392 char msg[MSG_SIZ], fullname[MSG_SIZ];
3394 if (*appData.bitmapDirectory != NULLCHAR) {
3395 strcpy(fullname, appData.bitmapDirectory);
3396 strcat(fullname, "/");
3397 strcat(fullname, name);
3398 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3399 &w, &h, pm, &x_hot, &y_hot);
3400 fprintf(stderr, "load %s\n", name);
3401 if (errcode != BitmapSuccess) {
3403 case BitmapOpenFailed:
3404 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3406 case BitmapFileInvalid:
3407 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3409 case BitmapNoMemory:
3410 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3414 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3418 fprintf(stderr, _("%s: %s...using built-in\n"),
3420 } else if (w != wreq || h != hreq) {
3422 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3423 programName, fullname, w, h, wreq, hreq);
3429 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3438 if (lineGap == 0) return;
3440 /* [HR] Split this into 2 loops for non-square boards. */
3442 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3443 gridSegments[i].x1 = 0;
3444 gridSegments[i].x2 =
3445 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3446 gridSegments[i].y1 = gridSegments[i].y2
3447 = lineGap / 2 + (i * (squareSize + lineGap));
3450 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3451 gridSegments[j + i].y1 = 0;
3452 gridSegments[j + i].y2 =
3453 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3454 gridSegments[j + i].x1 = gridSegments[j + i].x2
3455 = lineGap / 2 + (j * (squareSize + lineGap));
3459 static void MenuBarSelect(w, addr, index)
3464 XtActionProc proc = (XtActionProc) addr;
3466 (proc)(NULL, NULL, NULL, NULL);
3469 void CreateMenuBarPopup(parent, name, mb)
3479 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3482 XtSetArg(args[j], XtNleftMargin, 20); j++;
3483 XtSetArg(args[j], XtNrightMargin, 20); j++;
3485 while (mi->string != NULL) {
3486 if (strcmp(mi->string, "----") == 0) {
3487 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3490 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3491 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3493 XtAddCallback(entry, XtNcallback,
3494 (XtCallbackProc) MenuBarSelect,
3495 (caddr_t) mi->proc);
3501 Widget CreateMenuBar(mb)
3505 Widget anchor, menuBar;
3507 char menuName[MSG_SIZ];
3510 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3511 XtSetArg(args[j], XtNvSpace, 0); j++;
3512 XtSetArg(args[j], XtNborderWidth, 0); j++;
3513 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3514 formWidget, args, j);
3516 while (mb->name != NULL) {
3517 strcpy(menuName, "menu");
3518 strcat(menuName, mb->name);
3520 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3523 shortName[0] = _(mb->name)[0];
3524 shortName[1] = NULLCHAR;
3525 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3528 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3531 XtSetArg(args[j], XtNborderWidth, 0); j++;
3532 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3534 CreateMenuBarPopup(menuBar, menuName, mb);
3540 Widget CreateButtonBar(mi)
3544 Widget button, buttonBar;
3548 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3550 XtSetArg(args[j], XtNhSpace, 0); j++;
3552 XtSetArg(args[j], XtNborderWidth, 0); j++;
3553 XtSetArg(args[j], XtNvSpace, 0); j++;
3554 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3555 formWidget, args, j);
3557 while (mi->string != NULL) {
3560 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3561 XtSetArg(args[j], XtNborderWidth, 0); j++;
3563 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3564 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3565 buttonBar, args, j);
3566 XtAddCallback(button, XtNcallback,
3567 (XtCallbackProc) MenuBarSelect,
3568 (caddr_t) mi->proc);
3575 CreatePieceMenu(name, color)
3582 ChessSquare selection;
3584 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3585 boardWidget, args, 0);
3587 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3588 String item = pieceMenuStrings[color][i];
3590 if (strcmp(item, "----") == 0) {
3591 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3594 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3595 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3597 selection = pieceMenuTranslation[color][i];
3598 XtAddCallback(entry, XtNcallback,
3599 (XtCallbackProc) PieceMenuSelect,
3600 (caddr_t) selection);
3601 if (selection == WhitePawn || selection == BlackPawn) {
3602 XtSetArg(args[0], XtNpopupOnEntry, entry);
3603 XtSetValues(menu, args, 1);
3616 ChessSquare selection;
3618 whitePieceMenu = CreatePieceMenu("menuW", 0);
3619 blackPieceMenu = CreatePieceMenu("menuB", 1);
3621 XtRegisterGrabAction(PieceMenuPopup, True,
3622 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3623 GrabModeAsync, GrabModeAsync);
3625 XtSetArg(args[0], XtNlabel, _("Drop"));
3626 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3627 boardWidget, args, 1);
3628 for (i = 0; i < DROP_MENU_SIZE; i++) {
3629 String item = dropMenuStrings[i];
3631 if (strcmp(item, "----") == 0) {
3632 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3635 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3636 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3638 selection = dropMenuTranslation[i];
3639 XtAddCallback(entry, XtNcallback,
3640 (XtCallbackProc) DropMenuSelect,
3641 (caddr_t) selection);
3646 void SetupDropMenu()
3654 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3655 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3656 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3657 dmEnables[i].piece);
3658 XtSetSensitive(entry, p != NULL || !appData.testLegality
3659 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3660 && !appData.icsActive));
3662 while (p && *p++ == dmEnables[i].piece) count++;
3663 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3665 XtSetArg(args[j], XtNlabel, label); j++;
3666 XtSetValues(entry, args, j);
3670 void PieceMenuPopup(w, event, params, num_params)
3674 Cardinal *num_params;
3677 if (event->type != ButtonPress) return;
3678 if (errorUp) ErrorPopDown();
3682 whichMenu = params[0];
3684 case IcsPlayingWhite:
3685 case IcsPlayingBlack:
3687 case MachinePlaysWhite:
3688 case MachinePlaysBlack:
3689 if (appData.testLegality &&
3690 gameInfo.variant != VariantBughouse &&
3691 gameInfo.variant != VariantCrazyhouse) return;
3693 whichMenu = "menuD";
3699 if (((pmFromX = EventToSquare(event->xbutton.x, BOARD_WIDTH)) < 0) ||
3700 ((pmFromY = EventToSquare(event->xbutton.y, BOARD_HEIGHT)) < 0)) {
3701 pmFromX = pmFromY = -1;
3705 pmFromX = BOARD_WIDTH - 1 - pmFromX;
3707 pmFromY = BOARD_HEIGHT - 1 - pmFromY;
3709 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3712 static void PieceMenuSelect(w, piece, junk)
3717 if (pmFromX < 0 || pmFromY < 0) return;
3718 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3721 static void DropMenuSelect(w, piece, junk)
3726 if (pmFromX < 0 || pmFromY < 0) return;
3727 DropMenuEvent(piece, pmFromX, pmFromY);
3730 void WhiteClock(w, event, prms, nprms)
3736 if (gameMode == EditPosition || gameMode == IcsExamining) {
3737 SetWhiteToPlayEvent();
3738 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3743 void BlackClock(w, event, prms, nprms)
3749 if (gameMode == EditPosition || gameMode == IcsExamining) {
3750 SetBlackToPlayEvent();
3751 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3758 * If the user selects on a border boundary, return -1; if off the board,
3759 * return -2. Otherwise map the event coordinate to the square.
3761 int EventToSquare(x, limit)
3769 if ((x % (squareSize + lineGap)) >= squareSize)
3771 x /= (squareSize + lineGap);
3777 static void do_flash_delay(msec)
3783 static void drawHighlight(file, rank, gc)
3789 if (lineGap == 0 || appData.blindfold) return;
3792 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3793 (squareSize + lineGap);
3794 y = lineGap/2 + rank * (squareSize + lineGap);
3796 x = lineGap/2 + file * (squareSize + lineGap);
3797 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3798 (squareSize + lineGap);
3801 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3802 squareSize+lineGap, squareSize+lineGap);
3805 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3806 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3809 SetHighlights(fromX, fromY, toX, toY)
3810 int fromX, fromY, toX, toY;
3812 if (hi1X != fromX || hi1Y != fromY) {
3813 if (hi1X >= 0 && hi1Y >= 0) {
3814 drawHighlight(hi1X, hi1Y, lineGC);
3816 if (fromX >= 0 && fromY >= 0) {
3817 drawHighlight(fromX, fromY, highlineGC);
3820 if (hi2X != toX || hi2Y != toY) {
3821 if (hi2X >= 0 && hi2Y >= 0) {
3822 drawHighlight(hi2X, hi2Y, lineGC);
3824 if (toX >= 0 && toY >= 0) {
3825 drawHighlight(toX, toY, highlineGC);
3837 SetHighlights(-1, -1, -1, -1);
3842 SetPremoveHighlights(fromX, fromY, toX, toY)
3843 int fromX, fromY, toX, toY;
3845 if (pm1X != fromX || pm1Y != fromY) {
3846 if (pm1X >= 0 && pm1Y >= 0) {
3847 drawHighlight(pm1X, pm1Y, lineGC);
3849 if (fromX >= 0 && fromY >= 0) {
3850 drawHighlight(fromX, fromY, prelineGC);
3853 if (pm2X != toX || pm2Y != toY) {
3854 if (pm2X >= 0 && pm2Y >= 0) {
3855 drawHighlight(pm2X, pm2Y, lineGC);
3857 if (toX >= 0 && toY >= 0) {
3858 drawHighlight(toX, toY, prelineGC);
3868 ClearPremoveHighlights()
3870 SetPremoveHighlights(-1, -1, -1, -1);
3873 static void BlankSquare(x, y, color, piece, dest)
3878 if (useImages && useImageSqs) {
3882 pm = xpmLightSquare;
3887 case 2: /* neutral */
3892 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
3893 squareSize, squareSize, x, y);
3903 case 2: /* neutral */
3908 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
3913 I split out the routines to draw a piece so that I could
3914 make a generic flash routine.
3916 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
3918 int square_color, x, y;
3921 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3922 switch (square_color) {
3924 case 2: /* neutral */
3926 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3927 ? *pieceToOutline(piece)
3928 : *pieceToSolid(piece),
3929 dest, bwPieceGC, 0, 0,
3930 squareSize, squareSize, x, y);
3933 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3934 ? *pieceToSolid(piece)
3935 : *pieceToOutline(piece),
3936 dest, wbPieceGC, 0, 0,
3937 squareSize, squareSize, x, y);
3942 static void monoDrawPiece(piece, square_color, x, y, dest)
3944 int square_color, x, y;
3947 switch (square_color) {
3949 case 2: /* neutral */
3951 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3952 ? *pieceToOutline(piece)
3953 : *pieceToSolid(piece),
3954 dest, bwPieceGC, 0, 0,
3955 squareSize, squareSize, x, y, 1);
3958 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3959 ? *pieceToSolid(piece)
3960 : *pieceToOutline(piece),
3961 dest, wbPieceGC, 0, 0,
3962 squareSize, squareSize, x, y, 1);
3967 static void colorDrawPiece(piece, square_color, x, y, dest)
3969 int square_color, x, y;
3972 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
3973 switch (square_color) {
3975 XCopyPlane(xDisplay, *pieceToSolid(piece),
3976 dest, (int) piece < (int) BlackPawn
3977 ? wlPieceGC : blPieceGC, 0, 0,
3978 squareSize, squareSize, x, y, 1);
3981 XCopyPlane(xDisplay, *pieceToSolid(piece),
3982 dest, (int) piece < (int) BlackPawn
3983 ? wdPieceGC : bdPieceGC, 0, 0,
3984 squareSize, squareSize, x, y, 1);
3986 case 2: /* neutral */
3988 XCopyPlane(xDisplay, *pieceToSolid(piece),
3989 dest, (int) piece < (int) BlackPawn
3990 ? wjPieceGC : bjPieceGC, 0, 0,
3991 squareSize, squareSize, x, y, 1);
3996 static void colorDrawPieceImage(piece, square_color, x, y, dest)
3998 int square_color, x, y;
4003 switch (square_color) {
4005 case 2: /* neutral */
4007 if ((int)piece < (int) BlackPawn) {
4015 if ((int)piece < (int) BlackPawn) {
4023 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4024 dest, wlPieceGC, 0, 0,
4025 squareSize, squareSize, x, y);
4028 typedef void (*DrawFunc)();
4030 DrawFunc ChooseDrawFunc()
4032 if (appData.monoMode) {
4033 if (DefaultDepth(xDisplay, xScreen) == 1) {
4034 return monoDrawPiece_1bit;
4036 return monoDrawPiece;
4040 return colorDrawPieceImage;
4042 return colorDrawPiece;
4046 /* [HR] determine square color depending on chess variant. */
4047 static int SquareColor(row, column)
4052 if (gameInfo.variant == VariantXiangqi) {
4053 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4055 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4057 } else if (row <= 4) {
4063 square_color = ((column + row) % 2) == 1;
4066 /* [hgm] holdings: next line makes all holdings squares light */
4067 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4069 return square_color;
4072 void DrawSquare(row, column, piece, do_flash)
4073 int row, column, do_flash;
4076 int square_color, x, y, direction, font_ascent, font_descent;
4079 XCharStruct overall;
4083 /* Calculate delay in milliseconds (2-delays per complete flash) */
4084 flash_delay = 500 / appData.flashRate;
4087 x = lineGap + ((BOARD_WIDTH-1)-column) *
4088 (squareSize + lineGap);
4089 y = lineGap + row * (squareSize + lineGap);
4091 x = lineGap + column * (squareSize + lineGap);
4092 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4093 (squareSize + lineGap);
4096 square_color = SquareColor(row, column);
4098 if ( // [HGM] holdings: blank out area between board and holdings
4099 column == BOARD_LEFT-1 || column == BOARD_RGHT
4100 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4101 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4102 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4104 // [HGM] print piece counts next to holdings
4105 string[1] = NULLCHAR;
4106 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4107 string[0] = '0' + piece;
4108 XTextExtents(countFontStruct, string, 1, &direction,
4109 &font_ascent, &font_descent, &overall);
4110 if (appData.monoMode) {
4111 XDrawImageString(xDisplay, xBoardWindow, countGC,
4112 x + squareSize - overall.width - 2,
4113 y + font_ascent + 1, string, 1);
4115 XDrawString(xDisplay, xBoardWindow, countGC,
4116 x + squareSize - overall.width - 2,
4117 y + font_ascent + 1, string, 1);
4120 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4121 string[0] = '0' + piece;
4122 XTextExtents(countFontStruct, string, 1, &direction,
4123 &font_ascent, &font_descent, &overall);
4124 if (appData.monoMode) {
4125 XDrawImageString(xDisplay, xBoardWindow, countGC,
4126 x + 2, y + font_ascent + 1, string, 1);
4128 XDrawString(xDisplay, xBoardWindow, countGC,
4129 x + 2, y + font_ascent + 1, string, 1);
4133 if (piece == EmptySquare || appData.blindfold) {
4134 BlankSquare(x, y, square_color, piece, xBoardWindow);
4136 drawfunc = ChooseDrawFunc();
4137 if (do_flash && appData.flashCount > 0) {
4138 for (i=0; i<appData.flashCount; ++i) {
4140 drawfunc(piece, square_color, x, y, xBoardWindow);
4141 XSync(xDisplay, False);
4142 do_flash_delay(flash_delay);
4144 BlankSquare(x, y, square_color, piece, xBoardWindow);
4145 XSync(xDisplay, False);
4146 do_flash_delay(flash_delay);
4149 drawfunc(piece, square_color, x, y, xBoardWindow);
4153 string[1] = NULLCHAR;
4154 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4155 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4156 string[0] = 'a' + column - BOARD_LEFT;
4157 XTextExtents(coordFontStruct, string, 1, &direction,
4158 &font_ascent, &font_descent, &overall);
4159 if (appData.monoMode) {
4160 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4161 x + squareSize - overall.width - 2,
4162 y + squareSize - font_descent - 1, string, 1);
4164 XDrawString(xDisplay, xBoardWindow, coordGC,
4165 x + squareSize - overall.width - 2,
4166 y + squareSize - font_descent - 1, string, 1);
4169 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4170 string[0] = ONE + row;
4171 XTextExtents(coordFontStruct, string, 1, &direction,
4172 &font_ascent, &font_descent, &overall);
4173 if (appData.monoMode) {
4174 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4175 x + 2, y + font_ascent + 1, string, 1);
4177 XDrawString(xDisplay, xBoardWindow, coordGC,
4178 x + 2, y + font_ascent + 1, string, 1);
4184 /* Why is this needed on some versions of X? */
4185 void EventProc(widget, unused, event)
4190 if (!XtIsRealized(widget))
4193 switch (event->type) {
4195 if (event->xexpose.count > 0) return; /* no clipping is done */
4196 XDrawPosition(widget, True, NULL);
4204 void DrawPosition(fullRedraw, board)
4205 /*Boolean*/int fullRedraw;
4208 XDrawPosition(boardWidget, fullRedraw, board);
4211 /* Returns 1 if there are "too many" differences between b1 and b2
4212 (i.e. more than 1 move was made) */
4213 static int too_many_diffs(b1, b2)
4219 for (i=0; i<BOARD_HEIGHT; ++i) {
4220 for (j=0; j<BOARD_WIDTH; ++j) {
4221 if (b1[i][j] != b2[i][j]) {
4222 if (++c > 4) /* Castling causes 4 diffs */
4231 /* Matrix describing castling maneuvers */
4232 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4233 static int castling_matrix[4][5] = {
4234 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4235 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4236 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4237 { 7, 7, 4, 5, 6 } /* 0-0, black */
4240 /* Checks whether castling occurred. If it did, *rrow and *rcol
4241 are set to the destination (row,col) of the rook that moved.
4243 Returns 1 if castling occurred, 0 if not.
4245 Note: Only handles a max of 1 castling move, so be sure
4246 to call too_many_diffs() first.
4248 static int check_castle_draw(newb, oldb, rrow, rcol)
4255 /* For each type of castling... */
4256 for (i=0; i<4; ++i) {
4257 r = castling_matrix[i];
4259 /* Check the 4 squares involved in the castling move */
4261 for (j=1; j<=4; ++j) {
4262 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4269 /* All 4 changed, so it must be a castling move */
4278 static int damage[BOARD_RANKS][BOARD_FILES];
4281 * event handler for redrawing the board
4283 void XDrawPosition(w, repaint, board)
4285 /*Boolean*/int repaint;
4289 static int lastFlipView = 0;
4290 static int lastBoardValid = 0;
4291 static Board lastBoard;
4295 if (board == NULL) {
4296 if (!lastBoardValid) return;
4299 if (!lastBoardValid || lastFlipView != flipView) {
4300 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4301 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4306 * It would be simpler to clear the window with XClearWindow()
4307 * but this causes a very distracting flicker.
4310 if (!repaint && lastBoardValid && lastFlipView == flipView) {
4312 /* If too much changes (begin observing new game, etc.), don't
4314 do_flash = too_many_diffs(board, lastBoard) ? 0 : 1;
4316 /* Special check for castling so we don't flash both the king
4317 and the rook (just flash the king). */
4319 if (check_castle_draw(board, lastBoard, &rrow, &rcol)) {
4320 /* Draw rook with NO flashing. King will be drawn flashing later */
4321 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4322 lastBoard[rrow][rcol] = board[rrow][rcol];
4326 /* First pass -- Draw (newly) empty squares and repair damage.
4327 This prevents you from having a piece show up twice while it
4328 is flashing on its new square */
4329 for (i = 0; i < BOARD_HEIGHT; i++)
4330 for (j = 0; j < BOARD_WIDTH; j++)
4331 if ((board[i][j] != lastBoard[i][j] && board[i][j] == EmptySquare)
4333 DrawSquare(i, j, board[i][j], 0);
4334 damage[i][j] = False;
4337 /* Second pass -- Draw piece(s) in new position and flash them */
4338 for (i = 0; i < BOARD_HEIGHT; i++)
4339 for (j = 0; j < BOARD_WIDTH; j++)
4340 if (board[i][j] != lastBoard[i][j]) {
4341 DrawSquare(i, j, board[i][j], do_flash);
4345 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4346 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4348 for (i = 0; i < BOARD_HEIGHT; i++)
4349 for (j = 0; j < BOARD_WIDTH; j++) {
4350 DrawSquare(i, j, board[i][j], 0);
4351 damage[i][j] = False;
4355 CopyBoard(lastBoard, board);
4357 lastFlipView = flipView;
4359 /* Draw highlights */
4360 if (pm1X >= 0 && pm1Y >= 0) {
4361 drawHighlight(pm1X, pm1Y, prelineGC);
4363 if (pm2X >= 0 && pm2Y >= 0) {
4364 drawHighlight(pm2X, pm2Y, prelineGC);
4366 if (hi1X >= 0 && hi1Y >= 0) {
4367 drawHighlight(hi1X, hi1Y, highlineGC);
4369 if (hi2X >= 0 && hi2Y >= 0) {
4370 drawHighlight(hi2X, hi2Y, highlineGC);
4373 /* If piece being dragged around board, must redraw that too */
4376 XSync(xDisplay, False);
4381 * event handler for redrawing the board
4383 void DrawPositionProc(w, event, prms, nprms)
4389 XDrawPosition(w, True, NULL);
4394 * event handler for parsing user moves
4396 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4397 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4398 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4399 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4400 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4401 // and at the end FinishMove() to perform the move after optional promotion popups.
4402 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4403 void HandleUserMove(w, event, prms, nprms)
4409 if (w != boardWidget || errorExitStatus != -1) return;
4412 if (event->type == ButtonPress) {
4413 XtPopdown(promotionShell);
4414 XtDestroyWidget(promotionShell);
4415 promotionUp = False;
4423 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4424 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4425 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4428 void AnimateUserMove (Widget w, XEvent * event,
4429 String * params, Cardinal * nParams)
4431 DragPieceMove(event->xmotion.x, event->xmotion.y);
4434 Widget CommentCreate(name, text, mutable, callback, lines)
4436 int /*Boolean*/ mutable;
4437 XtCallbackProc callback;
4441 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4446 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4447 XtGetValues(boardWidget, args, j);
4450 XtSetArg(args[j], XtNresizable, True); j++;
4453 XtCreatePopupShell(name, topLevelShellWidgetClass,
4454 shellWidget, args, j);
4457 XtCreatePopupShell(name, transientShellWidgetClass,
4458 shellWidget, args, j);
4461 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4462 layoutArgs, XtNumber(layoutArgs));
4464 XtCreateManagedWidget("form", formWidgetClass, layout,
4465 formArgs, XtNumber(formArgs));
4469 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4470 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4472 XtSetArg(args[j], XtNstring, text); j++;
4473 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4474 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4475 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4476 XtSetArg(args[j], XtNright, XtChainRight); j++;
4477 XtSetArg(args[j], XtNresizable, True); j++;
4478 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4479 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4480 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4481 XtSetArg(args[j], XtNautoFill, True); j++;
4482 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4484 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4488 XtSetArg(args[j], XtNfromVert, edit); j++;
4489 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4490 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4491 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4492 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4494 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4495 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4498 XtSetArg(args[j], XtNfromVert, edit); j++;
4499 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4500 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4501 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4502 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4503 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4505 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4506 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4509 XtSetArg(args[j], XtNfromVert, edit); j++;
4510 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4511 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4512 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4513 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4514 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4516 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4517 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4520 XtSetArg(args[j], XtNfromVert, edit); j++;
4521 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4522 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4523 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4524 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4526 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4527 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4530 XtSetArg(args[j], XtNfromVert, edit); j++;
4531 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4532 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4533 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4534 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4535 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4537 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4538 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4541 XtRealizeWidget(shell);
4543 if (commentX == -1) {
4546 Dimension pw_height;
4547 Dimension ew_height;
4550 XtSetArg(args[j], XtNheight, &ew_height); j++;
4551 XtGetValues(edit, args, j);
4554 XtSetArg(args[j], XtNheight, &pw_height); j++;
4555 XtGetValues(shell, args, j);
4556 commentH = pw_height + (lines - 1) * ew_height;
4557 commentW = bw_width - 16;
4559 XSync(xDisplay, False);
4561 /* This code seems to tickle an X bug if it is executed too soon
4562 after xboard starts up. The coordinates get transformed as if
4563 the main window was positioned at (0, 0).
4565 XtTranslateCoords(shellWidget,
4566 (bw_width - commentW) / 2, 0 - commentH / 2,
4567 &commentX, &commentY);
4569 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4570 RootWindowOfScreen(XtScreen(shellWidget)),
4571 (bw_width - commentW) / 2, 0 - commentH / 2,
4576 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4579 if(wpComment.width > 0) {
4580 commentX = wpComment.x;
4581 commentY = wpComment.y;
4582 commentW = wpComment.width;
4583 commentH = wpComment.height;
4587 XtSetArg(args[j], XtNheight, commentH); j++;
4588 XtSetArg(args[j], XtNwidth, commentW); j++;
4589 XtSetArg(args[j], XtNx, commentX); j++;
4590 XtSetArg(args[j], XtNy, commentY); j++;
4591 XtSetValues(shell, args, j);
4592 XtSetKeyboardFocus(shell, edit);
4597 /* Used for analysis window and ICS input window */
4598 Widget MiscCreate(name, text, mutable, callback, lines)
4600 int /*Boolean*/ mutable;
4601 XtCallbackProc callback;
4605 Widget shell, layout, form, edit;
4607 Dimension bw_width, pw_height, ew_height, w, h;
4613 XtSetArg(args[j], XtNresizable, True); j++;
4616 XtCreatePopupShell(name, topLevelShellWidgetClass,
4617 shellWidget, args, j);
4620 XtCreatePopupShell(name, transientShellWidgetClass,
4621 shellWidget, args, j);
4624 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4625 layoutArgs, XtNumber(layoutArgs));
4627 XtCreateManagedWidget("form", formWidgetClass, layout,
4628 formArgs, XtNumber(formArgs));
4632 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4633 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4635 XtSetArg(args[j], XtNstring, text); j++;
4636 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4637 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4638 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4639 XtSetArg(args[j], XtNright, XtChainRight); j++;
4640 XtSetArg(args[j], XtNresizable, True); j++;
4641 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4642 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4643 XtSetArg(args[j], XtNautoFill, True); j++;
4644 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4646 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4648 XtRealizeWidget(shell);
4651 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4652 XtGetValues(boardWidget, args, j);
4655 XtSetArg(args[j], XtNheight, &ew_height); j++;
4656 XtGetValues(edit, args, j);
4659 XtSetArg(args[j], XtNheight, &pw_height); j++;
4660 XtGetValues(shell, args, j);
4661 h = pw_height + (lines - 1) * ew_height;
4664 XSync(xDisplay, False);
4666 /* This code seems to tickle an X bug if it is executed too soon
4667 after xboard starts up. The coordinates get transformed as if
4668 the main window was positioned at (0, 0).
4670 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4672 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4673 RootWindowOfScreen(XtScreen(shellWidget)),
4674 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4678 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4681 XtSetArg(args[j], XtNheight, h); j++;
4682 XtSetArg(args[j], XtNwidth, w); j++;
4683 XtSetArg(args[j], XtNx, x); j++;
4684 XtSetArg(args[j], XtNy, y); j++;
4685 XtSetValues(shell, args, j);
4691 static int savedIndex; /* gross that this is global */
4693 void EditCommentPopUp(index, title, text)
4702 if (text == NULL) text = "";
4704 if (editShell == NULL) {
4706 CommentCreate(title, text, True, EditCommentCallback, 4);
4707 XtRealizeWidget(editShell);
4708 CatchDeleteWindow(editShell, "EditCommentPopDown");
4710 edit = XtNameToWidget(editShell, "*form.text");
4712 XtSetArg(args[j], XtNstring, text); j++;
4713 XtSetValues(edit, args, j);
4715 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4716 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4717 XtSetValues(editShell, args, j);
4720 XtPopup(editShell, XtGrabNone);
4724 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4725 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4729 void EditCommentCallback(w, client_data, call_data)
4731 XtPointer client_data, call_data;
4739 XtSetArg(args[j], XtNlabel, &name); j++;
4740 XtGetValues(w, args, j);
4742 if (strcmp(name, _("ok")) == 0) {
4743 edit = XtNameToWidget(editShell, "*form.text");
4745 XtSetArg(args[j], XtNstring, &val); j++;
4746 XtGetValues(edit, args, j);
4747 ReplaceComment(savedIndex, val);
4748 EditCommentPopDown();
4749 } else if (strcmp(name, _("cancel")) == 0) {
4750 EditCommentPopDown();
4751 } else if (strcmp(name, _("clear")) == 0) {
4752 edit = XtNameToWidget(editShell, "*form.text");
4753 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4754 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4758 void EditCommentPopDown()
4763 if (!editUp) return;
4765 XtSetArg(args[j], XtNx, &commentX); j++;
4766 XtSetArg(args[j], XtNy, &commentY); j++;
4767 XtSetArg(args[j], XtNheight, &commentH); j++;
4768 XtSetArg(args[j], XtNwidth, &commentW); j++;
4769 XtGetValues(editShell, args, j);
4770 XtPopdown(editShell);
4773 XtSetArg(args[j], XtNleftBitmap, None); j++;
4774 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4778 void ICSInputBoxPopUp()
4783 char *title = _("ICS Input");
4786 if (ICSInputShell == NULL) {
4787 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
4788 tr = XtParseTranslationTable(ICSInputTranslations);
4789 edit = XtNameToWidget(ICSInputShell, "*form.text");
4790 XtOverrideTranslations(edit, tr);
4791 XtRealizeWidget(ICSInputShell);
4792 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
4795 edit = XtNameToWidget(ICSInputShell, "*form.text");
4797 XtSetArg(args[j], XtNstring, ""); j++;
4798 XtSetValues(edit, args, j);
4800 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4801 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4802 XtSetValues(ICSInputShell, args, j);
4805 XtPopup(ICSInputShell, XtGrabNone);
4806 XtSetKeyboardFocus(ICSInputShell, edit);
4808 ICSInputBoxUp = True;
4810 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4811 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4815 void ICSInputSendText()
4822 edit = XtNameToWidget(ICSInputShell, "*form.text");
4824 XtSetArg(args[j], XtNstring, &val); j++;
4825 XtGetValues(edit, args, j);
4826 SendMultiLineToICS(val);
4827 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4828 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4831 void ICSInputBoxPopDown()
4836 if (!ICSInputBoxUp) return;
4838 XtPopdown(ICSInputShell);
4839 ICSInputBoxUp = False;
4841 XtSetArg(args[j], XtNleftBitmap, None); j++;
4842 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4846 void CommentPopUp(title, text)
4853 if (commentShell == NULL) {
4855 CommentCreate(title, text, False, CommentCallback, 4);
4856 XtRealizeWidget(commentShell);
4857 CatchDeleteWindow(commentShell, "CommentPopDown");
4859 edit = XtNameToWidget(commentShell, "*form.text");
4861 XtSetArg(args[j], XtNstring, text); j++;
4862 XtSetValues(edit, args, j);
4864 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4865 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4866 XtSetValues(commentShell, args, j);
4869 XtPopup(commentShell, XtGrabNone);
4870 XSync(xDisplay, False);
4875 void CommentCallback(w, client_data, call_data)
4877 XtPointer client_data, call_data;
4884 XtSetArg(args[j], XtNlabel, &name); j++;
4885 XtGetValues(w, args, j);
4887 if (strcmp(name, _("close")) == 0) {
4889 } else if (strcmp(name, _("edit")) == 0) {
4896 void CommentPopDown()
4901 if (!commentUp) return;
4903 XtSetArg(args[j], XtNx, &commentX); j++;
4904 XtSetArg(args[j], XtNy, &commentY); j++;
4905 XtSetArg(args[j], XtNwidth, &commentW); j++;
4906 XtSetArg(args[j], XtNheight, &commentH); j++;
4907 XtGetValues(commentShell, args, j);
4908 XtPopdown(commentShell);
4909 XSync(xDisplay, False);
4913 void FileNamePopUp(label, def, proc, openMode)
4920 Widget popup, layout, dialog, edit;
4926 fileProc = proc; /* I can't see a way not */
4927 fileOpenMode = openMode; /* to use globals here */
4928 { // [HGM] use file-selector dialog stolen from Ghostview
4930 int index; // this is not supported yet
4932 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
4933 NULL, openMode, NULL, &name))
4934 (void) (*fileProc)(f, index=0, name);
4938 void FileNamePopDown()
4940 if (!filenameUp) return;
4941 XtPopdown(fileNameShell);
4942 XtDestroyWidget(fileNameShell);
4947 void FileNameCallback(w, client_data, call_data)
4949 XtPointer client_data, call_data;
4954 XtSetArg(args[0], XtNlabel, &name);
4955 XtGetValues(w, args, 1);
4957 if (strcmp(name, _("cancel")) == 0) {
4962 FileNameAction(w, NULL, NULL, NULL);
4965 void FileNameAction(w, event, prms, nprms)
4977 name = XawDialogGetValueString(w = XtParent(w));
4979 if ((name != NULL) && (*name != NULLCHAR)) {
4981 XtPopdown(w = XtParent(XtParent(w)));
4985 p = strrchr(buf, ' ');
4992 fullname = ExpandPathName(buf);
4994 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
4997 f = fopen(fullname, fileOpenMode);
4999 DisplayError(_("Failed to open file"), errno);
5001 (void) (*fileProc)(f, index, buf);
5008 XtPopdown(w = XtParent(XtParent(w)));
5014 void PromotionPopUp()
5017 Widget dialog, layout;
5019 Dimension bw_width, pw_width;
5023 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5024 XtGetValues(boardWidget, args, j);
5027 XtSetArg(args[j], XtNresizable, True); j++;
5028 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5030 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5031 shellWidget, args, j);
5033 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5034 layoutArgs, XtNumber(layoutArgs));
5037 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5038 XtSetArg(args[j], XtNborderWidth, 0); j++;
5039 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5042 if(gameInfo.variant != VariantShogi) {
5043 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5044 (XtPointer) dialog);
5045 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5046 (XtPointer) dialog);
5047 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5048 (XtPointer) dialog);
5049 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5050 (XtPointer) dialog);
5051 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5052 gameInfo.variant == VariantGiveaway) {
5053 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5054 (XtPointer) dialog);
5056 if(gameInfo.variant == VariantCapablanca ||
5057 gameInfo.variant == VariantGothic ||
5058 gameInfo.variant == VariantCapaRandom) {
5059 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5060 (XtPointer) dialog);
5061 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5062 (XtPointer) dialog);
5064 } else // [HGM] shogi
5066 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5067 (XtPointer) dialog);
5068 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5069 (XtPointer) dialog);
5071 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5072 (XtPointer) dialog);
5074 XtRealizeWidget(promotionShell);
5075 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5078 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5079 XtGetValues(promotionShell, args, j);
5081 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5082 lineGap + squareSize/3 +
5083 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5084 0 : 6*(squareSize + lineGap)), &x, &y);
5087 XtSetArg(args[j], XtNx, x); j++;
5088 XtSetArg(args[j], XtNy, y); j++;
5089 XtSetValues(promotionShell, args, j);
5091 XtPopup(promotionShell, XtGrabNone);
5096 void PromotionPopDown()
5098 if (!promotionUp) return;
5099 XtPopdown(promotionShell);
5100 XtDestroyWidget(promotionShell);
5101 promotionUp = False;
5104 void PromotionCallback(w, client_data, call_data)
5106 XtPointer client_data, call_data;
5112 XtSetArg(args[0], XtNlabel, &name);
5113 XtGetValues(w, args, 1);
5117 if (fromX == -1) return;
5119 if (strcmp(name, _("cancel")) == 0) {
5123 } else if (strcmp(name, _("Knight")) == 0) {
5125 } else if (strcmp(name, _("Promote")) == 0) {
5127 } else if (strcmp(name, _("Defer")) == 0) {
5130 promoChar = ToLower(name[0]);
5133 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5135 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5136 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5141 void ErrorCallback(w, client_data, call_data)
5143 XtPointer client_data, call_data;
5146 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5148 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5154 if (!errorUp) return;
5156 XtPopdown(errorShell);
5157 XtDestroyWidget(errorShell);
5158 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5161 void ErrorPopUp(title, label, modal)
5162 char *title, *label;
5166 Widget dialog, layout;
5170 Dimension bw_width, pw_width;
5171 Dimension pw_height;
5175 XtSetArg(args[i], XtNresizable, True); i++;
5176 XtSetArg(args[i], XtNtitle, title); i++;
5178 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5179 shellWidget, args, i);
5181 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5182 layoutArgs, XtNumber(layoutArgs));
5185 XtSetArg(args[i], XtNlabel, label); i++;
5186 XtSetArg(args[i], XtNborderWidth, 0); i++;
5187 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5190 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5192 XtRealizeWidget(errorShell);
5193 CatchDeleteWindow(errorShell, "ErrorPopDown");
5196 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5197 XtGetValues(boardWidget, args, i);
5199 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5200 XtSetArg(args[i], XtNheight, &pw_height); i++;
5201 XtGetValues(errorShell, args, i);
5204 /* This code seems to tickle an X bug if it is executed too soon
5205 after xboard starts up. The coordinates get transformed as if
5206 the main window was positioned at (0, 0).
5208 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5209 0 - pw_height + squareSize / 3, &x, &y);
5211 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5212 RootWindowOfScreen(XtScreen(boardWidget)),
5213 (bw_width - pw_width) / 2,
5214 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5218 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5221 XtSetArg(args[i], XtNx, x); i++;
5222 XtSetArg(args[i], XtNy, y); i++;
5223 XtSetValues(errorShell, args, i);
5226 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5229 /* Disable all user input other than deleting the window */
5230 static int frozen = 0;
5234 /* Grab by a widget that doesn't accept input */
5235 XtAddGrab(messageWidget, TRUE, FALSE);
5239 /* Undo a FreezeUI */
5242 if (!frozen) return;
5243 XtRemoveGrab(messageWidget);
5247 char *ModeToWidgetName(mode)
5251 case BeginningOfGame:
5252 if (appData.icsActive)
5253 return "menuMode.ICS Client";
5254 else if (appData.noChessProgram ||
5255 *appData.cmailGameName != NULLCHAR)
5256 return "menuMode.Edit Game";
5258 return "menuMode.Machine Black";
5259 case MachinePlaysBlack:
5260 return "menuMode.Machine Black";
5261 case MachinePlaysWhite:
5262 return "menuMode.Machine White";
5264 return "menuMode.Analysis Mode";
5266 return "menuMode.Analyze File";
5267 case TwoMachinesPlay:
5268 return "menuMode.Two Machines";
5270 return "menuMode.Edit Game";
5271 case PlayFromGameFile:
5272 return "menuFile.Load Game";
5274 return "menuMode.Edit Position";
5276 return "menuMode.Training";
5277 case IcsPlayingWhite:
5278 case IcsPlayingBlack:
5282 return "menuMode.ICS Client";
5289 void ModeHighlight()
5292 static int oldPausing = FALSE;
5293 static GameMode oldmode = (GameMode) -1;
5296 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5298 if (pausing != oldPausing) {
5299 oldPausing = pausing;
5301 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5303 XtSetArg(args[0], XtNleftBitmap, None);
5305 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5308 if (appData.showButtonBar) {
5309 /* Always toggle, don't set. Previous code messes up when
5310 invoked while the button is pressed, as releasing it
5311 toggles the state again. */
5314 XtSetArg(args[0], XtNbackground, &oldbg);
5315 XtSetArg(args[1], XtNforeground, &oldfg);
5316 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5318 XtSetArg(args[0], XtNbackground, oldfg);
5319 XtSetArg(args[1], XtNforeground, oldbg);
5321 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5325 wname = ModeToWidgetName(oldmode);
5326 if (wname != NULL) {
5327 XtSetArg(args[0], XtNleftBitmap, None);
5328 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5330 wname = ModeToWidgetName(gameMode);
5331 if (wname != NULL) {
5332 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5333 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5337 /* Maybe all the enables should be handled here, not just this one */
5338 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5339 gameMode == Training || gameMode == PlayFromGameFile);
5344 * Button/menu procedures
5346 void ResetProc(w, event, prms, nprms)
5355 int LoadGamePopUp(f, gameNumber, title)
5360 cmailMsgLoaded = FALSE;
5361 if (gameNumber == 0) {
5362 int error = GameListBuild(f);
5364 DisplayError(_("Cannot build game list"), error);
5365 } else if (!ListEmpty(&gameList) &&
5366 ((ListGame *) gameList.tailPred)->number > 1) {
5367 GameListPopUp(f, title);
5373 return LoadGame(f, gameNumber, title, FALSE);
5376 void LoadGameProc(w, event, prms, nprms)
5382 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5385 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5388 void LoadNextGameProc(w, event, prms, nprms)
5397 void LoadPrevGameProc(w, event, prms, nprms)
5406 void ReloadGameProc(w, event, prms, nprms)
5415 void LoadNextPositionProc(w, event, prms, nprms)
5424 void LoadPrevPositionProc(w, event, prms, nprms)
5433 void ReloadPositionProc(w, event, prms, nprms)
5442 void LoadPositionProc(w, event, prms, nprms)
5448 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5451 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5454 void SaveGameProc(w, event, prms, nprms)
5460 FileNamePopUp(_("Save game file name?"),
5461 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5465 void SavePositionProc(w, event, prms, nprms)
5471 FileNamePopUp(_("Save position file name?"),
5472 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5476 void ReloadCmailMsgProc(w, event, prms, nprms)
5482 ReloadCmailMsgEvent(FALSE);
5485 void MailMoveProc(w, event, prms, nprms)
5494 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5495 char *selected_fen_position=NULL;
5498 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5499 Atom *type_return, XtPointer *value_return,
5500 unsigned long *length_return, int *format_return)
5502 char *selection_tmp;
5504 if (!selected_fen_position) return False; /* should never happen */
5505 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5506 /* note: since no XtSelectionDoneProc was registered, Xt will
5507 * automatically call XtFree on the value returned. So have to
5508 * make a copy of it allocated with XtMalloc */
5509 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5510 strcpy(selection_tmp, selected_fen_position);
5512 *value_return=selection_tmp;
5513 *length_return=strlen(selection_tmp);
5514 *type_return=*target;
5515 *format_return = 8; /* bits per byte */
5517 } else if (*target == XA_TARGETS(xDisplay)) {
5518 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5519 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5520 targets_tmp[1] = XA_STRING;
5521 *value_return = targets_tmp;
5522 *type_return = XA_ATOM;
5524 *format_return = 8 * sizeof(Atom);
5525 if (*format_return > 32) {
5526 *length_return *= *format_return / 32;
5527 *format_return = 32;
5535 /* note: when called from menu all parameters are NULL, so no clue what the
5536 * Widget which was clicked on was, or what the click event was
5538 void CopyPositionProc(w, event, prms, nprms)
5545 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5546 * have a notion of a position that is selected but not copied.
5547 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5549 if(gameMode == EditPosition) EditPositionDone(TRUE);
5550 if (selected_fen_position) free(selected_fen_position);
5551 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5552 if (!selected_fen_position) return;
5553 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5555 SendPositionSelection,
5556 NULL/* lose_ownership_proc */ ,
5557 NULL/* transfer_done_proc */);
5558 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5560 SendPositionSelection,
5561 NULL/* lose_ownership_proc */ ,
5562 NULL/* transfer_done_proc */);
5565 /* function called when the data to Paste is ready */
5567 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5568 Atom *type, XtPointer value, unsigned long *len, int *format)
5571 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5572 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5573 EditPositionPasteFEN(fenstr);
5577 /* called when Paste Position button is pressed,
5578 * all parameters will be NULL */
5579 void PastePositionProc(w, event, prms, nprms)
5585 XtGetSelectionValue(menuBarWidget,
5586 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5587 /* (XtSelectionCallbackProc) */ PastePositionCB,
5588 NULL, /* client_data passed to PastePositionCB */
5590 /* better to use the time field from the event that triggered the
5591 * call to this function, but that isn't trivial to get
5599 SendGameSelection(Widget w, Atom *selection, Atom *target,
5600 Atom *type_return, XtPointer *value_return,
5601 unsigned long *length_return, int *format_return)
5603 char *selection_tmp;
5605 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5606 FILE* f = fopen(gameCopyFilename, "r");
5609 if (f == NULL) return False;
5613 selection_tmp = XtMalloc(len + 1);
5614 count = fread(selection_tmp, 1, len, f);
5616 XtFree(selection_tmp);
5619 selection_tmp[len] = NULLCHAR;
5620 *value_return = selection_tmp;
5621 *length_return = len;
5622 *type_return = *target;
5623 *format_return = 8; /* bits per byte */
5625 } else if (*target == XA_TARGETS(xDisplay)) {
5626 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5627 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5628 targets_tmp[1] = XA_STRING;
5629 *value_return = targets_tmp;
5630 *type_return = XA_ATOM;
5632 *format_return = 8 * sizeof(Atom);
5633 if (*format_return > 32) {
5634 *length_return *= *format_return / 32;
5635 *format_return = 32;
5643 /* note: when called from menu all parameters are NULL, so no clue what the
5644 * Widget which was clicked on was, or what the click event was
5646 void CopyGameProc(w, event, prms, nprms)
5654 ret = SaveGameToFile(gameCopyFilename, FALSE);
5658 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5659 * have a notion of a game that is selected but not copied.
5660 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5662 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5665 NULL/* lose_ownership_proc */ ,
5666 NULL/* transfer_done_proc */);
5667 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5670 NULL/* lose_ownership_proc */ ,
5671 NULL/* transfer_done_proc */);
5674 /* function called when the data to Paste is ready */
5676 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5677 Atom *type, XtPointer value, unsigned long *len, int *format)
5680 if (value == NULL || *len == 0) {
5681 return; /* nothing had been selected to copy */
5683 f = fopen(gamePasteFilename, "w");
5685 DisplayError(_("Can't open temp file"), errno);
5688 fwrite(value, 1, *len, f);
5691 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5694 /* called when Paste Game button is pressed,
5695 * all parameters will be NULL */
5696 void PasteGameProc(w, event, prms, nprms)
5702 XtGetSelectionValue(menuBarWidget,
5703 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5704 /* (XtSelectionCallbackProc) */ PasteGameCB,
5705 NULL, /* client_data passed to PasteGameCB */
5707 /* better to use the time field from the event that triggered the
5708 * call to this function, but that isn't trivial to get
5718 SaveGameProc(NULL, NULL, NULL, NULL);
5722 void QuitProc(w, event, prms, nprms)
5731 void PauseProc(w, event, prms, nprms)
5741 void MachineBlackProc(w, event, prms, nprms)
5747 MachineBlackEvent();
5750 void MachineWhiteProc(w, event, prms, nprms)
5756 MachineWhiteEvent();
5759 void AnalyzeModeProc(w, event, prms, nprms)
5767 if (!first.analysisSupport) {
5768 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5769 DisplayError(buf, 0);
5772 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5773 if (appData.icsActive) {
5774 if (gameMode != IcsObserving) {
5775 sprintf(buf,_("You are not observing a game"));
5776 DisplayError(buf, 0);
5778 if (appData.icsEngineAnalyze) {
5779 if (appData.debugMode)
5780 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5786 /* if enable, use want disable icsEngineAnalyze */
5787 if (appData.icsEngineAnalyze) {
5792 appData.icsEngineAnalyze = TRUE;
5793 if (appData.debugMode)
5794 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5796 if (!appData.showThinking)
5797 ShowThinkingProc(w,event,prms,nprms);
5802 void AnalyzeFileProc(w, event, prms, nprms)
5808 if (!first.analysisSupport) {
5810 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5811 DisplayError(buf, 0);
5816 if (!appData.showThinking)
5817 ShowThinkingProc(w,event,prms,nprms);
5820 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
5821 AnalysisPeriodicEvent(1);
5824 void TwoMachinesProc(w, event, prms, nprms)
5833 void IcsClientProc(w, event, prms, nprms)
5842 void EditGameProc(w, event, prms, nprms)
5851 void EditPositionProc(w, event, prms, nprms)
5857 EditPositionEvent();
5860 void TrainingProc(w, event, prms, nprms)
5869 void EditCommentProc(w, event, prms, nprms)
5876 EditCommentPopDown();
5882 void IcsInputBoxProc(w, event, prms, nprms)
5888 if (ICSInputBoxUp) {
5889 ICSInputBoxPopDown();
5895 void AcceptProc(w, event, prms, nprms)
5904 void DeclineProc(w, event, prms, nprms)
5913 void RematchProc(w, event, prms, nprms)
5922 void CallFlagProc(w, event, prms, nprms)
5931 void DrawProc(w, event, prms, nprms)
5940 void AbortProc(w, event, prms, nprms)
5949 void AdjournProc(w, event, prms, nprms)
5958 void ResignProc(w, event, prms, nprms)
5967 void AdjuWhiteProc(w, event, prms, nprms)
5973 UserAdjudicationEvent(+1);
5976 void AdjuBlackProc(w, event, prms, nprms)
5982 UserAdjudicationEvent(-1);
5985 void AdjuDrawProc(w, event, prms, nprms)
5991 UserAdjudicationEvent(0);
5994 void EnterKeyProc(w, event, prms, nprms)
6000 if (ICSInputBoxUp == True)
6004 void StopObservingProc(w, event, prms, nprms)
6010 StopObservingEvent();
6013 void StopExaminingProc(w, event, prms, nprms)
6019 StopExaminingEvent();
6023 void ForwardProc(w, event, prms, nprms)
6033 void BackwardProc(w, event, prms, nprms)
6042 void ToStartProc(w, event, prms, nprms)
6051 void ToEndProc(w, event, prms, nprms)
6060 void RevertProc(w, event, prms, nprms)
6069 void TruncateGameProc(w, event, prms, nprms)
6075 TruncateGameEvent();
6077 void RetractMoveProc(w, event, prms, nprms)
6086 void MoveNowProc(w, event, prms, nprms)
6096 void AlwaysQueenProc(w, event, prms, nprms)
6104 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6106 if (appData.alwaysPromoteToQueen) {
6107 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6109 XtSetArg(args[0], XtNleftBitmap, None);
6111 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6115 void AnimateDraggingProc(w, event, prms, nprms)
6123 appData.animateDragging = !appData.animateDragging;
6125 if (appData.animateDragging) {
6126 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6129 XtSetArg(args[0], XtNleftBitmap, None);
6131 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6135 void AnimateMovingProc(w, event, prms, nprms)
6143 appData.animate = !appData.animate;
6145 if (appData.animate) {
6146 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6149 XtSetArg(args[0], XtNleftBitmap, None);
6151 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6155 void AutocommProc(w, event, prms, nprms)
6163 appData.autoComment = !appData.autoComment;
6165 if (appData.autoComment) {
6166 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6168 XtSetArg(args[0], XtNleftBitmap, None);
6170 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6175 void AutoflagProc(w, event, prms, nprms)
6183 appData.autoCallFlag = !appData.autoCallFlag;
6185 if (appData.autoCallFlag) {
6186 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6188 XtSetArg(args[0], XtNleftBitmap, None);
6190 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6194 void AutoflipProc(w, event, prms, nprms)
6202 appData.autoFlipView = !appData.autoFlipView;
6204 if (appData.autoFlipView) {
6205 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6207 XtSetArg(args[0], XtNleftBitmap, None);
6209 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6213 void AutobsProc(w, event, prms, nprms)
6221 appData.autoObserve = !appData.autoObserve;
6223 if (appData.autoObserve) {
6224 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6226 XtSetArg(args[0], XtNleftBitmap, None);
6228 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6232 void AutoraiseProc(w, event, prms, nprms)
6240 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6242 if (appData.autoRaiseBoard) {
6243 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6245 XtSetArg(args[0], XtNleftBitmap, None);
6247 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6251 void AutosaveProc(w, event, prms, nprms)
6259 appData.autoSaveGames = !appData.autoSaveGames;
6261 if (appData.autoSaveGames) {
6262 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6264 XtSetArg(args[0], XtNleftBitmap, None);
6266 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6270 void BlindfoldProc(w, event, prms, nprms)
6278 appData.blindfold = !appData.blindfold;
6280 if (appData.blindfold) {
6281 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6283 XtSetArg(args[0], XtNleftBitmap, None);
6285 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6288 DrawPosition(True, NULL);
6291 void TestLegalityProc(w, event, prms, nprms)
6299 appData.testLegality = !appData.testLegality;
6301 if (appData.testLegality) {
6302 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6304 XtSetArg(args[0], XtNleftBitmap, None);
6306 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6311 void FlashMovesProc(w, event, prms, nprms)
6319 if (appData.flashCount == 0) {
6320 appData.flashCount = 3;
6322 appData.flashCount = -appData.flashCount;
6325 if (appData.flashCount > 0) {
6326 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6328 XtSetArg(args[0], XtNleftBitmap, None);
6330 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6334 void FlipViewProc(w, event, prms, nprms)
6340 flipView = !flipView;
6341 DrawPosition(True, NULL);
6344 void GetMoveListProc(w, event, prms, nprms)
6352 appData.getMoveList = !appData.getMoveList;
6354 if (appData.getMoveList) {
6355 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6358 XtSetArg(args[0], XtNleftBitmap, None);
6360 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6365 void HighlightDraggingProc(w, event, prms, nprms)
6373 appData.highlightDragging = !appData.highlightDragging;
6375 if (appData.highlightDragging) {
6376 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6378 XtSetArg(args[0], XtNleftBitmap, None);
6380 XtSetValues(XtNameToWidget(menuBarWidget,
6381 "menuOptions.Highlight Dragging"), args, 1);
6385 void HighlightLastMoveProc(w, event, prms, nprms)
6393 appData.highlightLastMove = !appData.highlightLastMove;
6395 if (appData.highlightLastMove) {
6396 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6398 XtSetArg(args[0], XtNleftBitmap, None);
6400 XtSetValues(XtNameToWidget(menuBarWidget,
6401 "menuOptions.Highlight Last Move"), args, 1);
6404 void IcsAlarmProc(w, event, prms, nprms)
6412 appData.icsAlarm = !appData.icsAlarm;
6414 if (appData.icsAlarm) {
6415 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6417 XtSetArg(args[0], XtNleftBitmap, None);
6419 XtSetValues(XtNameToWidget(menuBarWidget,
6420 "menuOptions.ICS Alarm"), args, 1);
6423 void MoveSoundProc(w, event, prms, nprms)
6431 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6433 if (appData.ringBellAfterMoves) {
6434 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6436 XtSetArg(args[0], XtNleftBitmap, None);
6438 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6443 void OldSaveStyleProc(w, event, prms, nprms)
6451 appData.oldSaveStyle = !appData.oldSaveStyle;
6453 if (appData.oldSaveStyle) {
6454 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6456 XtSetArg(args[0], XtNleftBitmap, None);
6458 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6462 void PeriodicUpdatesProc(w, event, prms, nprms)
6470 PeriodicUpdatesEvent(!appData.periodicUpdates);
6472 if (appData.periodicUpdates) {
6473 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6475 XtSetArg(args[0], XtNleftBitmap, None);
6477 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6481 void PonderNextMoveProc(w, event, prms, nprms)
6489 PonderNextMoveEvent(!appData.ponderNextMove);
6491 if (appData.ponderNextMove) {
6492 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6494 XtSetArg(args[0], XtNleftBitmap, None);
6496 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6500 void PopupExitMessageProc(w, event, prms, nprms)
6508 appData.popupExitMessage = !appData.popupExitMessage;
6510 if (appData.popupExitMessage) {
6511 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6513 XtSetArg(args[0], XtNleftBitmap, None);
6515 XtSetValues(XtNameToWidget(menuBarWidget,
6516 "menuOptions.Popup Exit Message"), args, 1);
6519 void PopupMoveErrorsProc(w, event, prms, nprms)
6527 appData.popupMoveErrors = !appData.popupMoveErrors;
6529 if (appData.popupMoveErrors) {
6530 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6532 XtSetArg(args[0], XtNleftBitmap, None);
6534 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6538 void PremoveProc(w, event, prms, nprms)
6546 appData.premove = !appData.premove;
6548 if (appData.premove) {
6549 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6551 XtSetArg(args[0], XtNleftBitmap, None);
6553 XtSetValues(XtNameToWidget(menuBarWidget,
6554 "menuOptions.Premove"), args, 1);
6557 void QuietPlayProc(w, event, prms, nprms)
6565 appData.quietPlay = !appData.quietPlay;
6567 if (appData.quietPlay) {
6568 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6570 XtSetArg(args[0], XtNleftBitmap, None);
6572 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6576 void ShowCoordsProc(w, event, prms, nprms)
6584 appData.showCoords = !appData.showCoords;
6586 if (appData.showCoords) {
6587 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6589 XtSetArg(args[0], XtNleftBitmap, None);
6591 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6594 DrawPosition(True, NULL);
6597 void ShowThinkingProc(w, event, prms, nprms)
6603 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6604 ShowThinkingEvent();
6607 void HideThinkingProc(w, event, prms, nprms)
6615 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6616 ShowThinkingEvent();
6618 if (appData.hideThinkingFromHuman) {
6619 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6621 XtSetArg(args[0], XtNleftBitmap, None);
6623 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6627 void SaveOnExitProc(w, event, prms, nprms)
6635 saveSettingsOnExit = !saveSettingsOnExit;
6637 if (saveSettingsOnExit) {
6638 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6640 XtSetArg(args[0], XtNleftBitmap, None);
6642 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6646 void SaveSettingsProc(w, event, prms, nprms)
6652 SaveSettings(settingsFileName);
6655 void InfoProc(w, event, prms, nprms)
6662 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6667 void ManProc(w, event, prms, nprms)
6675 if (nprms && *nprms > 0)
6679 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6683 void HintProc(w, event, prms, nprms)
6692 void BookProc(w, event, prms, nprms)
6701 void AboutProc(w, event, prms, nprms)
6709 char *zippy = " (with Zippy code)";
6713 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6714 programVersion, zippy,
6715 "Copyright 1991 Digital Equipment Corporation",
6716 "Enhancements Copyright 1992-2009 Free Software Foundation",
6717 "Enhancements Copyright 2005 Alessandro Scotti",
6718 PACKAGE, " is free software and carries NO WARRANTY;",
6719 "see the file COPYING for more information.");
6720 ErrorPopUp(_("About XBoard"), buf, FALSE);
6723 void DebugProc(w, event, prms, nprms)
6729 appData.debugMode = !appData.debugMode;
6732 void AboutGameProc(w, event, prms, nprms)
6741 void NothingProc(w, event, prms, nprms)
6750 void Iconify(w, event, prms, nprms)
6759 XtSetArg(args[0], XtNiconic, True);
6760 XtSetValues(shellWidget, args, 1);
6763 void DisplayMessage(message, extMessage)
6764 char *message, *extMessage;
6766 /* display a message in the message widget */
6775 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
6780 message = extMessage;
6784 /* need to test if messageWidget already exists, since this function
6785 can also be called during the startup, if for example a Xresource
6786 is not set up correctly */
6789 XtSetArg(arg, XtNlabel, message);
6790 XtSetValues(messageWidget, &arg, 1);
6796 void DisplayTitle(text)
6801 char title[MSG_SIZ];
6804 if (text == NULL) text = "";
6806 if (appData.titleInWindow) {
6808 XtSetArg(args[i], XtNlabel, text); i++;
6809 XtSetValues(titleWidget, args, i);
6812 if (*text != NULLCHAR) {
6814 strcpy(title, text);
6815 } else if (appData.icsActive) {
6816 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
6817 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
6818 } else if (appData.cmailGameName[0] != NULLCHAR) {
6819 snprintf(icon, sizeof(icon), "%s", "CMail");
6820 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
6822 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
6823 } else if (gameInfo.variant == VariantGothic) {
6824 strcpy(icon, programName);
6825 strcpy(title, GOTHIC);
6828 } else if (gameInfo.variant == VariantFalcon) {
6829 strcpy(icon, programName);
6830 strcpy(title, FALCON);
6832 } else if (appData.noChessProgram) {
6833 strcpy(icon, programName);
6834 strcpy(title, programName);
6836 strcpy(icon, first.tidy);
6837 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
6840 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
6841 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
6842 XtSetValues(shellWidget, args, i);
6846 void DisplayError(message, error)
6853 if (appData.debugMode || appData.matchMode) {
6854 fprintf(stderr, "%s: %s\n", programName, message);
6857 if (appData.debugMode || appData.matchMode) {
6858 fprintf(stderr, "%s: %s: %s\n",
6859 programName, message, strerror(error));
6861 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6864 ErrorPopUp(_("Error"), message, FALSE);
6868 void DisplayMoveError(message)
6873 DrawPosition(FALSE, NULL);
6874 if (appData.debugMode || appData.matchMode) {
6875 fprintf(stderr, "%s: %s\n", programName, message);
6877 if (appData.popupMoveErrors) {
6878 ErrorPopUp(_("Error"), message, FALSE);
6880 DisplayMessage(message, "");
6885 void DisplayFatalError(message, error, status)
6891 errorExitStatus = status;
6893 fprintf(stderr, "%s: %s\n", programName, message);
6895 fprintf(stderr, "%s: %s: %s\n",
6896 programName, message, strerror(error));
6897 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6900 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
6901 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
6907 void DisplayInformation(message)
6911 ErrorPopUp(_("Information"), message, TRUE);
6914 void DisplayNote(message)
6918 ErrorPopUp(_("Note"), message, FALSE);
6922 NullXErrorCheck(dpy, error_event)
6924 XErrorEvent *error_event;
6929 void DisplayIcsInteractionTitle(message)
6932 if (oldICSInteractionTitle == NULL) {
6933 /* Magic to find the old window title, adapted from vim */
6934 char *wina = getenv("WINDOWID");
6936 Window win = (Window) atoi(wina);
6937 Window root, parent, *children;
6938 unsigned int nchildren;
6939 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
6941 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
6942 if (!XQueryTree(xDisplay, win, &root, &parent,
6943 &children, &nchildren)) break;
6944 if (children) XFree((void *)children);
6945 if (parent == root || parent == 0) break;
6948 XSetErrorHandler(oldHandler);
6950 if (oldICSInteractionTitle == NULL) {
6951 oldICSInteractionTitle = "xterm";
6954 printf("\033]0;%s\007", message);
6958 char pendingReplyPrefix[MSG_SIZ];
6959 ProcRef pendingReplyPR;
6961 void AskQuestionProc(w, event, prms, nprms)
6968 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
6972 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
6975 void AskQuestionPopDown()
6977 if (!askQuestionUp) return;
6978 XtPopdown(askQuestionShell);
6979 XtDestroyWidget(askQuestionShell);
6980 askQuestionUp = False;
6983 void AskQuestionReplyAction(w, event, prms, nprms)
6993 reply = XawDialogGetValueString(w = XtParent(w));
6994 strcpy(buf, pendingReplyPrefix);
6995 if (*buf) strcat(buf, " ");
6998 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
6999 AskQuestionPopDown();
7001 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7004 void AskQuestionCallback(w, client_data, call_data)
7006 XtPointer client_data, call_data;
7011 XtSetArg(args[0], XtNlabel, &name);
7012 XtGetValues(w, args, 1);
7014 if (strcmp(name, _("cancel")) == 0) {
7015 AskQuestionPopDown();
7017 AskQuestionReplyAction(w, NULL, NULL, NULL);
7021 void AskQuestion(title, question, replyPrefix, pr)
7022 char *title, *question, *replyPrefix;
7026 Widget popup, layout, dialog, edit;
7032 strcpy(pendingReplyPrefix, replyPrefix);
7033 pendingReplyPR = pr;
7036 XtSetArg(args[i], XtNresizable, True); i++;
7037 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7038 askQuestionShell = popup =
7039 XtCreatePopupShell(title, transientShellWidgetClass,
7040 shellWidget, args, i);
7043 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7044 layoutArgs, XtNumber(layoutArgs));
7047 XtSetArg(args[i], XtNlabel, question); i++;
7048 XtSetArg(args[i], XtNvalue, ""); i++;
7049 XtSetArg(args[i], XtNborderWidth, 0); i++;
7050 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7053 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7054 (XtPointer) dialog);
7055 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7056 (XtPointer) dialog);
7058 XtRealizeWidget(popup);
7059 CatchDeleteWindow(popup, "AskQuestionPopDown");
7061 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7062 &x, &y, &win_x, &win_y, &mask);
7064 XtSetArg(args[0], XtNx, x - 10);
7065 XtSetArg(args[1], XtNy, y - 30);
7066 XtSetValues(popup, args, 2);
7068 XtPopup(popup, XtGrabExclusive);
7069 askQuestionUp = True;
7071 edit = XtNameToWidget(dialog, "*value");
7072 XtSetKeyboardFocus(popup, edit);
7080 if (*name == NULLCHAR) {
7082 } else if (strcmp(name, "$") == 0) {
7083 putc(BELLCHAR, stderr);
7086 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7094 PlaySound(appData.soundMove);
7100 PlaySound(appData.soundIcsWin);
7106 PlaySound(appData.soundIcsLoss);
7112 PlaySound(appData.soundIcsDraw);
7116 PlayIcsUnfinishedSound()
7118 PlaySound(appData.soundIcsUnfinished);
7124 PlaySound(appData.soundIcsAlarm);
7130 system("stty echo");
7136 system("stty -echo");
7140 Colorize(cc, continuation)
7145 int count, outCount, error;
7147 if (textColors[(int)cc].bg > 0) {
7148 if (textColors[(int)cc].fg > 0) {
7149 sprintf(buf, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7150 textColors[(int)cc].fg, textColors[(int)cc].bg);
7152 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7153 textColors[(int)cc].bg);
7156 if (textColors[(int)cc].fg > 0) {
7157 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7158 textColors[(int)cc].fg);
7160 sprintf(buf, "\033[0;%dm", textColors[(int)cc].attr);
7163 count = strlen(buf);
7164 outCount = OutputToProcess(NoProc, buf, count, &error);
7165 if (outCount < count) {
7166 DisplayFatalError(_("Error writing to display"), error, 1);
7169 if (continuation) return;
7172 PlaySound(appData.soundShout);
7175 PlaySound(appData.soundSShout);
7178 PlaySound(appData.soundChannel1);
7181 PlaySound(appData.soundChannel);
7184 PlaySound(appData.soundKibitz);
7187 PlaySound(appData.soundTell);
7189 case ColorChallenge:
7190 PlaySound(appData.soundChallenge);
7193 PlaySound(appData.soundRequest);
7196 PlaySound(appData.soundSeek);
7207 return getpwuid(getuid())->pw_name;
7210 static char *ExpandPathName(path)
7213 static char static_buf[2000];
7214 char *d, *s, buf[2000];
7220 while (*s && isspace(*s))
7229 if (*(s+1) == '/') {
7230 strcpy(d, getpwuid(getuid())->pw_dir);
7235 *strchr(buf, '/') = 0;
7236 pwd = getpwnam(buf);
7239 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7243 strcpy(d, pwd->pw_dir);
7244 strcat(d, strchr(s+1, '/'));
7255 static char host_name[MSG_SIZ];
7257 #if HAVE_GETHOSTNAME
7258 gethostname(host_name, MSG_SIZ);
7260 #else /* not HAVE_GETHOSTNAME */
7261 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7262 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7264 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7266 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7267 #endif /* not HAVE_GETHOSTNAME */
7270 XtIntervalId delayedEventTimerXID = 0;
7271 DelayedEventCallback delayedEventCallback = 0;
7276 delayedEventTimerXID = 0;
7277 delayedEventCallback();
7281 ScheduleDelayedEvent(cb, millisec)
7282 DelayedEventCallback cb; long millisec;
7284 if(delayedEventTimerXID && delayedEventCallback == cb)
7285 // [HGM] alive: replace, rather than add or flush identical event
7286 XtRemoveTimeOut(delayedEventTimerXID);
7287 delayedEventCallback = cb;
7288 delayedEventTimerXID =
7289 XtAppAddTimeOut(appContext, millisec,
7290 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7293 DelayedEventCallback
7296 if (delayedEventTimerXID) {
7297 return delayedEventCallback;
7304 CancelDelayedEvent()
7306 if (delayedEventTimerXID) {
7307 XtRemoveTimeOut(delayedEventTimerXID);
7308 delayedEventTimerXID = 0;
7312 XtIntervalId loadGameTimerXID = 0;
7314 int LoadGameTimerRunning()
7316 return loadGameTimerXID != 0;
7319 int StopLoadGameTimer()
7321 if (loadGameTimerXID != 0) {
7322 XtRemoveTimeOut(loadGameTimerXID);
7323 loadGameTimerXID = 0;
7331 LoadGameTimerCallback(arg, id)
7335 loadGameTimerXID = 0;
7340 StartLoadGameTimer(millisec)
7344 XtAppAddTimeOut(appContext, millisec,
7345 (XtTimerCallbackProc) LoadGameTimerCallback,
7349 XtIntervalId analysisClockXID = 0;
7352 AnalysisClockCallback(arg, id)
7356 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7357 || appData.icsEngineAnalyze) { // [DM]
7358 AnalysisPeriodicEvent(0);
7359 StartAnalysisClock();
7364 StartAnalysisClock()
7367 XtAppAddTimeOut(appContext, 2000,
7368 (XtTimerCallbackProc) AnalysisClockCallback,
7372 XtIntervalId clockTimerXID = 0;
7374 int ClockTimerRunning()
7376 return clockTimerXID != 0;
7379 int StopClockTimer()
7381 if (clockTimerXID != 0) {
7382 XtRemoveTimeOut(clockTimerXID);
7391 ClockTimerCallback(arg, id)
7400 StartClockTimer(millisec)
7404 XtAppAddTimeOut(appContext, millisec,
7405 (XtTimerCallbackProc) ClockTimerCallback,
7410 DisplayTimerLabel(w, color, timer, highlight)
7419 /* check for low time warning */
7420 Pixel foregroundOrWarningColor = timerForegroundPixel;
7423 appData.lowTimeWarning &&
7424 (timer / 1000) < appData.icsAlarmTime)
7425 foregroundOrWarningColor = lowTimeWarningColor;
7427 if (appData.clockMode) {
7428 sprintf(buf, "%s: %s", color, TimeString(timer));
7429 XtSetArg(args[0], XtNlabel, buf);
7431 sprintf(buf, "%s ", color);
7432 XtSetArg(args[0], XtNlabel, buf);
7437 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7438 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7440 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7441 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7444 XtSetValues(w, args, 3);
7448 DisplayWhiteClock(timeRemaining, highlight)
7454 if(appData.noGUI) return;
7455 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7456 if (highlight && iconPixmap == bIconPixmap) {
7457 iconPixmap = wIconPixmap;
7458 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7459 XtSetValues(shellWidget, args, 1);
7464 DisplayBlackClock(timeRemaining, highlight)
7470 if(appData.noGUI) return;
7471 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7472 if (highlight && iconPixmap == wIconPixmap) {
7473 iconPixmap = bIconPixmap;
7474 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7475 XtSetValues(shellWidget, args, 1);
7493 int StartChildProcess(cmdLine, dir, pr)
7500 int to_prog[2], from_prog[2];
7504 if (appData.debugMode) {
7505 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7508 /* We do NOT feed the cmdLine to the shell; we just
7509 parse it into blank-separated arguments in the
7510 most simple-minded way possible.
7513 strcpy(buf, cmdLine);
7516 while(*p == ' ') p++;
7518 if(*p == '"' || *p == '\'')
7519 p = strchr(++argv[i-1], *p);
7520 else p = strchr(p, ' ');
7521 if (p == NULL) break;
7526 SetUpChildIO(to_prog, from_prog);
7528 if ((pid = fork()) == 0) {
7530 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7531 close(to_prog[1]); // first close the unused pipe ends
7532 close(from_prog[0]);
7533 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7534 dup2(from_prog[1], 1);
7535 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7536 close(from_prog[1]); // and closing again loses one of the pipes!
7537 if(fileno(stderr) >= 2) // better safe than sorry...
7538 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7540 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7545 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7547 execvp(argv[0], argv);
7549 /* If we get here, exec failed */
7554 /* Parent process */
7556 close(from_prog[1]);
7558 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7561 cp->fdFrom = from_prog[0];
7562 cp->fdTo = to_prog[1];
7567 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7568 static RETSIGTYPE AlarmCallBack(int n)
7574 DestroyChildProcess(pr, signalType)
7578 ChildProc *cp = (ChildProc *) pr;
7580 if (cp->kind != CPReal) return;
7582 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7583 signal(SIGALRM, AlarmCallBack);
7585 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7586 kill(cp->pid, SIGKILL); // kill it forcefully
7587 wait((int *) 0); // and wait again
7591 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7593 /* Process is exiting either because of the kill or because of
7594 a quit command sent by the backend; either way, wait for it to die.
7603 InterruptChildProcess(pr)
7606 ChildProc *cp = (ChildProc *) pr;
7608 if (cp->kind != CPReal) return;
7609 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7612 int OpenTelnet(host, port, pr)
7617 char cmdLine[MSG_SIZ];
7619 if (port[0] == NULLCHAR) {
7620 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7622 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7624 return StartChildProcess(cmdLine, "", pr);
7627 int OpenTCP(host, port, pr)
7633 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7634 #else /* !OMIT_SOCKETS */
7636 struct sockaddr_in sa;
7638 unsigned short uport;
7641 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7645 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7646 sa.sin_family = AF_INET;
7647 sa.sin_addr.s_addr = INADDR_ANY;
7648 uport = (unsigned short) 0;
7649 sa.sin_port = htons(uport);
7650 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7654 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7655 if (!(hp = gethostbyname(host))) {
7657 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7658 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7659 hp->h_addrtype = AF_INET;
7661 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7662 hp->h_addr_list[0] = (char *) malloc(4);
7663 hp->h_addr_list[0][0] = b0;
7664 hp->h_addr_list[0][1] = b1;
7665 hp->h_addr_list[0][2] = b2;
7666 hp->h_addr_list[0][3] = b3;
7671 sa.sin_family = hp->h_addrtype;
7672 uport = (unsigned short) atoi(port);
7673 sa.sin_port = htons(uport);
7674 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7676 if (connect(s, (struct sockaddr *) &sa,
7677 sizeof(struct sockaddr_in)) < 0) {
7681 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7688 #endif /* !OMIT_SOCKETS */
7693 int OpenCommPort(name, pr)
7700 fd = open(name, 2, 0);
7701 if (fd < 0) return errno;
7703 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7713 int OpenLoopback(pr)
7719 SetUpChildIO(to, from);
7721 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7724 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7731 int OpenRcmd(host, user, cmd, pr)
7732 char *host, *user, *cmd;
7735 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7739 #define INPUT_SOURCE_BUF_SIZE 8192
7748 char buf[INPUT_SOURCE_BUF_SIZE];
7753 DoInputCallback(closure, source, xid)
7758 InputSource *is = (InputSource *) closure;
7763 if (is->lineByLine) {
7764 count = read(is->fd, is->unused,
7765 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7767 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7770 is->unused += count;
7772 while (p < is->unused) {
7773 q = memchr(p, '\n', is->unused - p);
7774 if (q == NULL) break;
7776 (is->func)(is, is->closure, p, q - p, 0);
7780 while (p < is->unused) {
7785 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
7790 (is->func)(is, is->closure, is->buf, count, error);
7794 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
7801 ChildProc *cp = (ChildProc *) pr;
7803 is = (InputSource *) calloc(1, sizeof(InputSource));
7804 is->lineByLine = lineByLine;
7808 is->fd = fileno(stdin);
7810 is->kind = cp->kind;
7811 is->fd = cp->fdFrom;
7814 is->unused = is->buf;
7817 is->xid = XtAppAddInput(appContext, is->fd,
7818 (XtPointer) (XtInputReadMask),
7819 (XtInputCallbackProc) DoInputCallback,
7821 is->closure = closure;
7822 return (InputSourceRef) is;
7826 RemoveInputSource(isr)
7829 InputSource *is = (InputSource *) isr;
7831 if (is->xid == 0) return;
7832 XtRemoveInput(is->xid);
7836 int OutputToProcess(pr, message, count, outError)
7842 static int line = 0;
7843 ChildProc *cp = (ChildProc *) pr;
7848 if (appData.noJoin || !appData.useInternalWrap)
7849 outCount = fwrite(message, 1, count, stdout);
7852 int width = get_term_width();
7853 int len = wrap(NULL, message, count, width, &line);
7854 char *msg = malloc(len);
7858 outCount = fwrite(message, 1, count, stdout);
7861 dbgchk = wrap(msg, message, count, width, &line);
7862 if (dbgchk != len && appData.debugMode)
7863 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
7864 outCount = fwrite(msg, 1, dbgchk, stdout);
7870 outCount = write(cp->fdTo, message, count);
7880 /* Output message to process, with "ms" milliseconds of delay
7881 between each character. This is needed when sending the logon
7882 script to ICC, which for some reason doesn't like the
7883 instantaneous send. */
7884 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
7891 ChildProc *cp = (ChildProc *) pr;
7896 r = write(cp->fdTo, message++, 1);
7909 /**** Animation code by Hugh Fisher, DCS, ANU.
7911 Known problem: if a window overlapping the board is
7912 moved away while a piece is being animated underneath,
7913 the newly exposed area won't be updated properly.
7914 I can live with this.
7916 Known problem: if you look carefully at the animation
7917 of pieces in mono mode, they are being drawn as solid
7918 shapes without interior detail while moving. Fixing
7919 this would be a major complication for minimal return.
7922 /* Masks for XPM pieces. Black and white pieces can have
7923 different shapes, but in the interest of retaining my
7924 sanity pieces must have the same outline on both light
7925 and dark squares, and all pieces must use the same
7926 background square colors/images. */
7928 static int xpmDone = 0;
7931 CreateAnimMasks (pieceDepth)
7938 unsigned long plane;
7941 /* Need a bitmap just to get a GC with right depth */
7942 buf = XCreatePixmap(xDisplay, xBoardWindow,
7944 values.foreground = 1;
7945 values.background = 0;
7946 /* Don't use XtGetGC, not read only */
7947 maskGC = XCreateGC(xDisplay, buf,
7948 GCForeground | GCBackground, &values);
7949 XFreePixmap(xDisplay, buf);
7951 buf = XCreatePixmap(xDisplay, xBoardWindow,
7952 squareSize, squareSize, pieceDepth);
7953 values.foreground = XBlackPixel(xDisplay, xScreen);
7954 values.background = XWhitePixel(xDisplay, xScreen);
7955 bufGC = XCreateGC(xDisplay, buf,
7956 GCForeground | GCBackground, &values);
7958 for (piece = WhitePawn; piece <= BlackKing; piece++) {
7959 /* Begin with empty mask */
7960 if(!xpmDone) // [HGM] pieces: keep using existing
7961 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
7962 squareSize, squareSize, 1);
7963 XSetFunction(xDisplay, maskGC, GXclear);
7964 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
7965 0, 0, squareSize, squareSize);
7967 /* Take a copy of the piece */
7972 XSetFunction(xDisplay, bufGC, GXcopy);
7973 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
7975 0, 0, squareSize, squareSize, 0, 0);
7977 /* XOR the background (light) over the piece */
7978 XSetFunction(xDisplay, bufGC, GXxor);
7980 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
7981 0, 0, squareSize, squareSize, 0, 0);
7983 XSetForeground(xDisplay, bufGC, lightSquareColor);
7984 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
7987 /* We now have an inverted piece image with the background
7988 erased. Construct mask by just selecting all the non-zero
7989 pixels - no need to reconstruct the original image. */
7990 XSetFunction(xDisplay, maskGC, GXor);
7992 /* Might be quicker to download an XImage and create bitmap
7993 data from it rather than this N copies per piece, but it
7994 only takes a fraction of a second and there is a much
7995 longer delay for loading the pieces. */
7996 for (n = 0; n < pieceDepth; n ++) {
7997 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
7998 0, 0, squareSize, squareSize,
8004 XFreePixmap(xDisplay, buf);
8005 XFreeGC(xDisplay, bufGC);
8006 XFreeGC(xDisplay, maskGC);
8010 InitAnimState (anim, info)
8012 XWindowAttributes * info;
8017 /* Each buffer is square size, same depth as window */
8018 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8019 squareSize, squareSize, info->depth);
8020 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8021 squareSize, squareSize, info->depth);
8023 /* Create a plain GC for blitting */
8024 mask = GCForeground | GCBackground | GCFunction |
8025 GCPlaneMask | GCGraphicsExposures;
8026 values.foreground = XBlackPixel(xDisplay, xScreen);
8027 values.background = XWhitePixel(xDisplay, xScreen);
8028 values.function = GXcopy;
8029 values.plane_mask = AllPlanes;
8030 values.graphics_exposures = False;
8031 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8033 /* Piece will be copied from an existing context at
8034 the start of each new animation/drag. */
8035 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8037 /* Outline will be a read-only copy of an existing */
8038 anim->outlineGC = None;
8044 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8045 XWindowAttributes info;
8047 if (xpmDone && gameInfo.variant == old) return;
8048 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8049 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8051 InitAnimState(&game, &info);
8052 InitAnimState(&player, &info);
8054 /* For XPM pieces, we need bitmaps to use as masks. */
8056 CreateAnimMasks(info.depth);
8062 static Boolean frameWaiting;
8064 static RETSIGTYPE FrameAlarm (sig)
8067 frameWaiting = False;
8068 /* In case System-V style signals. Needed?? */
8069 signal(SIGALRM, FrameAlarm);
8076 struct itimerval delay;
8078 XSync(xDisplay, False);
8081 frameWaiting = True;
8082 signal(SIGALRM, FrameAlarm);
8083 delay.it_interval.tv_sec =
8084 delay.it_value.tv_sec = time / 1000;
8085 delay.it_interval.tv_usec =
8086 delay.it_value.tv_usec = (time % 1000) * 1000;
8087 setitimer(ITIMER_REAL, &delay, NULL);
8088 while (frameWaiting) pause();
8089 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8090 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8091 setitimer(ITIMER_REAL, &delay, NULL);
8101 XSync(xDisplay, False);
8103 usleep(time * 1000);
8108 /* Convert board position to corner of screen rect and color */
8111 ScreenSquare(column, row, pt, color)
8112 int column; int row; XPoint * pt; int * color;
8115 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8116 pt->y = lineGap + row * (squareSize + lineGap);
8118 pt->x = lineGap + column * (squareSize + lineGap);
8119 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8121 *color = SquareColor(row, column);
8124 /* Convert window coords to square */
8127 BoardSquare(x, y, column, row)
8128 int x; int y; int * column; int * row;
8130 *column = EventToSquare(x, BOARD_WIDTH);
8131 if (flipView && *column >= 0)
8132 *column = BOARD_WIDTH - 1 - *column;
8133 *row = EventToSquare(y, BOARD_HEIGHT);
8134 if (!flipView && *row >= 0)
8135 *row = BOARD_HEIGHT - 1 - *row;
8140 #undef Max /* just in case */
8142 #define Max(a, b) ((a) > (b) ? (a) : (b))
8143 #define Min(a, b) ((a) < (b) ? (a) : (b))
8146 SetRect(rect, x, y, width, height)
8147 XRectangle * rect; int x; int y; int width; int height;
8151 rect->width = width;
8152 rect->height = height;
8155 /* Test if two frames overlap. If they do, return
8156 intersection rect within old and location of
8157 that rect within new. */
8160 Intersect(old, new, size, area, pt)
8161 XPoint * old; XPoint * new;
8162 int size; XRectangle * area; XPoint * pt;
8164 if (old->x > new->x + size || new->x > old->x + size ||
8165 old->y > new->y + size || new->y > old->y + size) {
8168 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8169 size - abs(old->x - new->x), size - abs(old->y - new->y));
8170 pt->x = Max(old->x - new->x, 0);
8171 pt->y = Max(old->y - new->y, 0);
8176 /* For two overlapping frames, return the rect(s)
8177 in the old that do not intersect with the new. */
8180 CalcUpdateRects(old, new, size, update, nUpdates)
8181 XPoint * old; XPoint * new; int size;
8182 XRectangle update[]; int * nUpdates;
8186 /* If old = new (shouldn't happen) then nothing to draw */
8187 if (old->x == new->x && old->y == new->y) {
8191 /* Work out what bits overlap. Since we know the rects
8192 are the same size we don't need a full intersect calc. */
8194 /* Top or bottom edge? */
8195 if (new->y > old->y) {
8196 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8198 } else if (old->y > new->y) {
8199 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8200 size, old->y - new->y);
8203 /* Left or right edge - don't overlap any update calculated above. */
8204 if (new->x > old->x) {
8205 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8206 new->x - old->x, size - abs(new->y - old->y));
8208 } else if (old->x > new->x) {
8209 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8210 old->x - new->x, size - abs(new->y - old->y));
8217 /* Generate a series of frame coords from start->mid->finish.
8218 The movement rate doubles until the half way point is
8219 reached, then halves back down to the final destination,
8220 which gives a nice slow in/out effect. The algorithmn
8221 may seem to generate too many intermediates for short
8222 moves, but remember that the purpose is to attract the
8223 viewers attention to the piece about to be moved and
8224 then to where it ends up. Too few frames would be less
8228 Tween(start, mid, finish, factor, frames, nFrames)
8229 XPoint * start; XPoint * mid;
8230 XPoint * finish; int factor;
8231 XPoint frames[]; int * nFrames;
8233 int fraction, n, count;
8237 /* Slow in, stepping 1/16th, then 1/8th, ... */
8239 for (n = 0; n < factor; n++)
8241 for (n = 0; n < factor; n++) {
8242 frames[count].x = start->x + (mid->x - start->x) / fraction;
8243 frames[count].y = start->y + (mid->y - start->y) / fraction;
8245 fraction = fraction / 2;
8249 frames[count] = *mid;
8252 /* Slow out, stepping 1/2, then 1/4, ... */
8254 for (n = 0; n < factor; n++) {
8255 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8256 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8258 fraction = fraction * 2;
8263 /* Draw a piece on the screen without disturbing what's there */
8266 SelectGCMask(piece, clip, outline, mask)
8267 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8271 /* Bitmap for piece being moved. */
8272 if (appData.monoMode) {
8273 *mask = *pieceToSolid(piece);
8274 } else if (useImages) {
8276 *mask = xpmMask[piece];
8278 *mask = ximMaskPm[piece];
8281 *mask = *pieceToSolid(piece);
8284 /* GC for piece being moved. Square color doesn't matter, but
8285 since it gets modified we make a copy of the original. */
8287 if (appData.monoMode)
8292 if (appData.monoMode)
8297 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8299 /* Outline only used in mono mode and is not modified */
8301 *outline = bwPieceGC;
8303 *outline = wbPieceGC;
8307 OverlayPiece(piece, clip, outline, dest)
8308 ChessSquare piece; GC clip; GC outline; Drawable dest;
8313 /* Draw solid rectangle which will be clipped to shape of piece */
8314 XFillRectangle(xDisplay, dest, clip,
8315 0, 0, squareSize, squareSize);
8316 if (appData.monoMode)
8317 /* Also draw outline in contrasting color for black
8318 on black / white on white cases */
8319 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8320 0, 0, squareSize, squareSize, 0, 0, 1);
8322 /* Copy the piece */
8327 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8329 0, 0, squareSize, squareSize,
8334 /* Animate the movement of a single piece */
8337 BeginAnimation(anim, piece, startColor, start)
8345 /* The old buffer is initialised with the start square (empty) */
8346 BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8347 anim->prevFrame = *start;
8349 /* The piece will be drawn using its own bitmap as a matte */
8350 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8351 XSetClipMask(xDisplay, anim->pieceGC, mask);
8355 AnimationFrame(anim, frame, piece)
8360 XRectangle updates[4];
8365 /* Save what we are about to draw into the new buffer */
8366 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8367 frame->x, frame->y, squareSize, squareSize,
8370 /* Erase bits of the previous frame */
8371 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8372 /* Where the new frame overlapped the previous,
8373 the contents in newBuf are wrong. */
8374 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8375 overlap.x, overlap.y,
8376 overlap.width, overlap.height,
8378 /* Repaint the areas in the old that don't overlap new */
8379 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8380 for (i = 0; i < count; i++)
8381 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8382 updates[i].x - anim->prevFrame.x,
8383 updates[i].y - anim->prevFrame.y,
8384 updates[i].width, updates[i].height,
8385 updates[i].x, updates[i].y);
8387 /* Easy when no overlap */
8388 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8389 0, 0, squareSize, squareSize,
8390 anim->prevFrame.x, anim->prevFrame.y);
8393 /* Save this frame for next time round */
8394 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8395 0, 0, squareSize, squareSize,
8397 anim->prevFrame = *frame;
8399 /* Draw piece over original screen contents, not current,
8400 and copy entire rect. Wipes out overlapping piece images. */
8401 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8402 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8403 0, 0, squareSize, squareSize,
8404 frame->x, frame->y);
8408 EndAnimation (anim, finish)
8412 XRectangle updates[4];
8417 /* The main code will redraw the final square, so we
8418 only need to erase the bits that don't overlap. */
8419 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8420 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8421 for (i = 0; i < count; i++)
8422 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8423 updates[i].x - anim->prevFrame.x,
8424 updates[i].y - anim->prevFrame.y,
8425 updates[i].width, updates[i].height,
8426 updates[i].x, updates[i].y);
8428 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8429 0, 0, squareSize, squareSize,
8430 anim->prevFrame.x, anim->prevFrame.y);
8435 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8437 ChessSquare piece; int startColor;
8438 XPoint * start; XPoint * finish;
8439 XPoint frames[]; int nFrames;
8443 BeginAnimation(anim, piece, startColor, start);
8444 for (n = 0; n < nFrames; n++) {
8445 AnimationFrame(anim, &(frames[n]), piece);
8446 FrameDelay(appData.animSpeed);
8448 EndAnimation(anim, finish);
8451 /* Main control logic for deciding what to animate and how */
8454 AnimateMove(board, fromX, fromY, toX, toY)
8463 XPoint start, finish, mid;
8464 XPoint frames[kFactor * 2 + 1];
8465 int nFrames, startColor, endColor;
8467 /* Are we animating? */
8468 if (!appData.animate || appData.blindfold)
8471 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8472 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8473 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8475 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8476 piece = board[fromY][fromX];
8477 if (piece >= EmptySquare) return;
8482 hop = (piece == WhiteKnight || piece == BlackKnight);
8485 if (appData.debugMode) {
8486 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8487 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8488 piece, fromX, fromY, toX, toY); }
8490 ScreenSquare(fromX, fromY, &start, &startColor);
8491 ScreenSquare(toX, toY, &finish, &endColor);
8494 /* Knight: make diagonal movement then straight */
8495 if (abs(toY - fromY) < abs(toX - fromX)) {
8496 mid.x = start.x + (finish.x - start.x) / 2;
8500 mid.y = start.y + (finish.y - start.y) / 2;
8503 mid.x = start.x + (finish.x - start.x) / 2;
8504 mid.y = start.y + (finish.y - start.y) / 2;
8507 /* Don't use as many frames for very short moves */
8508 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8509 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8511 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8512 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8514 /* Be sure end square is redrawn */
8515 damage[toY][toX] = True;
8519 DragPieceBegin(x, y)
8522 int boardX, boardY, color;
8525 /* Are we animating? */
8526 if (!appData.animateDragging || appData.blindfold)
8529 /* Figure out which square we start in and the
8530 mouse position relative to top left corner. */
8531 BoardSquare(x, y, &boardX, &boardY);
8532 player.startBoardX = boardX;
8533 player.startBoardY = boardY;
8534 ScreenSquare(boardX, boardY, &corner, &color);
8535 player.startSquare = corner;
8536 player.startColor = color;
8537 /* As soon as we start dragging, the piece will jump slightly to
8538 be centered over the mouse pointer. */
8539 player.mouseDelta.x = squareSize/2;
8540 player.mouseDelta.y = squareSize/2;
8541 /* Initialise animation */
8542 player.dragPiece = PieceForSquare(boardX, boardY);
8544 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8545 player.dragActive = True;
8546 BeginAnimation(&player, player.dragPiece, color, &corner);
8547 /* Mark this square as needing to be redrawn. Note that
8548 we don't remove the piece though, since logically (ie
8549 as seen by opponent) the move hasn't been made yet. */
8550 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8551 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8552 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8553 corner.x, corner.y, squareSize, squareSize,
8554 0, 0); // [HGM] zh: unstack in stead of grab
8555 damage[boardY][boardX] = True;
8557 player.dragActive = False;
8567 /* Are we animating? */
8568 if (!appData.animateDragging || appData.blindfold)
8572 if (! player.dragActive)
8574 /* Move piece, maintaining same relative position
8575 of mouse within square */
8576 corner.x = x - player.mouseDelta.x;
8577 corner.y = y - player.mouseDelta.y;
8578 AnimationFrame(&player, &corner, player.dragPiece);
8580 if (appData.highlightDragging) {
8582 BoardSquare(x, y, &boardX, &boardY);
8583 SetHighlights(fromX, fromY, boardX, boardY);
8592 int boardX, boardY, color;
8595 /* Are we animating? */
8596 if (!appData.animateDragging || appData.blindfold)
8600 if (! player.dragActive)
8602 /* Last frame in sequence is square piece is
8603 placed on, which may not match mouse exactly. */
8604 BoardSquare(x, y, &boardX, &boardY);
8605 ScreenSquare(boardX, boardY, &corner, &color);
8606 EndAnimation(&player, &corner);
8608 /* Be sure end square is redrawn */
8609 damage[boardY][boardX] = True;
8611 /* This prevents weird things happening with fast successive
8612 clicks which on my Sun at least can cause motion events
8613 without corresponding press/release. */
8614 player.dragActive = False;
8617 /* Handle expose event while piece being dragged */
8622 if (!player.dragActive || appData.blindfold)
8625 /* What we're doing: logically, the move hasn't been made yet,
8626 so the piece is still in it's original square. But visually
8627 it's being dragged around the board. So we erase the square
8628 that the piece is on and draw it at the last known drag point. */
8629 BlankSquare(player.startSquare.x, player.startSquare.y,
8630 player.startColor, EmptySquare, xBoardWindow);
8631 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8632 damage[player.startBoardY][player.startBoardX] = TRUE;
8635 #include <sys/ioctl.h>
8636 int get_term_width()
8638 int fd, default_width;
8641 default_width = 79; // this is FICS default anyway...
8643 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8645 if (!ioctl(fd, TIOCGSIZE, &win))
8646 default_width = win.ts_cols;
8647 #elif defined(TIOCGWINSZ)
8649 if (!ioctl(fd, TIOCGWINSZ, &win))
8650 default_width = win.ws_col;
8652 return default_width;
8655 void update_ics_width()
8657 static int old_width = 0;
8658 int new_width = get_term_width();
8660 if (old_width != new_width)
8661 ics_printf("set width %d\n", new_width);
8662 old_width = new_width;
8665 void NotifyFrontendLogin()