2 * xboard.c -- X front end for XBoard
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
8 * 2007, 2008, 2009 Free Software Foundation, Inc.
10 * The following terms apply to Digital Equipment Corporation's copyright
12 * ------------------------------------------------------------------------
15 * Permission to use, copy, modify, and distribute this software and its
16 * documentation for any purpose and without fee is hereby granted,
17 * provided that the above copyright notice appear in all copies and that
18 * both that copyright notice and this permission notice appear in
19 * supporting documentation, and that the name of Digital not be
20 * used in advertising or publicity pertaining to distribution of the
21 * software without specific, written prior permission.
23 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
30 * ------------------------------------------------------------------------
32 * The following terms apply to the enhanced version of XBoard
33 * distributed by the Free Software Foundation:
34 * ------------------------------------------------------------------------
36 * GNU XBoard is free software: you can redistribute it and/or modify
37 * it under the terms of the GNU General Public License as published by
38 * the Free Software Foundation, either version 3 of the License, or (at
39 * your option) any later version.
41 * GNU XBoard is distributed in the hope that it will be useful, but
42 * WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44 * General Public License for more details.
46 * You should have received a copy of the GNU General Public License
47 * along with this program. If not, see http://www.gnu.org/licenses/. *
49 *------------------------------------------------------------------------
50 ** See the file ChangeLog for a revision history. */
58 #include <sys/types.h>
63 # if HAVE_SYS_SOCKET_H
64 # include <sys/socket.h>
65 # include <netinet/in.h>
67 # else /* not HAVE_SYS_SOCKET_H */
68 # if HAVE_LAN_SOCKET_H
69 # include <lan/socket.h>
71 # include <lan/netdb.h>
72 # else /* not HAVE_LAN_SOCKET_H */
73 # define OMIT_SOCKETS 1
74 # endif /* not HAVE_LAN_SOCKET_H */
75 # endif /* not HAVE_SYS_SOCKET_H */
76 #endif /* !OMIT_SOCKETS */
81 #else /* not STDC_HEADERS */
82 extern char *getenv();
85 # else /* not HAVE_STRING_H */
87 # endif /* not HAVE_STRING_H */
88 #endif /* not STDC_HEADERS */
91 # include <sys/fcntl.h>
92 #else /* not HAVE_SYS_FCNTL_H */
95 # endif /* HAVE_FCNTL_H */
96 #endif /* not HAVE_SYS_FCNTL_H */
98 #if HAVE_SYS_SYSTEMINFO_H
99 # include <sys/systeminfo.h>
100 #endif /* HAVE_SYS_SYSTEMINFO_H */
102 #if TIME_WITH_SYS_TIME
103 # include <sys/time.h>
107 # include <sys/time.h>
118 # include <sys/wait.h>
123 # define NAMLEN(dirent) strlen((dirent)->d_name)
124 # define HAVE_DIR_STRUCT
126 # define dirent direct
127 # define NAMLEN(dirent) (dirent)->d_namlen
129 # include <sys/ndir.h>
130 # define HAVE_DIR_STRUCT
133 # include <sys/dir.h>
134 # define HAVE_DIR_STRUCT
138 # define HAVE_DIR_STRUCT
142 #include <X11/Intrinsic.h>
143 #include <X11/StringDefs.h>
144 #include <X11/Shell.h>
145 #include <X11/cursorfont.h>
146 #include <X11/Xatom.h>
147 #include <X11/Xmu/Atoms.h>
149 #include <X11/Xaw3d/Dialog.h>
150 #include <X11/Xaw3d/Form.h>
151 #include <X11/Xaw3d/List.h>
152 #include <X11/Xaw3d/Label.h>
153 #include <X11/Xaw3d/SimpleMenu.h>
154 #include <X11/Xaw3d/SmeBSB.h>
155 #include <X11/Xaw3d/SmeLine.h>
156 #include <X11/Xaw3d/Box.h>
157 #include <X11/Xaw3d/MenuButton.h>
158 #include <X11/Xaw3d/Text.h>
159 #include <X11/Xaw3d/AsciiText.h>
161 #include <X11/Xaw/Dialog.h>
162 #include <X11/Xaw/Form.h>
163 #include <X11/Xaw/List.h>
164 #include <X11/Xaw/Label.h>
165 #include <X11/Xaw/SimpleMenu.h>
166 #include <X11/Xaw/SmeBSB.h>
167 #include <X11/Xaw/SmeLine.h>
168 #include <X11/Xaw/Box.h>
169 #include <X11/Xaw/MenuButton.h>
170 #include <X11/Xaw/Text.h>
171 #include <X11/Xaw/AsciiText.h>
174 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
179 #include "pixmaps/pixmaps.h"
180 #define IMAGE_EXT "xpm"
182 #define IMAGE_EXT "xim"
183 #include "bitmaps/bitmaps.h"
186 #include "bitmaps/icon_white.bm"
187 #include "bitmaps/icon_black.bm"
188 #include "bitmaps/checkmark.bm"
190 #include "frontend.h"
195 #include "xgamelist.h"
196 #include "xhistory.h"
197 #include "xedittags.h"
200 // must be moved to xengineoutput.h
202 void EngineOutputProc P((Widget w, XEvent *event,
203 String *prms, Cardinal *nprms));
204 void EvalGraphProc P((Widget w, XEvent *event,
205 String *prms, Cardinal *nprms));
212 #define usleep(t) _sleep2(((t)+500)/1000)
216 # define _(s) gettext (s)
217 # define N_(s) gettext_noop (s)
233 int main P((int argc, char **argv));
234 RETSIGTYPE CmailSigHandler P((int sig));
235 RETSIGTYPE IntSigHandler P((int sig));
236 RETSIGTYPE TermSizeSigHandler P((int sig));
237 void CreateGCs P((void));
238 void CreateXIMPieces P((void));
239 void CreateXPMPieces P((void));
240 void CreatePieces P((void));
241 void CreatePieceMenus P((void));
242 Widget CreateMenuBar P((Menu *mb));
243 Widget CreateButtonBar P ((MenuItem *mi));
244 char *FindFont P((char *pattern, int targetPxlSize));
245 void PieceMenuPopup P((Widget w, XEvent *event,
246 String *params, Cardinal *num_params));
247 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
248 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
249 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
250 u_int wreq, u_int hreq));
251 void CreateGrid P((void));
252 int EventToSquare P((int x, int limit));
253 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
254 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
255 void HandleUserMove P((Widget w, XEvent *event,
256 String *prms, Cardinal *nprms));
257 void AnimateUserMove P((Widget w, XEvent * event,
258 String * params, Cardinal * nParams));
259 void WhiteClock P((Widget w, XEvent *event,
260 String *prms, Cardinal *nprms));
261 void BlackClock P((Widget w, XEvent *event,
262 String *prms, Cardinal *nprms));
263 void DrawPositionProc P((Widget w, XEvent *event,
264 String *prms, Cardinal *nprms));
265 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
267 void CommentPopUp P((char *title, char *label));
268 void CommentPopDown P((void));
269 void CommentCallback P((Widget w, XtPointer client_data,
270 XtPointer call_data));
271 void ICSInputBoxPopUp P((void));
272 void ICSInputBoxPopDown P((void));
273 void FileNamePopUp P((char *label, char *def,
274 FileProc proc, char *openMode));
275 void FileNamePopDown P((void));
276 void FileNameCallback P((Widget w, XtPointer client_data,
277 XtPointer call_data));
278 void FileNameAction P((Widget w, XEvent *event,
279 String *prms, Cardinal *nprms));
280 void AskQuestionReplyAction P((Widget w, XEvent *event,
281 String *prms, Cardinal *nprms));
282 void AskQuestionProc P((Widget w, XEvent *event,
283 String *prms, Cardinal *nprms));
284 void AskQuestionPopDown P((void));
285 void PromotionPopDown P((void));
286 void PromotionCallback P((Widget w, XtPointer client_data,
287 XtPointer call_data));
288 void EditCommentPopDown P((void));
289 void EditCommentCallback P((Widget w, XtPointer client_data,
290 XtPointer call_data));
291 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
292 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
293 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
294 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
296 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
298 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
300 void LoadPositionProc P((Widget w, XEvent *event,
301 String *prms, Cardinal *nprms));
302 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
304 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
306 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
308 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
310 void PastePositionProc P((Widget w, XEvent *event, String *prms,
312 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
313 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
314 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
315 void SavePositionProc P((Widget w, XEvent *event,
316 String *prms, Cardinal *nprms));
317 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
318 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
320 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
321 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
322 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
324 void MachineWhiteProc P((Widget w, XEvent *event,
325 String *prms, Cardinal *nprms));
326 void AnalyzeModeProc P((Widget w, XEvent *event,
327 String *prms, Cardinal *nprms));
328 void AnalyzeFileProc P((Widget w, XEvent *event,
329 String *prms, Cardinal *nprms));
330 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
332 void IcsClientProc P((Widget w, XEvent *event, String *prms,
334 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
335 void EditPositionProc P((Widget w, XEvent *event,
336 String *prms, Cardinal *nprms));
337 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
338 void EditCommentProc P((Widget w, XEvent *event,
339 String *prms, Cardinal *nprms));
340 void IcsInputBoxProc P((Widget w, XEvent *event,
341 String *prms, Cardinal *nprms));
342 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
343 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
344 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
345 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
346 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
347 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
348 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
349 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
350 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
351 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
352 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
353 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
354 void StopObservingProc P((Widget w, XEvent *event, String *prms,
356 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
358 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
365 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
367 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
370 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
372 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
374 void AutocommProc P((Widget w, XEvent *event, String *prms,
376 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
377 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void AutobsProc P((Widget w, XEvent *event, String *prms,
380 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
385 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
386 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
388 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
390 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
392 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
393 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
394 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
396 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
398 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
400 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
402 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
404 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
405 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
406 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
408 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
410 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
412 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
414 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
415 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
416 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
417 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
418 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
419 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
420 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
421 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
422 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
423 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
424 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
425 void DisplayMove P((int moveNumber));
426 void DisplayTitle P((char *title));
427 void ICSInitScript P((void));
428 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
429 void ErrorPopUp P((char *title, char *text, int modal));
430 void ErrorPopDown P((void));
431 static char *ExpandPathName P((char *path));
432 static void CreateAnimVars P((void));
433 static void DragPieceMove P((int x, int y));
434 static void DrawDragPiece P((void));
435 char *ModeToWidgetName P((GameMode mode));
436 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
442 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
443 void ShufflePopDown P(());
444 void EnginePopDown P(());
445 void UciPopDown P(());
446 void TimeControlPopDown P(());
447 void NewVariantPopDown P(());
448 void SettingsPopDown P(());
449 void update_ics_width P(());
450 int get_term_width P(());
451 int CopyMemoProc P(());
453 * XBoard depends on Xt R4 or higher
455 int xtVersion = XtSpecificationRelease;
460 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
461 jailSquareColor, highlightSquareColor, premoveHighlightColor;
462 Pixel lowTimeWarningColor;
463 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
464 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
465 wjPieceGC, bjPieceGC, prelineGC, countGC;
466 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
467 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
468 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
469 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
470 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
471 ICSInputShell, fileNameShell, askQuestionShell;
472 Widget historyShell, evalGraphShell, gameListShell;
473 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
474 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
475 Font clockFontID, coordFontID, countFontID;
476 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
477 XtAppContext appContext;
479 char *oldICSInteractionTitle;
483 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
485 Position commentX = -1, commentY = -1;
486 Dimension commentW, commentH;
487 typedef unsigned int BoardSize;
489 Boolean chessProgram;
491 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
492 int squareSize, smallLayout = 0, tinyLayout = 0,
493 marginW, marginH, // [HGM] for run-time resizing
494 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
495 ICSInputBoxUp = False, askQuestionUp = False,
496 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
497 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
498 Pixel timerForegroundPixel, timerBackgroundPixel;
499 Pixel buttonForegroundPixel, buttonBackgroundPixel;
500 char *chessDir, *programName, *programVersion,
501 *gameCopyFilename, *gamePasteFilename;
502 Boolean alwaysOnTop = False;
503 Boolean saveSettingsOnExit;
504 char *settingsFileName;
505 char *icsTextMenuString;
507 char *firstChessProgramNames;
508 char *secondChessProgramNames;
510 WindowPlacement wpMain;
511 WindowPlacement wpConsole;
512 WindowPlacement wpComment;
513 WindowPlacement wpMoveHistory;
514 WindowPlacement wpEvalGraph;
515 WindowPlacement wpEngineOutput;
516 WindowPlacement wpGameList;
517 WindowPlacement wpTags;
521 Pixmap pieceBitmap[2][(int)BlackPawn];
522 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
523 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
524 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
525 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
526 int useImages, useImageSqs;
527 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
528 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
529 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
530 XImage *ximLightSquare, *ximDarkSquare;
533 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
534 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
536 #define White(piece) ((int)(piece) < (int)BlackPawn)
538 /* Variables for doing smooth animation. This whole thing
539 would be much easier if the board was double-buffered,
540 but that would require a fairly major rewrite. */
545 GC blitGC, pieceGC, outlineGC;
546 XPoint startSquare, prevFrame, mouseDelta;
550 int startBoardX, startBoardY;
553 /* There can be two pieces being animated at once: a player
554 can begin dragging a piece before the remote opponent has moved. */
556 static AnimState game, player;
558 /* Bitmaps for use as masks when drawing XPM pieces.
559 Need one for each black and white piece. */
560 static Pixmap xpmMask[BlackKing + 1];
562 /* This magic number is the number of intermediate frames used
563 in each half of the animation. For short moves it's reduced
564 by 1. The total number of frames will be factor * 2 + 1. */
567 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
569 MenuItem fileMenu[] = {
570 {N_("New Game"), ResetProc},
571 {N_("New Shuffle Game ..."), ShuffleMenuProc},
572 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
573 {"----", NothingProc},
574 {N_("Load Game"), LoadGameProc},
575 {N_("Load Next Game"), LoadNextGameProc},
576 {N_("Load Previous Game"), LoadPrevGameProc},
577 {N_("Reload Same Game"), ReloadGameProc},
578 {N_("Save Game"), SaveGameProc},
579 {"----", NothingProc},
580 {N_("Copy Game"), CopyGameProc},
581 {N_("Paste Game"), PasteGameProc},
582 {"----", NothingProc},
583 {N_("Load Position"), LoadPositionProc},
584 {N_("Load Next Position"), LoadNextPositionProc},
585 {N_("Load Previous Position"), LoadPrevPositionProc},
586 {N_("Reload Same Position"), ReloadPositionProc},
587 {N_("Save Position"), SavePositionProc},
588 {"----", NothingProc},
589 {N_("Copy Position"), CopyPositionProc},
590 {N_("Paste Position"), PastePositionProc},
591 {"----", NothingProc},
592 {N_("Mail Move"), MailMoveProc},
593 {N_("Reload CMail Message"), ReloadCmailMsgProc},
594 {"----", NothingProc},
595 {N_("Exit"), QuitProc},
599 MenuItem modeMenu[] = {
600 {N_("Machine White"), MachineWhiteProc},
601 {N_("Machine Black"), MachineBlackProc},
602 {N_("Two Machines"), TwoMachinesProc},
603 {N_("Analysis Mode"), AnalyzeModeProc},
604 {N_("Analyze File"), AnalyzeFileProc },
605 {N_("ICS Client"), IcsClientProc},
606 {N_("Edit Game"), EditGameProc},
607 {N_("Edit Position"), EditPositionProc},
608 {N_("Training"), TrainingProc},
609 {"----", NothingProc},
610 {N_("Show Engine Output"), EngineOutputProc},
611 {N_("Show Evaluation Graph"), EvalGraphProc},
612 {N_("Show Game List"), ShowGameListProc},
613 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
614 {"----", NothingProc},
615 {N_("Edit Tags"), EditTagsProc},
616 {N_("Edit Comment"), EditCommentProc},
617 {N_("ICS Input Box"), IcsInputBoxProc},
618 {N_("Pause"), PauseProc},
622 MenuItem actionMenu[] = {
623 {N_("Accept"), AcceptProc},
624 {N_("Decline"), DeclineProc},
625 {N_("Rematch"), RematchProc},
626 {"----", NothingProc},
627 {N_("Call Flag"), CallFlagProc},
628 {N_("Draw"), DrawProc},
629 {N_("Adjourn"), AdjournProc},
630 {N_("Abort"), AbortProc},
631 {N_("Resign"), ResignProc},
632 {"----", NothingProc},
633 {N_("Stop Observing"), StopObservingProc},
634 {N_("Stop Examining"), StopExaminingProc},
635 {"----", NothingProc},
636 {N_("Adjudicate to White"), AdjuWhiteProc},
637 {N_("Adjudicate to Black"), AdjuBlackProc},
638 {N_("Adjudicate Draw"), AdjuDrawProc},
642 MenuItem stepMenu[] = {
643 {N_("Backward"), BackwardProc},
644 {N_("Forward"), ForwardProc},
645 {N_("Back to Start"), ToStartProc},
646 {N_("Forward to End"), ToEndProc},
647 {N_("Revert"), RevertProc},
648 {N_("Truncate Game"), TruncateGameProc},
649 {"----", NothingProc},
650 {N_("Move Now"), MoveNowProc},
651 {N_("Retract Move"), RetractMoveProc},
655 MenuItem optionsMenu[] = {
656 {N_("Flip View"), FlipViewProc},
657 {"----", NothingProc},
658 {N_("Adjudications ..."), EngineMenuProc},
659 {N_("General Settings ..."), UciMenuProc},
660 {N_("Engine #1 Settings ..."), FirstSettingsProc},
661 {N_("Engine #2 Settings ..."), SecondSettingsProc},
662 {N_("Time Control ..."), TimeControlProc},
663 {"----", NothingProc},
664 {N_("Always Queen"), AlwaysQueenProc},
665 {N_("Animate Dragging"), AnimateDraggingProc},
666 {N_("Animate Moving"), AnimateMovingProc},
667 {N_("Auto Comment"), AutocommProc},
668 {N_("Auto Flag"), AutoflagProc},
669 {N_("Auto Flip View"), AutoflipProc},
670 {N_("Auto Observe"), AutobsProc},
671 {N_("Auto Raise Board"), AutoraiseProc},
672 {N_("Auto Save"), AutosaveProc},
673 {N_("Blindfold"), BlindfoldProc},
674 {N_("Flash Moves"), FlashMovesProc},
675 {N_("Get Move List"), GetMoveListProc},
677 {N_("Highlight Dragging"), HighlightDraggingProc},
679 {N_("Highlight Last Move"), HighlightLastMoveProc},
680 {N_("Move Sound"), MoveSoundProc},
681 {N_("ICS Alarm"), IcsAlarmProc},
682 {N_("Old Save Style"), OldSaveStyleProc},
683 {N_("Periodic Updates"), PeriodicUpdatesProc},
684 {N_("Ponder Next Move"), PonderNextMoveProc},
685 {N_("Popup Exit Message"), PopupExitMessageProc},
686 {N_("Popup Move Errors"), PopupMoveErrorsProc},
687 {N_("Premove"), PremoveProc},
688 {N_("Quiet Play"), QuietPlayProc},
689 {N_("Show Coords"), ShowCoordsProc},
690 {N_("Hide Thinking"), HideThinkingProc},
691 {N_("Test Legality"), TestLegalityProc},
692 {"----", NothingProc},
693 {N_("Save Settings Now"), SaveSettingsProc},
694 {N_("Save Settings on Exit"), SaveOnExitProc},
698 MenuItem helpMenu[] = {
699 {N_("Info XBoard"), InfoProc},
700 {N_("Man XBoard"), ManProc},
701 {"----", NothingProc},
702 {N_("Hint"), HintProc},
703 {N_("Book"), BookProc},
704 {"----", NothingProc},
705 {N_("About XBoard"), AboutProc},
710 {N_("File"), fileMenu},
711 {N_("Mode"), modeMenu},
712 {N_("Action"), actionMenu},
713 {N_("Step"), stepMenu},
714 {N_("Options"), optionsMenu},
715 {N_("Help"), helpMenu},
719 #define PAUSE_BUTTON N_("P")
720 MenuItem buttonBar[] = {
723 {PAUSE_BUTTON, PauseProc},
729 #define PIECE_MENU_SIZE 18
730 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
731 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
732 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
733 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
734 N_("Empty square"), N_("Clear board") },
735 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
736 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
737 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
738 N_("Empty square"), N_("Clear board") }
740 /* must be in same order as PieceMenuStrings! */
741 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
742 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
743 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
744 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
745 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
746 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
747 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
748 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
749 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
752 #define DROP_MENU_SIZE 6
753 String dropMenuStrings[DROP_MENU_SIZE] = {
754 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
756 /* must be in same order as PieceMenuStrings! */
757 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
758 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
759 WhiteRook, WhiteQueen
767 DropMenuEnables dmEnables[] = {
785 { XtNborderWidth, 0 },
786 { XtNdefaultDistance, 0 },
790 { XtNborderWidth, 0 },
791 { XtNresizable, (XtArgVal) True },
795 { XtNborderWidth, 0 },
801 { XtNjustify, (XtArgVal) XtJustifyRight },
802 { XtNlabel, (XtArgVal) "..." },
803 { XtNresizable, (XtArgVal) True },
804 { XtNresize, (XtArgVal) False }
807 Arg messageArgs[] = {
808 { XtNjustify, (XtArgVal) XtJustifyLeft },
809 { XtNlabel, (XtArgVal) "..." },
810 { XtNresizable, (XtArgVal) True },
811 { XtNresize, (XtArgVal) False }
815 { XtNborderWidth, 0 },
816 { XtNjustify, (XtArgVal) XtJustifyLeft }
819 XtResource clientResources[] = {
820 { "flashCount", "flashCount", XtRInt, sizeof(int),
821 XtOffset(AppDataPtr, flashCount), XtRImmediate,
822 (XtPointer) FLASH_COUNT },
825 XrmOptionDescRec shellOptions[] = {
826 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
827 { "-flash", "flashCount", XrmoptionNoArg, "3" },
828 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
831 XtActionsRec boardActions[] = {
832 { "DrawPosition", DrawPositionProc },
833 { "HandleUserMove", HandleUserMove },
834 { "AnimateUserMove", AnimateUserMove },
835 { "FileNameAction", FileNameAction },
836 { "AskQuestionProc", AskQuestionProc },
837 { "AskQuestionReplyAction", AskQuestionReplyAction },
838 { "PieceMenuPopup", PieceMenuPopup },
839 { "WhiteClock", WhiteClock },
840 { "BlackClock", BlackClock },
841 { "Iconify", Iconify },
842 { "ResetProc", ResetProc },
843 { "LoadGameProc", LoadGameProc },
844 { "LoadNextGameProc", LoadNextGameProc },
845 { "LoadPrevGameProc", LoadPrevGameProc },
846 { "LoadSelectedProc", LoadSelectedProc },
847 { "ReloadGameProc", ReloadGameProc },
848 { "LoadPositionProc", LoadPositionProc },
849 { "LoadNextPositionProc", LoadNextPositionProc },
850 { "LoadPrevPositionProc", LoadPrevPositionProc },
851 { "ReloadPositionProc", ReloadPositionProc },
852 { "CopyPositionProc", CopyPositionProc },
853 { "PastePositionProc", PastePositionProc },
854 { "CopyGameProc", CopyGameProc },
855 { "PasteGameProc", PasteGameProc },
856 { "SaveGameProc", SaveGameProc },
857 { "SavePositionProc", SavePositionProc },
858 { "MailMoveProc", MailMoveProc },
859 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
860 { "QuitProc", QuitProc },
861 { "MachineWhiteProc", MachineWhiteProc },
862 { "MachineBlackProc", MachineBlackProc },
863 { "AnalysisModeProc", AnalyzeModeProc },
864 { "AnalyzeFileProc", AnalyzeFileProc },
865 { "TwoMachinesProc", TwoMachinesProc },
866 { "IcsClientProc", IcsClientProc },
867 { "EditGameProc", EditGameProc },
868 { "EditPositionProc", EditPositionProc },
869 { "TrainingProc", EditPositionProc },
870 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
871 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
872 { "ShowGameListProc", ShowGameListProc },
873 { "ShowMoveListProc", HistoryShowProc},
874 { "EditTagsProc", EditCommentProc },
875 { "EditCommentProc", EditCommentProc },
876 { "IcsAlarmProc", IcsAlarmProc },
877 { "IcsInputBoxProc", IcsInputBoxProc },
878 { "PauseProc", PauseProc },
879 { "AcceptProc", AcceptProc },
880 { "DeclineProc", DeclineProc },
881 { "RematchProc", RematchProc },
882 { "CallFlagProc", CallFlagProc },
883 { "DrawProc", DrawProc },
884 { "AdjournProc", AdjournProc },
885 { "AbortProc", AbortProc },
886 { "ResignProc", ResignProc },
887 { "AdjuWhiteProc", AdjuWhiteProc },
888 { "AdjuBlackProc", AdjuBlackProc },
889 { "AdjuDrawProc", AdjuDrawProc },
890 { "EnterKeyProc", EnterKeyProc },
891 { "StopObservingProc", StopObservingProc },
892 { "StopExaminingProc", StopExaminingProc },
893 { "BackwardProc", BackwardProc },
894 { "ForwardProc", ForwardProc },
895 { "ToStartProc", ToStartProc },
896 { "ToEndProc", ToEndProc },
897 { "RevertProc", RevertProc },
898 { "TruncateGameProc", TruncateGameProc },
899 { "MoveNowProc", MoveNowProc },
900 { "RetractMoveProc", RetractMoveProc },
901 { "AlwaysQueenProc", AlwaysQueenProc },
902 { "AnimateDraggingProc", AnimateDraggingProc },
903 { "AnimateMovingProc", AnimateMovingProc },
904 { "AutoflagProc", AutoflagProc },
905 { "AutoflipProc", AutoflipProc },
906 { "AutobsProc", AutobsProc },
907 { "AutoraiseProc", AutoraiseProc },
908 { "AutosaveProc", AutosaveProc },
909 { "BlindfoldProc", BlindfoldProc },
910 { "FlashMovesProc", FlashMovesProc },
911 { "FlipViewProc", FlipViewProc },
912 { "GetMoveListProc", GetMoveListProc },
914 { "HighlightDraggingProc", HighlightDraggingProc },
916 { "HighlightLastMoveProc", HighlightLastMoveProc },
917 { "IcsAlarmProc", IcsAlarmProc },
918 { "MoveSoundProc", MoveSoundProc },
919 { "OldSaveStyleProc", OldSaveStyleProc },
920 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
921 { "PonderNextMoveProc", PonderNextMoveProc },
922 { "PopupExitMessageProc", PopupExitMessageProc },
923 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
924 { "PremoveProc", PremoveProc },
925 { "QuietPlayProc", QuietPlayProc },
926 { "ShowCoordsProc", ShowCoordsProc },
927 { "ShowThinkingProc", ShowThinkingProc },
928 { "HideThinkingProc", HideThinkingProc },
929 { "TestLegalityProc", TestLegalityProc },
930 { "SaveSettingsProc", SaveSettingsProc },
931 { "SaveOnExitProc", SaveOnExitProc },
932 { "InfoProc", InfoProc },
933 { "ManProc", ManProc },
934 { "HintProc", HintProc },
935 { "BookProc", BookProc },
936 { "AboutGameProc", AboutGameProc },
937 { "AboutProc", AboutProc },
938 { "DebugProc", DebugProc },
939 { "NothingProc", NothingProc },
940 { "CommentPopDown", (XtActionProc) CommentPopDown },
941 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
942 { "TagsPopDown", (XtActionProc) TagsPopDown },
943 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
944 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
945 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
946 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
947 { "GameListPopDown", (XtActionProc) GameListPopDown },
948 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
949 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
950 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
951 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
952 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
953 { "EnginePopDown", (XtActionProc) EnginePopDown },
954 { "UciPopDown", (XtActionProc) UciPopDown },
955 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
956 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
957 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
958 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
961 char globalTranslations[] =
962 ":<Key>R: ResignProc() \n \
963 :<Key>r: ResetProc() \n \
964 :<Key>g: LoadGameProc() \n \
965 :<Key>N: LoadNextGameProc() \n \
966 :<Key>P: LoadPrevGameProc() \n \
967 :<Key>Q: QuitProc() \n \
968 :<Key>F: ToEndProc() \n \
969 :<Key>f: ForwardProc() \n \
970 :<Key>B: ToStartProc() \n \
971 :<Key>b: BackwardProc() \n \
972 :<Key>p: PauseProc() \n \
973 :<Key>d: DrawProc() \n \
974 :<Key>t: CallFlagProc() \n \
975 :<Key>i: Iconify() \n \
976 :<Key>c: Iconify() \n \
977 :<Key>v: FlipViewProc() \n \
978 <KeyDown>Control_L: BackwardProc() \n \
979 <KeyUp>Control_L: ForwardProc() \n \
980 <KeyDown>Control_R: BackwardProc() \n \
981 <KeyUp>Control_R: ForwardProc() \n \
982 Shift<Key>1: AskQuestionProc(\"Direct command\",\
983 \"Send to chess program:\",,1) \n \
984 Shift<Key>2: AskQuestionProc(\"Direct command\",\
985 \"Send to second chess program:\",,2) \n";
987 char boardTranslations[] =
988 "<Btn1Down>: HandleUserMove() \n \
989 <Btn1Up>: HandleUserMove() \n \
990 <Btn1Motion>: AnimateUserMove() \n \
991 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
992 PieceMenuPopup(menuB) \n \
993 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
994 PieceMenuPopup(menuW) \n \
995 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
996 PieceMenuPopup(menuW) \n \
997 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
998 PieceMenuPopup(menuB) \n";
1000 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1001 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1003 char ICSInputTranslations[] =
1004 "<Key>Return: EnterKeyProc() \n";
1006 String xboardResources[] = {
1007 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1008 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1009 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1014 /* Max possible square size */
1015 #define MAXSQSIZE 256
1017 static int xpm_avail[MAXSQSIZE];
1019 #ifdef HAVE_DIR_STRUCT
1021 /* Extract piece size from filename */
1023 xpm_getsize(name, len, ext)
1034 if ((p=strchr(name, '.')) == NULL ||
1035 StrCaseCmp(p+1, ext) != 0)
1041 while (*p && isdigit(*p))
1048 /* Setup xpm_avail */
1050 xpm_getavail(dirname, ext)
1058 for (i=0; i<MAXSQSIZE; ++i)
1061 if (appData.debugMode)
1062 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1064 dir = opendir(dirname);
1067 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1068 programName, dirname);
1072 while ((ent=readdir(dir)) != NULL) {
1073 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1074 if (i > 0 && i < MAXSQSIZE)
1084 xpm_print_avail(fp, ext)
1090 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1091 for (i=1; i<MAXSQSIZE; ++i) {
1097 /* Return XPM piecesize closest to size */
1099 xpm_closest_to(dirname, size, ext)
1105 int sm_diff = MAXSQSIZE;
1109 xpm_getavail(dirname, ext);
1111 if (appData.debugMode)
1112 xpm_print_avail(stderr, ext);
1114 for (i=1; i<MAXSQSIZE; ++i) {
1117 diff = (diff<0) ? -diff : diff;
1118 if (diff < sm_diff) {
1126 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1132 #else /* !HAVE_DIR_STRUCT */
1133 /* If we are on a system without a DIR struct, we can't
1134 read the directory, so we can't collect a list of
1135 filenames, etc., so we can't do any size-fitting. */
1137 xpm_closest_to(dirname, size, ext)
1142 fprintf(stderr, _("\
1143 Warning: No DIR structure found on this system --\n\
1144 Unable to autosize for XPM/XIM pieces.\n\
1145 Please report this error to frankm@hiwaay.net.\n\
1146 Include system type & operating system in message.\n"));
1149 #endif /* HAVE_DIR_STRUCT */
1151 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1152 "magenta", "cyan", "white" };
1156 TextColors textColors[(int)NColorClasses];
1158 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1160 parse_color(str, which)
1164 char *p, buf[100], *d;
1167 if (strlen(str) > 99) /* watch bounds on buf */
1172 for (i=0; i<which; ++i) {
1179 /* Could be looking at something like:
1181 .. in which case we want to stop on a comma also */
1182 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1186 return -1; /* Use default for empty field */
1189 if (which == 2 || isdigit(*p))
1192 while (*p && isalpha(*p))
1197 for (i=0; i<8; ++i) {
1198 if (!StrCaseCmp(buf, cnames[i]))
1199 return which? (i+40) : (i+30);
1201 if (!StrCaseCmp(buf, "default")) return -1;
1203 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1208 parse_cpair(cc, str)
1212 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1213 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1218 /* bg and attr are optional */
1219 textColors[(int)cc].bg = parse_color(str, 1);
1220 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1221 textColors[(int)cc].attr = 0;
1227 /* Arrange to catch delete-window events */
1228 Atom wm_delete_window;
1230 CatchDeleteWindow(Widget w, String procname)
1233 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1234 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1235 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1242 XtSetArg(args[0], XtNiconic, False);
1243 XtSetValues(shellWidget, args, 1);
1245 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1248 //---------------------------------------------------------------------------------------------------------
1249 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1252 #define CW_USEDEFAULT (1<<31)
1253 #define ICS_TEXT_MENU_SIZE 90
1254 #define DEBUG_FILE "xboard.debug"
1255 #define SetCurrentDirectory chdir
1256 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1260 // these two must some day move to frontend.h, when they are implemented
1261 Boolean MoveHistoryIsUp();
1262 Boolean GameListIsUp();
1264 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1267 // front-end part of option handling
1269 // [HGM] This platform-dependent table provides the location for storing the color info
1270 extern char *crWhite, * crBlack;
1274 &appData.whitePieceColor,
1275 &appData.blackPieceColor,
1276 &appData.lightSquareColor,
1277 &appData.darkSquareColor,
1278 &appData.highlightSquareColor,
1279 &appData.premoveHighlightColor,
1292 ParseFont(char *name, int number)
1293 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1295 case 0: // CLOCK_FONT
1296 appData.clockFont = strdup(name);
1298 case 1: // MESSAGE_FONT
1299 appData.font = strdup(name);
1301 case 2: // COORD_FONT
1302 appData.coordFont = strdup(name);
1311 { // only 2 fonts currently
1312 appData.clockFont = CLOCK_FONT_NAME;
1313 appData.coordFont = COORD_FONT_NAME;
1314 appData.font = DEFAULT_FONT_NAME;
1319 { // no-op, until we identify the code for this already in XBoard and move it here
1323 ParseColor(int n, char *name)
1324 { // in XBoard, just copy the color-name string
1325 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1329 ParseTextAttribs(ColorClass cc, char *s)
1331 (&appData.colorShout)[cc] = strdup(s);
1335 ParseBoardSize(void *addr, char *name)
1337 appData.boardSize = strdup(name);
1342 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1346 SetCommPortDefaults()
1347 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1350 // [HGM] args: these three cases taken out to stay in front-end
1352 SaveFontArg(FILE *f, ArgDescriptor *ad)
1355 switch((int)ad->argLoc) {
1356 case 0: // CLOCK_FONT
1357 name = appData.clockFont;
1359 case 1: // MESSAGE_FONT
1360 name = appData.font;
1362 case 2: // COORD_FONT
1363 name = appData.coordFont;
1368 // Do not save fonts for now, as the saved font would be board-size specific
1369 // and not suitable for a re-start at another board size
1370 // fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, name);
1375 { // nothing to do, as the sounds are at all times represented by their text-string names already
1379 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1380 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1381 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1385 SaveColor(FILE *f, ArgDescriptor *ad)
1386 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1387 if(colorVariable[(int)ad->argLoc])
1388 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1392 SaveBoardSize(FILE *f, char *name, void *addr)
1393 { // wrapper to shield back-end from BoardSize & sizeInfo
1394 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1398 ParseCommPortSettings(char *s)
1399 { // no such option in XBoard (yet)
1402 extern Widget engineOutputShell;
1403 extern Widget tagsShell, editTagsShell;
1405 GetActualPlacement(Widget wg, WindowPlacement *wp)
1415 XtSetArg(args[i], XtNx, &x); i++;
1416 XtSetArg(args[i], XtNy, &y); i++;
1417 XtSetArg(args[i], XtNwidth, &w); i++;
1418 XtSetArg(args[i], XtNheight, &h); i++;
1419 XtGetValues(wg, args, i);
1428 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1429 // In XBoard this will have to wait until awareness of window parameters is implemented
1430 GetActualPlacement(shellWidget, &wpMain);
1431 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1432 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1433 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1434 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1435 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1436 else GetActualPlacement(editShell, &wpComment);
1437 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1438 else GetActualPlacement(editTagsShell, &wpTags);
1442 PrintCommPortSettings(FILE *f, char *name)
1443 { // This option does not exist in XBoard
1447 MySearchPath(char *installDir, char *name, char *fullname)
1448 { // just append installDir and name. Perhaps ExpandPath should be used here?
1449 name = ExpandPathName(name);
1450 if(name && name[0] == '/') strcpy(fullname, name); else {
1451 sprintf(fullname, "%s%c%s", installDir, '/', name);
1457 MyGetFullPathName(char *name, char *fullname)
1458 { // should use ExpandPath?
1459 name = ExpandPathName(name);
1460 strcpy(fullname, name);
1465 EnsureOnScreen(int *x, int *y, int minX, int minY)
1472 { // [HGM] args: allows testing if main window is realized from back-end
1473 return xBoardWindow != 0;
1477 PopUpStartupDialog()
1478 { // start menu not implemented in XBoard
1481 ConvertToLine(int argc, char **argv)
1483 static char line[128*1024], buf[1024];
1487 for(i=1; i<argc; i++) {
1488 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1489 && argv[i][0] != '{' )
1490 sprintf(buf, "{%s} ", argv[i]);
1491 else sprintf(buf, "%s ", argv[i]);
1494 line[strlen(line)-1] = NULLCHAR;
1498 //--------------------------------------------------------------------------------------------
1501 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1503 #define BoardSize int
1504 void InitDrawingSizes(BoardSize boardSize, int flags)
1505 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1506 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1508 XtGeometryResult gres;
1511 if(!formWidget) return;
1514 * Enable shell resizing.
1516 shellArgs[0].value = (XtArgVal) &w;
1517 shellArgs[1].value = (XtArgVal) &h;
1518 XtGetValues(shellWidget, shellArgs, 2);
1520 shellArgs[4].value = 2*w; shellArgs[2].value = 10;
1521 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1522 XtSetValues(shellWidget, &shellArgs[2], 4);
1524 XtSetArg(args[0], XtNdefaultDistance, &sep);
1525 XtGetValues(formWidget, args, 1);
1527 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1528 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1531 XtSetArg(args[0], XtNwidth, boardWidth);
1532 XtSetArg(args[1], XtNheight, boardHeight);
1533 XtSetValues(boardWidget, args, 2);
1535 timerWidth = (boardWidth - sep) / 2;
1536 XtSetArg(args[0], XtNwidth, timerWidth);
1537 XtSetValues(whiteTimerWidget, args, 1);
1538 XtSetValues(blackTimerWidget, args, 1);
1540 XawFormDoLayout(formWidget, False);
1542 if (appData.titleInWindow) {
1544 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1545 XtSetArg(args[i], XtNheight, &h); i++;
1546 XtGetValues(titleWidget, args, i);
1548 w = boardWidth - 2*bor;
1550 XtSetArg(args[0], XtNwidth, &w);
1551 XtGetValues(menuBarWidget, args, 1);
1552 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1555 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1556 if (gres != XtGeometryYes && appData.debugMode) {
1558 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1559 programName, gres, w, h, wr, hr);
1563 XawFormDoLayout(formWidget, True);
1566 * Inhibit shell resizing.
1568 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW;
1569 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1570 shellArgs[4].value = shellArgs[2].value = w;
1571 shellArgs[5].value = shellArgs[3].value = h;
1572 XtSetValues(shellWidget, &shellArgs[0], 6);
1574 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1577 for(i=0; i<4; i++) {
1579 for(p=0; p<=(int)WhiteKing; p++)
1580 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1581 if(gameInfo.variant == VariantShogi) {
1582 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1583 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1584 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1585 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1586 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1589 if(gameInfo.variant == VariantGothic) {
1590 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1594 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1595 for(p=0; p<=(int)WhiteKing; p++)
1596 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1597 if(gameInfo.variant == VariantShogi) {
1598 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1599 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1600 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1601 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1602 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1605 if(gameInfo.variant == VariantGothic) {
1606 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1612 for(i=0; i<2; i++) {
1614 for(p=0; p<=(int)WhiteKing; p++)
1615 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1616 if(gameInfo.variant == VariantShogi) {
1617 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1618 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1619 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1620 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1621 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1624 if(gameInfo.variant == VariantGothic) {
1625 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1636 void EscapeExpand(char *p, char *q)
1637 { // [HGM] initstring: routine to shape up string arguments
1638 while(*p++ = *q++) if(p[-1] == '\\')
1640 case 'n': p[-1] = '\n'; break;
1641 case 'r': p[-1] = '\r'; break;
1642 case 't': p[-1] = '\t'; break;
1643 case '\\': p[-1] = '\\'; break;
1644 case 0: *p = 0; return;
1645 default: p[-1] = q[-1]; break;
1654 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1655 XSetWindowAttributes window_attributes;
1657 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1658 XrmValue vFrom, vTo;
1659 XtGeometryResult gres;
1662 int forceMono = False;
1664 srandom(time(0)); // [HGM] book: make random truly random
1666 setbuf(stdout, NULL);
1667 setbuf(stderr, NULL);
1670 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1671 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1675 programName = strrchr(argv[0], '/');
1676 if (programName == NULL)
1677 programName = argv[0];
1682 XtSetLanguageProc(NULL, NULL, NULL);
1683 bindtextdomain(PACKAGE, LOCALEDIR);
1684 textdomain(PACKAGE);
1688 XtAppInitialize(&appContext, "XBoard", shellOptions,
1689 XtNumber(shellOptions),
1690 &argc, argv, xboardResources, NULL, 0);
1691 appData.boardSize = "";
1692 InitAppData(ConvertToLine(argc, argv));
1694 if (p == NULL) p = "/tmp";
1695 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1696 gameCopyFilename = (char*) malloc(i);
1697 gamePasteFilename = (char*) malloc(i);
1698 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1699 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1701 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1702 clientResources, XtNumber(clientResources),
1705 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1706 static char buf[MSG_SIZ];
1707 EscapeExpand(buf, appData.initString);
1708 appData.initString = strdup(buf);
1709 EscapeExpand(buf, appData.secondInitString);
1710 appData.secondInitString = strdup(buf);
1711 EscapeExpand(buf, appData.firstComputerString);
1712 appData.firstComputerString = strdup(buf);
1713 EscapeExpand(buf, appData.secondComputerString);
1714 appData.secondComputerString = strdup(buf);
1717 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1720 if (chdir(chessDir) != 0) {
1721 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1727 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1728 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1729 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1730 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1733 setbuf(debugFP, NULL);
1736 /* [HGM,HR] make sure board size is acceptable */
1737 if(appData.NrFiles > BOARD_FILES ||
1738 appData.NrRanks > BOARD_RANKS )
1739 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1742 /* This feature does not work; animation needs a rewrite */
1743 appData.highlightDragging = FALSE;
1747 xDisplay = XtDisplay(shellWidget);
1748 xScreen = DefaultScreen(xDisplay);
1749 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1751 gameInfo.variant = StringToVariant(appData.variant);
1752 InitPosition(FALSE);
1755 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1757 if (isdigit(appData.boardSize[0])) {
1758 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1759 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1760 &fontPxlSize, &smallLayout, &tinyLayout);
1762 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1763 programName, appData.boardSize);
1767 /* Find some defaults; use the nearest known size */
1768 SizeDefaults *szd, *nearest;
1769 int distance = 99999;
1770 nearest = szd = sizeDefaults;
1771 while (szd->name != NULL) {
1772 if (abs(szd->squareSize - squareSize) < distance) {
1774 distance = abs(szd->squareSize - squareSize);
1775 if (distance == 0) break;
1779 if (i < 2) lineGap = nearest->lineGap;
1780 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1781 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1782 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1783 if (i < 6) smallLayout = nearest->smallLayout;
1784 if (i < 7) tinyLayout = nearest->tinyLayout;
1787 SizeDefaults *szd = sizeDefaults;
1788 if (*appData.boardSize == NULLCHAR) {
1789 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1790 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1793 if (szd->name == NULL) szd--;
1794 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1796 while (szd->name != NULL &&
1797 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1798 if (szd->name == NULL) {
1799 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1800 programName, appData.boardSize);
1804 squareSize = szd->squareSize;
1805 lineGap = szd->lineGap;
1806 clockFontPxlSize = szd->clockFontPxlSize;
1807 coordFontPxlSize = szd->coordFontPxlSize;
1808 fontPxlSize = szd->fontPxlSize;
1809 smallLayout = szd->smallLayout;
1810 tinyLayout = szd->tinyLayout;
1813 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1814 if (strlen(appData.pixmapDirectory) > 0) {
1815 p = ExpandPathName(appData.pixmapDirectory);
1817 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1818 appData.pixmapDirectory);
1821 if (appData.debugMode) {
1822 fprintf(stderr, _("\
1823 XBoard square size (hint): %d\n\
1824 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1826 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1827 if (appData.debugMode) {
1828 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1832 /* [HR] height treated separately (hacked) */
1833 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1834 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1835 if (appData.showJail == 1) {
1836 /* Jail on top and bottom */
1837 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1838 XtSetArg(boardArgs[2], XtNheight,
1839 boardHeight + 2*(lineGap + squareSize));
1840 } else if (appData.showJail == 2) {
1842 XtSetArg(boardArgs[1], XtNwidth,
1843 boardWidth + 2*(lineGap + squareSize));
1844 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1847 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1848 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1852 * Determine what fonts to use.
1854 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1855 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1856 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1857 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1858 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1859 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1860 appData.font = FindFont(appData.font, fontPxlSize);
1861 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1862 countFontStruct = XQueryFont(xDisplay, countFontID);
1863 // appData.font = FindFont(appData.font, fontPxlSize);
1865 xdb = XtDatabase(xDisplay);
1866 XrmPutStringResource(&xdb, "*font", appData.font);
1869 * Detect if there are not enough colors available and adapt.
1871 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1872 appData.monoMode = True;
1875 if (!appData.monoMode) {
1876 vFrom.addr = (caddr_t) appData.lightSquareColor;
1877 vFrom.size = strlen(appData.lightSquareColor);
1878 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1879 if (vTo.addr == NULL) {
1880 appData.monoMode = True;
1883 lightSquareColor = *(Pixel *) vTo.addr;
1886 if (!appData.monoMode) {
1887 vFrom.addr = (caddr_t) appData.darkSquareColor;
1888 vFrom.size = strlen(appData.darkSquareColor);
1889 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1890 if (vTo.addr == NULL) {
1891 appData.monoMode = True;
1894 darkSquareColor = *(Pixel *) vTo.addr;
1897 if (!appData.monoMode) {
1898 vFrom.addr = (caddr_t) appData.whitePieceColor;
1899 vFrom.size = strlen(appData.whitePieceColor);
1900 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1901 if (vTo.addr == NULL) {
1902 appData.monoMode = True;
1905 whitePieceColor = *(Pixel *) vTo.addr;
1908 if (!appData.monoMode) {
1909 vFrom.addr = (caddr_t) appData.blackPieceColor;
1910 vFrom.size = strlen(appData.blackPieceColor);
1911 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1912 if (vTo.addr == NULL) {
1913 appData.monoMode = True;
1916 blackPieceColor = *(Pixel *) vTo.addr;
1920 if (!appData.monoMode) {
1921 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1922 vFrom.size = strlen(appData.highlightSquareColor);
1923 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1924 if (vTo.addr == NULL) {
1925 appData.monoMode = True;
1928 highlightSquareColor = *(Pixel *) vTo.addr;
1932 if (!appData.monoMode) {
1933 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1934 vFrom.size = strlen(appData.premoveHighlightColor);
1935 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1936 if (vTo.addr == NULL) {
1937 appData.monoMode = True;
1940 premoveHighlightColor = *(Pixel *) vTo.addr;
1945 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1948 if (appData.bitmapDirectory == NULL ||
1949 appData.bitmapDirectory[0] == NULLCHAR)
1950 appData.bitmapDirectory = DEF_BITMAP_DIR;
1953 if (appData.lowTimeWarning && !appData.monoMode) {
1954 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
1955 vFrom.size = strlen(appData.lowTimeWarningColor);
1956 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1957 if (vTo.addr == NULL)
1958 appData.monoMode = True;
1960 lowTimeWarningColor = *(Pixel *) vTo.addr;
1963 if (appData.monoMode && appData.debugMode) {
1964 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1965 (unsigned long) XWhitePixel(xDisplay, xScreen),
1966 (unsigned long) XBlackPixel(xDisplay, xScreen));
1969 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1970 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1971 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1972 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1973 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1974 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1975 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1976 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1977 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1978 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1980 if (appData.colorize) {
1982 _("%s: can't parse color names; disabling colorization\n"),
1985 appData.colorize = FALSE;
1987 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
1988 textColors[ColorNone].attr = 0;
1990 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
1996 layoutName = "tinyLayout";
1997 } else if (smallLayout) {
1998 layoutName = "smallLayout";
2000 layoutName = "normalLayout";
2002 /* Outer layoutWidget is there only to provide a name for use in
2003 resources that depend on the layout style */
2005 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2006 layoutArgs, XtNumber(layoutArgs));
2008 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2009 formArgs, XtNumber(formArgs));
2010 XtSetArg(args[0], XtNdefaultDistance, &sep);
2011 XtGetValues(formWidget, args, 1);
2014 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2015 XtSetArg(args[0], XtNtop, XtChainTop);
2016 XtSetArg(args[1], XtNbottom, XtChainTop);
2017 XtSetArg(args[2], XtNright, XtChainLeft);
2018 XtSetValues(menuBarWidget, args, 3);
2020 widgetList[j++] = whiteTimerWidget =
2021 XtCreateWidget("whiteTime", labelWidgetClass,
2022 formWidget, timerArgs, XtNumber(timerArgs));
2023 XtSetArg(args[0], XtNfont, clockFontStruct);
2024 XtSetArg(args[1], XtNtop, XtChainTop);
2025 XtSetArg(args[2], XtNbottom, XtChainTop);
2026 XtSetValues(whiteTimerWidget, args, 3);
2028 widgetList[j++] = blackTimerWidget =
2029 XtCreateWidget("blackTime", labelWidgetClass,
2030 formWidget, timerArgs, XtNumber(timerArgs));
2031 XtSetArg(args[0], XtNfont, clockFontStruct);
2032 XtSetArg(args[1], XtNtop, XtChainTop);
2033 XtSetArg(args[2], XtNbottom, XtChainTop);
2034 XtSetValues(blackTimerWidget, args, 3);
2036 if (appData.titleInWindow) {
2037 widgetList[j++] = titleWidget =
2038 XtCreateWidget("title", labelWidgetClass, formWidget,
2039 titleArgs, XtNumber(titleArgs));
2040 XtSetArg(args[0], XtNtop, XtChainTop);
2041 XtSetArg(args[1], XtNbottom, XtChainTop);
2042 XtSetValues(titleWidget, args, 2);
2045 if (appData.showButtonBar) {
2046 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2047 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2048 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2049 XtSetArg(args[2], XtNtop, XtChainTop);
2050 XtSetArg(args[3], XtNbottom, XtChainTop);
2051 XtSetValues(buttonBarWidget, args, 4);
2054 widgetList[j++] = messageWidget =
2055 XtCreateWidget("message", labelWidgetClass, formWidget,
2056 messageArgs, XtNumber(messageArgs));
2057 XtSetArg(args[0], XtNtop, XtChainTop);
2058 XtSetArg(args[1], XtNbottom, XtChainTop);
2059 XtSetValues(messageWidget, args, 2);
2061 widgetList[j++] = boardWidget =
2062 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2063 XtNumber(boardArgs));
2065 XtManageChildren(widgetList, j);
2067 timerWidth = (boardWidth - sep) / 2;
2068 XtSetArg(args[0], XtNwidth, timerWidth);
2069 XtSetValues(whiteTimerWidget, args, 1);
2070 XtSetValues(blackTimerWidget, args, 1);
2072 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2073 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2074 XtGetValues(whiteTimerWidget, args, 2);
2076 if (appData.showButtonBar) {
2077 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2078 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2079 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2083 * formWidget uses these constraints but they are stored
2087 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2088 XtSetValues(menuBarWidget, args, i);
2089 if (appData.titleInWindow) {
2092 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2093 XtSetValues(whiteTimerWidget, args, i);
2095 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2096 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2097 XtSetValues(blackTimerWidget, args, i);
2099 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2100 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2101 XtSetValues(titleWidget, args, i);
2103 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2104 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2105 XtSetValues(messageWidget, args, i);
2106 if (appData.showButtonBar) {
2108 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2109 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2110 XtSetValues(buttonBarWidget, args, i);
2114 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2115 XtSetValues(whiteTimerWidget, args, i);
2117 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2118 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2119 XtSetValues(blackTimerWidget, args, i);
2121 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2122 XtSetValues(titleWidget, args, i);
2124 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2125 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2126 XtSetValues(messageWidget, args, i);
2127 if (appData.showButtonBar) {
2129 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2130 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2131 XtSetValues(buttonBarWidget, args, i);
2136 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2137 XtSetValues(whiteTimerWidget, args, i);
2139 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2140 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2141 XtSetValues(blackTimerWidget, args, i);
2143 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2144 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2145 XtSetValues(messageWidget, args, i);
2146 if (appData.showButtonBar) {
2148 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2149 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2150 XtSetValues(buttonBarWidget, args, i);
2154 XtSetArg(args[0], XtNfromVert, messageWidget);
2155 XtSetArg(args[1], XtNtop, XtChainTop);
2156 XtSetArg(args[2], XtNbottom, XtChainBottom);
2157 XtSetArg(args[3], XtNleft, XtChainLeft);
2158 XtSetArg(args[4], XtNright, XtChainRight);
2159 XtSetValues(boardWidget, args, 5);
2161 XtRealizeWidget(shellWidget);
2164 XtSetArg(args[0], XtNx, wpMain.x);
2165 XtSetArg(args[1], XtNy, wpMain.y);
2166 XtSetValues(shellWidget, args, 2);
2170 * Correct the width of the message and title widgets.
2171 * It is not known why some systems need the extra fudge term.
2172 * The value "2" is probably larger than needed.
2174 XawFormDoLayout(formWidget, False);
2176 #define WIDTH_FUDGE 2
2178 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2179 XtSetArg(args[i], XtNheight, &h); i++;
2180 XtGetValues(messageWidget, args, i);
2181 if (appData.showButtonBar) {
2183 XtSetArg(args[i], XtNwidth, &w); i++;
2184 XtGetValues(buttonBarWidget, args, i);
2185 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2187 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2190 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2191 if (gres != XtGeometryYes && appData.debugMode) {
2192 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2193 programName, gres, w, h, wr, hr);
2196 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2197 /* The size used for the child widget in layout lags one resize behind
2198 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2200 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2201 if (gres != XtGeometryYes && appData.debugMode) {
2202 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2203 programName, gres, w, h, wr, hr);
2206 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2207 XtSetArg(args[1], XtNright, XtChainRight);
2208 XtSetValues(messageWidget, args, 2);
2210 if (appData.titleInWindow) {
2212 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2213 XtSetArg(args[i], XtNheight, &h); i++;
2214 XtGetValues(titleWidget, args, i);
2216 w = boardWidth - 2*bor;
2218 XtSetArg(args[0], XtNwidth, &w);
2219 XtGetValues(menuBarWidget, args, 1);
2220 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2223 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2224 if (gres != XtGeometryYes && appData.debugMode) {
2226 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2227 programName, gres, w, h, wr, hr);
2230 XawFormDoLayout(formWidget, True);
2232 xBoardWindow = XtWindow(boardWidget);
2234 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2235 // not need to go into InitDrawingSizes().
2239 * Create X checkmark bitmap and initialize option menu checks.
2241 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2242 checkmark_bits, checkmark_width, checkmark_height);
2243 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2244 if (appData.alwaysPromoteToQueen) {
2245 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2248 if (appData.animateDragging) {
2249 XtSetValues(XtNameToWidget(menuBarWidget,
2250 "menuOptions.Animate Dragging"),
2253 if (appData.animate) {
2254 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2257 if (appData.autoComment) {
2258 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2261 if (appData.autoCallFlag) {
2262 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2265 if (appData.autoFlipView) {
2266 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2269 if (appData.autoObserve) {
2270 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2273 if (appData.autoRaiseBoard) {
2274 XtSetValues(XtNameToWidget(menuBarWidget,
2275 "menuOptions.Auto Raise Board"), args, 1);
2277 if (appData.autoSaveGames) {
2278 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2281 if (appData.saveGameFile[0] != NULLCHAR) {
2282 /* Can't turn this off from menu */
2283 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2285 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2289 if (appData.blindfold) {
2290 XtSetValues(XtNameToWidget(menuBarWidget,
2291 "menuOptions.Blindfold"), args, 1);
2293 if (appData.flashCount > 0) {
2294 XtSetValues(XtNameToWidget(menuBarWidget,
2295 "menuOptions.Flash Moves"),
2298 if (appData.getMoveList) {
2299 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2303 if (appData.highlightDragging) {
2304 XtSetValues(XtNameToWidget(menuBarWidget,
2305 "menuOptions.Highlight Dragging"),
2309 if (appData.highlightLastMove) {
2310 XtSetValues(XtNameToWidget(menuBarWidget,
2311 "menuOptions.Highlight Last Move"),
2314 if (appData.icsAlarm) {
2315 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2318 if (appData.ringBellAfterMoves) {
2319 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2322 if (appData.oldSaveStyle) {
2323 XtSetValues(XtNameToWidget(menuBarWidget,
2324 "menuOptions.Old Save Style"), args, 1);
2326 if (appData.periodicUpdates) {
2327 XtSetValues(XtNameToWidget(menuBarWidget,
2328 "menuOptions.Periodic Updates"), args, 1);
2330 if (appData.ponderNextMove) {
2331 XtSetValues(XtNameToWidget(menuBarWidget,
2332 "menuOptions.Ponder Next Move"), args, 1);
2334 if (appData.popupExitMessage) {
2335 XtSetValues(XtNameToWidget(menuBarWidget,
2336 "menuOptions.Popup Exit Message"), args, 1);
2338 if (appData.popupMoveErrors) {
2339 XtSetValues(XtNameToWidget(menuBarWidget,
2340 "menuOptions.Popup Move Errors"), args, 1);
2342 if (appData.premove) {
2343 XtSetValues(XtNameToWidget(menuBarWidget,
2344 "menuOptions.Premove"), args, 1);
2346 if (appData.quietPlay) {
2347 XtSetValues(XtNameToWidget(menuBarWidget,
2348 "menuOptions.Quiet Play"), args, 1);
2350 if (appData.showCoords) {
2351 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2354 if (appData.hideThinkingFromHuman) {
2355 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2358 if (appData.testLegality) {
2359 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2362 if (saveSettingsOnExit) {
2363 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2370 ReadBitmap(&wIconPixmap, "icon_white.bm",
2371 icon_white_bits, icon_white_width, icon_white_height);
2372 ReadBitmap(&bIconPixmap, "icon_black.bm",
2373 icon_black_bits, icon_black_width, icon_black_height);
2374 iconPixmap = wIconPixmap;
2376 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2377 XtSetValues(shellWidget, args, i);
2380 * Create a cursor for the board widget.
2382 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2383 XChangeWindowAttributes(xDisplay, xBoardWindow,
2384 CWCursor, &window_attributes);
2387 * Inhibit shell resizing.
2389 shellArgs[0].value = (XtArgVal) &w;
2390 shellArgs[1].value = (XtArgVal) &h;
2391 XtGetValues(shellWidget, shellArgs, 2);
2392 shellArgs[4].value = shellArgs[2].value = w;
2393 shellArgs[5].value = shellArgs[3].value = h;
2394 XtSetValues(shellWidget, &shellArgs[2], 4);
2395 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2396 marginH = h - boardHeight;
2398 CatchDeleteWindow(shellWidget, "QuitProc");
2403 if (appData.bitmapDirectory[0] != NULLCHAR) {
2410 /* Create regular pieces */
2411 if (!useImages) CreatePieces();
2416 if (appData.animate || appData.animateDragging)
2419 XtAugmentTranslations(formWidget,
2420 XtParseTranslationTable(globalTranslations));
2421 XtAugmentTranslations(boardWidget,
2422 XtParseTranslationTable(boardTranslations));
2423 XtAugmentTranslations(whiteTimerWidget,
2424 XtParseTranslationTable(whiteTranslations));
2425 XtAugmentTranslations(blackTimerWidget,
2426 XtParseTranslationTable(blackTranslations));
2428 /* Why is the following needed on some versions of X instead
2429 * of a translation? */
2430 XtAddEventHandler(boardWidget, ExposureMask, False,
2431 (XtEventHandler) EventProc, NULL);
2434 /* [AS] Restore layout */
2435 if( wpMoveHistory.visible ) {
2439 if( wpEvalGraph.visible )
2444 if( wpEngineOutput.visible ) {
2445 EngineOutputPopUp();
2450 if (errorExitStatus == -1) {
2451 if (appData.icsActive) {
2452 /* We now wait until we see "login:" from the ICS before
2453 sending the logon script (problems with timestamp otherwise) */
2454 /*ICSInitScript();*/
2455 if (appData.icsInputBox) ICSInputBoxPopUp();
2459 signal(SIGWINCH, TermSizeSigHandler);
2461 signal(SIGINT, IntSigHandler);
2462 signal(SIGTERM, IntSigHandler);
2463 if (*appData.cmailGameName != NULLCHAR) {
2464 signal(SIGUSR1, CmailSigHandler);
2467 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2470 XtAppMainLoop(appContext);
2471 if (appData.debugMode) fclose(debugFP); // [DM] debug
2478 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2479 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2481 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2482 unlink(gameCopyFilename);
2483 unlink(gamePasteFilename);
2486 RETSIGTYPE TermSizeSigHandler(int sig)
2499 CmailSigHandler(sig)
2505 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2507 /* Activate call-back function CmailSigHandlerCallBack() */
2508 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2510 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2514 CmailSigHandlerCallBack(isr, closure, message, count, error)
2522 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2524 /**** end signal code ****/
2534 f = fopen(appData.icsLogon, "r");
2540 strcat(buf, appData.icsLogon);
2541 f = fopen(buf, "r");
2545 ProcessICSInitScript(f);
2552 EditCommentPopDown();
2567 if (!menuBarWidget) return;
2568 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2570 DisplayError("menuStep.Revert", 0);
2572 XtSetSensitive(w, !grey);
2577 SetMenuEnables(enab)
2581 if (!menuBarWidget) return;
2582 while (enab->name != NULL) {
2583 w = XtNameToWidget(menuBarWidget, enab->name);
2585 DisplayError(enab->name, 0);
2587 XtSetSensitive(w, enab->value);
2593 Enables icsEnables[] = {
2594 { "menuFile.Mail Move", False },
2595 { "menuFile.Reload CMail Message", False },
2596 { "menuMode.Machine Black", False },
2597 { "menuMode.Machine White", False },
2598 { "menuMode.Analysis Mode", False },
2599 { "menuMode.Analyze File", False },
2600 { "menuMode.Two Machines", False },
2602 { "menuHelp.Hint", False },
2603 { "menuHelp.Book", False },
2604 { "menuStep.Move Now", False },
2605 { "menuOptions.Periodic Updates", False },
2606 { "menuOptions.Hide Thinking", False },
2607 { "menuOptions.Ponder Next Move", False },
2612 Enables ncpEnables[] = {
2613 { "menuFile.Mail Move", False },
2614 { "menuFile.Reload CMail Message", False },
2615 { "menuMode.Machine White", False },
2616 { "menuMode.Machine Black", False },
2617 { "menuMode.Analysis Mode", False },
2618 { "menuMode.Analyze File", False },
2619 { "menuMode.Two Machines", False },
2620 { "menuMode.ICS Client", False },
2621 { "menuMode.ICS Input Box", False },
2622 { "Action", False },
2623 { "menuStep.Revert", False },
2624 { "menuStep.Move Now", False },
2625 { "menuStep.Retract Move", False },
2626 { "menuOptions.Auto Comment", False },
2627 { "menuOptions.Auto Flag", False },
2628 { "menuOptions.Auto Flip View", False },
2629 { "menuOptions.Auto Observe", False },
2630 { "menuOptions.Auto Raise Board", False },
2631 { "menuOptions.Get Move List", False },
2632 { "menuOptions.ICS Alarm", False },
2633 { "menuOptions.Move Sound", False },
2634 { "menuOptions.Quiet Play", False },
2635 { "menuOptions.Hide Thinking", False },
2636 { "menuOptions.Periodic Updates", False },
2637 { "menuOptions.Ponder Next Move", False },
2638 { "menuHelp.Hint", False },
2639 { "menuHelp.Book", False },
2643 Enables gnuEnables[] = {
2644 { "menuMode.ICS Client", False },
2645 { "menuMode.ICS Input Box", False },
2646 { "menuAction.Accept", False },
2647 { "menuAction.Decline", False },
2648 { "menuAction.Rematch", False },
2649 { "menuAction.Adjourn", False },
2650 { "menuAction.Stop Examining", False },
2651 { "menuAction.Stop Observing", False },
2652 { "menuStep.Revert", False },
2653 { "menuOptions.Auto Comment", False },
2654 { "menuOptions.Auto Observe", False },
2655 { "menuOptions.Auto Raise Board", False },
2656 { "menuOptions.Get Move List", False },
2657 { "menuOptions.Premove", False },
2658 { "menuOptions.Quiet Play", False },
2660 /* The next two options rely on SetCmailMode being called *after* */
2661 /* SetGNUMode so that when GNU is being used to give hints these */
2662 /* menu options are still available */
2664 { "menuFile.Mail Move", False },
2665 { "menuFile.Reload CMail Message", False },
2669 Enables cmailEnables[] = {
2671 { "menuAction.Call Flag", False },
2672 { "menuAction.Draw", True },
2673 { "menuAction.Adjourn", False },
2674 { "menuAction.Abort", False },
2675 { "menuAction.Stop Observing", False },
2676 { "menuAction.Stop Examining", False },
2677 { "menuFile.Mail Move", True },
2678 { "menuFile.Reload CMail Message", True },
2682 Enables trainingOnEnables[] = {
2683 { "menuMode.Edit Comment", False },
2684 { "menuMode.Pause", False },
2685 { "menuStep.Forward", False },
2686 { "menuStep.Backward", False },
2687 { "menuStep.Forward to End", False },
2688 { "menuStep.Back to Start", False },
2689 { "menuStep.Move Now", False },
2690 { "menuStep.Truncate Game", False },
2694 Enables trainingOffEnables[] = {
2695 { "menuMode.Edit Comment", True },
2696 { "menuMode.Pause", True },
2697 { "menuStep.Forward", True },
2698 { "menuStep.Backward", True },
2699 { "menuStep.Forward to End", True },
2700 { "menuStep.Back to Start", True },
2701 { "menuStep.Move Now", True },
2702 { "menuStep.Truncate Game", True },
2706 Enables machineThinkingEnables[] = {
2707 { "menuFile.Load Game", False },
2708 { "menuFile.Load Next Game", False },
2709 { "menuFile.Load Previous Game", False },
2710 { "menuFile.Reload Same Game", False },
2711 { "menuFile.Paste Game", False },
2712 { "menuFile.Load Position", False },
2713 { "menuFile.Load Next Position", False },
2714 { "menuFile.Load Previous Position", False },
2715 { "menuFile.Reload Same Position", False },
2716 { "menuFile.Paste Position", False },
2717 { "menuMode.Machine White", False },
2718 { "menuMode.Machine Black", False },
2719 { "menuMode.Two Machines", False },
2720 { "menuStep.Retract Move", False },
2724 Enables userThinkingEnables[] = {
2725 { "menuFile.Load Game", True },
2726 { "menuFile.Load Next Game", True },
2727 { "menuFile.Load Previous Game", True },
2728 { "menuFile.Reload Same Game", True },
2729 { "menuFile.Paste Game", True },
2730 { "menuFile.Load Position", True },
2731 { "menuFile.Load Next Position", True },
2732 { "menuFile.Load Previous Position", True },
2733 { "menuFile.Reload Same Position", True },
2734 { "menuFile.Paste Position", True },
2735 { "menuMode.Machine White", True },
2736 { "menuMode.Machine Black", True },
2737 { "menuMode.Two Machines", True },
2738 { "menuStep.Retract Move", True },
2744 SetMenuEnables(icsEnables);
2747 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2748 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2755 SetMenuEnables(ncpEnables);
2761 SetMenuEnables(gnuEnables);
2767 SetMenuEnables(cmailEnables);
2773 SetMenuEnables(trainingOnEnables);
2774 if (appData.showButtonBar) {
2775 XtSetSensitive(buttonBarWidget, False);
2781 SetTrainingModeOff()
2783 SetMenuEnables(trainingOffEnables);
2784 if (appData.showButtonBar) {
2785 XtSetSensitive(buttonBarWidget, True);
2790 SetUserThinkingEnables()
2792 if (appData.noChessProgram) return;
2793 SetMenuEnables(userThinkingEnables);
2797 SetMachineThinkingEnables()
2799 if (appData.noChessProgram) return;
2800 SetMenuEnables(machineThinkingEnables);
2802 case MachinePlaysBlack:
2803 case MachinePlaysWhite:
2804 case TwoMachinesPlay:
2805 XtSetSensitive(XtNameToWidget(menuBarWidget,
2806 ModeToWidgetName(gameMode)), True);
2813 #define Abs(n) ((n)<0 ? -(n) : (n))
2816 * Find a font that matches "pattern" that is as close as
2817 * possible to the targetPxlSize. Prefer fonts that are k
2818 * pixels smaller to fonts that are k pixels larger. The
2819 * pattern must be in the X Consortium standard format,
2820 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2821 * The return value should be freed with XtFree when no
2824 char *FindFont(pattern, targetPxlSize)
2828 char **fonts, *p, *best, *scalable, *scalableTail;
2829 int i, j, nfonts, minerr, err, pxlSize;
2832 char **missing_list;
2834 char *def_string, *base_fnt_lst, strInt[3];
2836 XFontStruct **fnt_list;
2838 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2839 sprintf(strInt, "%d", targetPxlSize);
2840 p = strstr(pattern, "--");
2841 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2842 strcat(base_fnt_lst, strInt);
2843 strcat(base_fnt_lst, strchr(p + 2, '-'));
2845 if ((fntSet = XCreateFontSet(xDisplay,
2849 &def_string)) == NULL) {
2851 fprintf(stderr, _("Unable to create font set.\n"));
2855 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2857 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2859 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2860 programName, pattern);
2868 for (i=0; i<nfonts; i++) {
2871 if (*p != '-') continue;
2873 if (*p == NULLCHAR) break;
2874 if (*p++ == '-') j++;
2876 if (j < 7) continue;
2879 scalable = fonts[i];
2882 err = pxlSize - targetPxlSize;
2883 if (Abs(err) < Abs(minerr) ||
2884 (minerr > 0 && err < 0 && -err == minerr)) {
2890 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
2891 /* If the error is too big and there is a scalable font,
2892 use the scalable font. */
2893 int headlen = scalableTail - scalable;
2894 p = (char *) XtMalloc(strlen(scalable) + 10);
2895 while (isdigit(*scalableTail)) scalableTail++;
2896 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
2898 p = (char *) XtMalloc(strlen(best) + 1);
2901 if (appData.debugMode) {
2902 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
2903 pattern, targetPxlSize, p);
2906 if (missing_count > 0)
2907 XFreeStringList(missing_list);
2908 XFreeFontSet(xDisplay, fntSet);
2910 XFreeFontNames(fonts);
2917 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
2918 | GCBackground | GCFunction | GCPlaneMask;
2919 XGCValues gc_values;
2922 gc_values.plane_mask = AllPlanes;
2923 gc_values.line_width = lineGap;
2924 gc_values.line_style = LineSolid;
2925 gc_values.function = GXcopy;
2927 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2928 gc_values.background = XBlackPixel(xDisplay, xScreen);
2929 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2931 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2932 gc_values.background = XWhitePixel(xDisplay, xScreen);
2933 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
2934 XSetFont(xDisplay, coordGC, coordFontID);
2936 // [HGM] make font for holdings counts (white on black0
2937 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2938 gc_values.background = XBlackPixel(xDisplay, xScreen);
2939 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
2940 XSetFont(xDisplay, countGC, countFontID);
2942 if (appData.monoMode) {
2943 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2944 gc_values.background = XWhitePixel(xDisplay, xScreen);
2945 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2947 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2948 gc_values.background = XBlackPixel(xDisplay, xScreen);
2949 lightSquareGC = wbPieceGC
2950 = XtGetGC(shellWidget, value_mask, &gc_values);
2952 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2953 gc_values.background = XWhitePixel(xDisplay, xScreen);
2954 darkSquareGC = bwPieceGC
2955 = XtGetGC(shellWidget, value_mask, &gc_values);
2957 if (DefaultDepth(xDisplay, xScreen) == 1) {
2958 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
2959 gc_values.function = GXcopyInverted;
2960 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
2961 gc_values.function = GXcopy;
2962 if (XBlackPixel(xDisplay, xScreen) == 1) {
2963 bwPieceGC = darkSquareGC;
2964 wbPieceGC = copyInvertedGC;
2966 bwPieceGC = copyInvertedGC;
2967 wbPieceGC = lightSquareGC;
2971 gc_values.foreground = highlightSquareColor;
2972 gc_values.background = highlightSquareColor;
2973 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2975 gc_values.foreground = premoveHighlightColor;
2976 gc_values.background = premoveHighlightColor;
2977 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2979 gc_values.foreground = lightSquareColor;
2980 gc_values.background = darkSquareColor;
2981 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2983 gc_values.foreground = darkSquareColor;
2984 gc_values.background = lightSquareColor;
2985 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2987 gc_values.foreground = jailSquareColor;
2988 gc_values.background = jailSquareColor;
2989 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2991 gc_values.foreground = whitePieceColor;
2992 gc_values.background = darkSquareColor;
2993 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
2995 gc_values.foreground = whitePieceColor;
2996 gc_values.background = lightSquareColor;
2997 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
2999 gc_values.foreground = whitePieceColor;
3000 gc_values.background = jailSquareColor;
3001 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3003 gc_values.foreground = blackPieceColor;
3004 gc_values.background = darkSquareColor;
3005 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3007 gc_values.foreground = blackPieceColor;
3008 gc_values.background = lightSquareColor;
3009 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3011 gc_values.foreground = blackPieceColor;
3012 gc_values.background = jailSquareColor;
3013 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3017 void loadXIM(xim, xmask, filename, dest, mask)
3030 fp = fopen(filename, "rb");
3032 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3039 for (y=0; y<h; ++y) {
3040 for (x=0; x<h; ++x) {
3045 XPutPixel(xim, x, y, blackPieceColor);
3047 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3050 XPutPixel(xim, x, y, darkSquareColor);
3052 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3055 XPutPixel(xim, x, y, whitePieceColor);
3057 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3060 XPutPixel(xim, x, y, lightSquareColor);
3062 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3068 /* create Pixmap of piece */
3069 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3071 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3074 /* create Pixmap of clipmask
3075 Note: We assume the white/black pieces have the same
3076 outline, so we make only 6 masks. This is okay
3077 since the XPM clipmask routines do the same. */
3079 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3081 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3084 /* now create the 1-bit version */
3085 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3088 values.foreground = 1;
3089 values.background = 0;
3091 /* Don't use XtGetGC, not read only */
3092 maskGC = XCreateGC(xDisplay, *mask,
3093 GCForeground | GCBackground, &values);
3094 XCopyPlane(xDisplay, temp, *mask, maskGC,
3095 0, 0, squareSize, squareSize, 0, 0, 1);
3096 XFreePixmap(xDisplay, temp);
3101 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3103 void CreateXIMPieces()
3108 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3113 /* The XSynchronize calls were copied from CreatePieces.
3114 Not sure if needed, but can't hurt */
3115 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3118 /* temp needed by loadXIM() */
3119 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3120 0, 0, ss, ss, AllPlanes, XYPixmap);
3122 if (strlen(appData.pixmapDirectory) == 0) {
3126 if (appData.monoMode) {
3127 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3131 fprintf(stderr, _("\nLoading XIMs...\n"));
3133 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3134 fprintf(stderr, "%d", piece+1);
3135 for (kind=0; kind<4; kind++) {
3136 fprintf(stderr, ".");
3137 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3138 ExpandPathName(appData.pixmapDirectory),
3139 piece <= (int) WhiteKing ? "" : "w",
3140 pieceBitmapNames[piece],
3142 ximPieceBitmap[kind][piece] =
3143 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3144 0, 0, ss, ss, AllPlanes, XYPixmap);
3145 if (appData.debugMode)
3146 fprintf(stderr, _("(File:%s:) "), buf);
3147 loadXIM(ximPieceBitmap[kind][piece],
3149 &(xpmPieceBitmap2[kind][piece]),
3150 &(ximMaskPm2[piece]));
3151 if(piece <= (int)WhiteKing)
3152 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3154 fprintf(stderr," ");
3156 /* Load light and dark squares */
3157 /* If the LSQ and DSQ pieces don't exist, we will
3158 draw them with solid squares. */
3159 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3160 if (access(buf, 0) != 0) {
3164 fprintf(stderr, _("light square "));
3166 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3167 0, 0, ss, ss, AllPlanes, XYPixmap);
3168 if (appData.debugMode)
3169 fprintf(stderr, _("(File:%s:) "), buf);
3171 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3172 fprintf(stderr, _("dark square "));
3173 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3174 ExpandPathName(appData.pixmapDirectory), ss);
3175 if (appData.debugMode)
3176 fprintf(stderr, _("(File:%s:) "), buf);
3178 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3179 0, 0, ss, ss, AllPlanes, XYPixmap);
3180 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3181 xpmJailSquare = xpmLightSquare;
3183 fprintf(stderr, _("Done.\n"));
3185 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3189 void CreateXPMPieces()
3193 u_int ss = squareSize;
3195 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3196 XpmColorSymbol symbols[4];
3198 /* The XSynchronize calls were copied from CreatePieces.
3199 Not sure if needed, but can't hurt */
3200 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3202 /* Setup translations so piece colors match square colors */
3203 symbols[0].name = "light_piece";
3204 symbols[0].value = appData.whitePieceColor;
3205 symbols[1].name = "dark_piece";
3206 symbols[1].value = appData.blackPieceColor;
3207 symbols[2].name = "light_square";
3208 symbols[2].value = appData.lightSquareColor;
3209 symbols[3].name = "dark_square";
3210 symbols[3].value = appData.darkSquareColor;
3212 attr.valuemask = XpmColorSymbols;
3213 attr.colorsymbols = symbols;
3214 attr.numsymbols = 4;
3216 if (appData.monoMode) {
3217 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3221 if (strlen(appData.pixmapDirectory) == 0) {
3222 XpmPieces* pieces = builtInXpms;
3225 while (pieces->size != squareSize && pieces->size) pieces++;
3226 if (!pieces->size) {
3227 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3230 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3231 for (kind=0; kind<4; kind++) {
3233 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3234 pieces->xpm[piece][kind],
3235 &(xpmPieceBitmap2[kind][piece]),
3236 NULL, &attr)) != 0) {
3237 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3241 if(piece <= (int) WhiteKing)
3242 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3246 xpmJailSquare = xpmLightSquare;
3250 fprintf(stderr, _("\nLoading XPMs...\n"));
3253 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3254 fprintf(stderr, "%d ", piece+1);
3255 for (kind=0; kind<4; kind++) {
3256 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3257 ExpandPathName(appData.pixmapDirectory),
3258 piece > (int) WhiteKing ? "w" : "",
3259 pieceBitmapNames[piece],
3261 if (appData.debugMode) {
3262 fprintf(stderr, _("(File:%s:) "), buf);
3264 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3265 &(xpmPieceBitmap2[kind][piece]),
3266 NULL, &attr)) != 0) {
3267 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3268 // [HGM] missing: read of unorthodox piece failed; substitute King.
3269 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3270 ExpandPathName(appData.pixmapDirectory),
3272 if (appData.debugMode) {
3273 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3275 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3276 &(xpmPieceBitmap2[kind][piece]),
3280 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3285 if(piece <= (int) WhiteKing)
3286 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3289 /* Load light and dark squares */
3290 /* If the LSQ and DSQ pieces don't exist, we will
3291 draw them with solid squares. */
3292 fprintf(stderr, _("light square "));
3293 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3294 if (access(buf, 0) != 0) {
3298 if (appData.debugMode)
3299 fprintf(stderr, _("(File:%s:) "), buf);
3301 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3302 &xpmLightSquare, NULL, &attr)) != 0) {
3303 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3306 fprintf(stderr, _("dark square "));
3307 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3308 ExpandPathName(appData.pixmapDirectory), ss);
3309 if (appData.debugMode) {
3310 fprintf(stderr, _("(File:%s:) "), buf);
3312 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3313 &xpmDarkSquare, NULL, &attr)) != 0) {
3314 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3318 xpmJailSquare = xpmLightSquare;
3319 fprintf(stderr, _("Done.\n"));
3321 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3324 #endif /* HAVE_LIBXPM */
3327 /* No built-in bitmaps */
3332 u_int ss = squareSize;
3334 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3337 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3338 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3339 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3340 pieceBitmapNames[piece],
3341 ss, kind == SOLID ? 's' : 'o');
3342 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3343 if(piece <= (int)WhiteKing)
3344 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3348 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3352 /* With built-in bitmaps */
3355 BuiltInBits* bib = builtInBits;
3358 u_int ss = squareSize;
3360 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3363 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3365 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3366 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3367 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3368 pieceBitmapNames[piece],
3369 ss, kind == SOLID ? 's' : 'o');
3370 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3371 bib->bits[kind][piece], ss, ss);
3372 if(piece <= (int)WhiteKing)
3373 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3377 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3382 void ReadBitmap(pm, name, bits, wreq, hreq)
3385 unsigned char bits[];
3391 char msg[MSG_SIZ], fullname[MSG_SIZ];
3393 if (*appData.bitmapDirectory != NULLCHAR) {
3394 strcpy(fullname, appData.bitmapDirectory);
3395 strcat(fullname, "/");
3396 strcat(fullname, name);
3397 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3398 &w, &h, pm, &x_hot, &y_hot);
3399 fprintf(stderr, "load %s\n", name);
3400 if (errcode != BitmapSuccess) {
3402 case BitmapOpenFailed:
3403 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3405 case BitmapFileInvalid:
3406 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3408 case BitmapNoMemory:
3409 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3413 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3417 fprintf(stderr, _("%s: %s...using built-in\n"),
3419 } else if (w != wreq || h != hreq) {
3421 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3422 programName, fullname, w, h, wreq, hreq);
3428 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3437 if (lineGap == 0) return;
3439 /* [HR] Split this into 2 loops for non-square boards. */
3441 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3442 gridSegments[i].x1 = 0;
3443 gridSegments[i].x2 =
3444 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3445 gridSegments[i].y1 = gridSegments[i].y2
3446 = lineGap / 2 + (i * (squareSize + lineGap));
3449 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3450 gridSegments[j + i].y1 = 0;
3451 gridSegments[j + i].y2 =
3452 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3453 gridSegments[j + i].x1 = gridSegments[j + i].x2
3454 = lineGap / 2 + (j * (squareSize + lineGap));
3458 static void MenuBarSelect(w, addr, index)
3463 XtActionProc proc = (XtActionProc) addr;
3465 (proc)(NULL, NULL, NULL, NULL);
3468 void CreateMenuBarPopup(parent, name, mb)
3478 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3481 XtSetArg(args[j], XtNleftMargin, 20); j++;
3482 XtSetArg(args[j], XtNrightMargin, 20); j++;
3484 while (mi->string != NULL) {
3485 if (strcmp(mi->string, "----") == 0) {
3486 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3489 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3490 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3492 XtAddCallback(entry, XtNcallback,
3493 (XtCallbackProc) MenuBarSelect,
3494 (caddr_t) mi->proc);
3500 Widget CreateMenuBar(mb)
3504 Widget anchor, menuBar;
3506 char menuName[MSG_SIZ];
3509 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3510 XtSetArg(args[j], XtNvSpace, 0); j++;
3511 XtSetArg(args[j], XtNborderWidth, 0); j++;
3512 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3513 formWidget, args, j);
3515 while (mb->name != NULL) {
3516 strcpy(menuName, "menu");
3517 strcat(menuName, mb->name);
3519 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3522 shortName[0] = _(mb->name)[0];
3523 shortName[1] = NULLCHAR;
3524 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3527 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3530 XtSetArg(args[j], XtNborderWidth, 0); j++;
3531 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3533 CreateMenuBarPopup(menuBar, menuName, mb);
3539 Widget CreateButtonBar(mi)
3543 Widget button, buttonBar;
3547 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3549 XtSetArg(args[j], XtNhSpace, 0); j++;
3551 XtSetArg(args[j], XtNborderWidth, 0); j++;
3552 XtSetArg(args[j], XtNvSpace, 0); j++;
3553 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3554 formWidget, args, j);
3556 while (mi->string != NULL) {
3559 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3560 XtSetArg(args[j], XtNborderWidth, 0); j++;
3562 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3563 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3564 buttonBar, args, j);
3565 XtAddCallback(button, XtNcallback,
3566 (XtCallbackProc) MenuBarSelect,
3567 (caddr_t) mi->proc);
3574 CreatePieceMenu(name, color)
3581 ChessSquare selection;
3583 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3584 boardWidget, args, 0);
3586 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3587 String item = pieceMenuStrings[color][i];
3589 if (strcmp(item, "----") == 0) {
3590 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3593 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3594 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3596 selection = pieceMenuTranslation[color][i];
3597 XtAddCallback(entry, XtNcallback,
3598 (XtCallbackProc) PieceMenuSelect,
3599 (caddr_t) selection);
3600 if (selection == WhitePawn || selection == BlackPawn) {
3601 XtSetArg(args[0], XtNpopupOnEntry, entry);
3602 XtSetValues(menu, args, 1);
3615 ChessSquare selection;
3617 whitePieceMenu = CreatePieceMenu("menuW", 0);
3618 blackPieceMenu = CreatePieceMenu("menuB", 1);
3620 XtRegisterGrabAction(PieceMenuPopup, True,
3621 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3622 GrabModeAsync, GrabModeAsync);
3624 XtSetArg(args[0], XtNlabel, _("Drop"));
3625 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3626 boardWidget, args, 1);
3627 for (i = 0; i < DROP_MENU_SIZE; i++) {
3628 String item = dropMenuStrings[i];
3630 if (strcmp(item, "----") == 0) {
3631 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3634 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3635 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3637 selection = dropMenuTranslation[i];
3638 XtAddCallback(entry, XtNcallback,
3639 (XtCallbackProc) DropMenuSelect,
3640 (caddr_t) selection);
3645 void SetupDropMenu()
3653 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3654 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3655 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3656 dmEnables[i].piece);
3657 XtSetSensitive(entry, p != NULL || !appData.testLegality
3658 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3659 && !appData.icsActive));
3661 while (p && *p++ == dmEnables[i].piece) count++;
3662 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3664 XtSetArg(args[j], XtNlabel, label); j++;
3665 XtSetValues(entry, args, j);
3669 void PieceMenuPopup(w, event, params, num_params)
3673 Cardinal *num_params;
3676 if (event->type != ButtonPress) return;
3677 if (errorUp) ErrorPopDown();
3681 whichMenu = params[0];
3683 case IcsPlayingWhite:
3684 case IcsPlayingBlack:
3686 case MachinePlaysWhite:
3687 case MachinePlaysBlack:
3688 if (appData.testLegality &&
3689 gameInfo.variant != VariantBughouse &&
3690 gameInfo.variant != VariantCrazyhouse) return;
3692 whichMenu = "menuD";
3698 if (((pmFromX = EventToSquare(event->xbutton.x, BOARD_WIDTH)) < 0) ||
3699 ((pmFromY = EventToSquare(event->xbutton.y, BOARD_HEIGHT)) < 0)) {
3700 pmFromX = pmFromY = -1;
3704 pmFromX = BOARD_WIDTH - 1 - pmFromX;
3706 pmFromY = BOARD_HEIGHT - 1 - pmFromY;
3708 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3711 static void PieceMenuSelect(w, piece, junk)
3716 if (pmFromX < 0 || pmFromY < 0) return;
3717 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3720 static void DropMenuSelect(w, piece, junk)
3725 if (pmFromX < 0 || pmFromY < 0) return;
3726 DropMenuEvent(piece, pmFromX, pmFromY);
3729 void WhiteClock(w, event, prms, nprms)
3735 if (gameMode == EditPosition || gameMode == IcsExamining) {
3736 SetWhiteToPlayEvent();
3737 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3742 void BlackClock(w, event, prms, nprms)
3748 if (gameMode == EditPosition || gameMode == IcsExamining) {
3749 SetBlackToPlayEvent();
3750 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3757 * If the user selects on a border boundary, return -1; if off the board,
3758 * return -2. Otherwise map the event coordinate to the square.
3760 int EventToSquare(x, limit)
3768 if ((x % (squareSize + lineGap)) >= squareSize)
3770 x /= (squareSize + lineGap);
3776 static void do_flash_delay(msec)
3782 static void drawHighlight(file, rank, gc)
3788 if (lineGap == 0 || appData.blindfold) return;
3791 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3792 (squareSize + lineGap);
3793 y = lineGap/2 + rank * (squareSize + lineGap);
3795 x = lineGap/2 + file * (squareSize + lineGap);
3796 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3797 (squareSize + lineGap);
3800 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3801 squareSize+lineGap, squareSize+lineGap);
3804 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3805 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3808 SetHighlights(fromX, fromY, toX, toY)
3809 int fromX, fromY, toX, toY;
3811 if (hi1X != fromX || hi1Y != fromY) {
3812 if (hi1X >= 0 && hi1Y >= 0) {
3813 drawHighlight(hi1X, hi1Y, lineGC);
3815 if (fromX >= 0 && fromY >= 0) {
3816 drawHighlight(fromX, fromY, highlineGC);
3819 if (hi2X != toX || hi2Y != toY) {
3820 if (hi2X >= 0 && hi2Y >= 0) {
3821 drawHighlight(hi2X, hi2Y, lineGC);
3823 if (toX >= 0 && toY >= 0) {
3824 drawHighlight(toX, toY, highlineGC);
3836 SetHighlights(-1, -1, -1, -1);
3841 SetPremoveHighlights(fromX, fromY, toX, toY)
3842 int fromX, fromY, toX, toY;
3844 if (pm1X != fromX || pm1Y != fromY) {
3845 if (pm1X >= 0 && pm1Y >= 0) {
3846 drawHighlight(pm1X, pm1Y, lineGC);
3848 if (fromX >= 0 && fromY >= 0) {
3849 drawHighlight(fromX, fromY, prelineGC);
3852 if (pm2X != toX || pm2Y != toY) {
3853 if (pm2X >= 0 && pm2Y >= 0) {
3854 drawHighlight(pm2X, pm2Y, lineGC);
3856 if (toX >= 0 && toY >= 0) {
3857 drawHighlight(toX, toY, prelineGC);
3867 ClearPremoveHighlights()
3869 SetPremoveHighlights(-1, -1, -1, -1);
3872 static void BlankSquare(x, y, color, piece, dest)
3877 if (useImages && useImageSqs) {
3881 pm = xpmLightSquare;
3886 case 2: /* neutral */
3891 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
3892 squareSize, squareSize, x, y);
3902 case 2: /* neutral */
3907 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
3912 I split out the routines to draw a piece so that I could
3913 make a generic flash routine.
3915 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
3917 int square_color, x, y;
3920 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3921 switch (square_color) {
3923 case 2: /* neutral */
3925 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3926 ? *pieceToOutline(piece)
3927 : *pieceToSolid(piece),
3928 dest, bwPieceGC, 0, 0,
3929 squareSize, squareSize, x, y);
3932 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3933 ? *pieceToSolid(piece)
3934 : *pieceToOutline(piece),
3935 dest, wbPieceGC, 0, 0,
3936 squareSize, squareSize, x, y);
3941 static void monoDrawPiece(piece, square_color, x, y, dest)
3943 int square_color, x, y;
3946 switch (square_color) {
3948 case 2: /* neutral */
3950 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3951 ? *pieceToOutline(piece)
3952 : *pieceToSolid(piece),
3953 dest, bwPieceGC, 0, 0,
3954 squareSize, squareSize, x, y, 1);
3957 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3958 ? *pieceToSolid(piece)
3959 : *pieceToOutline(piece),
3960 dest, wbPieceGC, 0, 0,
3961 squareSize, squareSize, x, y, 1);
3966 static void colorDrawPiece(piece, square_color, x, y, dest)
3968 int square_color, x, y;
3971 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
3972 switch (square_color) {
3974 XCopyPlane(xDisplay, *pieceToSolid(piece),
3975 dest, (int) piece < (int) BlackPawn
3976 ? wlPieceGC : blPieceGC, 0, 0,
3977 squareSize, squareSize, x, y, 1);
3980 XCopyPlane(xDisplay, *pieceToSolid(piece),
3981 dest, (int) piece < (int) BlackPawn
3982 ? wdPieceGC : bdPieceGC, 0, 0,
3983 squareSize, squareSize, x, y, 1);
3985 case 2: /* neutral */
3987 XCopyPlane(xDisplay, *pieceToSolid(piece),
3988 dest, (int) piece < (int) BlackPawn
3989 ? wjPieceGC : bjPieceGC, 0, 0,
3990 squareSize, squareSize, x, y, 1);
3995 static void colorDrawPieceImage(piece, square_color, x, y, dest)
3997 int square_color, x, y;
4002 switch (square_color) {
4004 case 2: /* neutral */
4006 if ((int)piece < (int) BlackPawn) {
4014 if ((int)piece < (int) BlackPawn) {
4022 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4023 dest, wlPieceGC, 0, 0,
4024 squareSize, squareSize, x, y);
4027 typedef void (*DrawFunc)();
4029 DrawFunc ChooseDrawFunc()
4031 if (appData.monoMode) {
4032 if (DefaultDepth(xDisplay, xScreen) == 1) {
4033 return monoDrawPiece_1bit;
4035 return monoDrawPiece;
4039 return colorDrawPieceImage;
4041 return colorDrawPiece;
4045 /* [HR] determine square color depending on chess variant. */
4046 static int SquareColor(row, column)
4051 if (gameInfo.variant == VariantXiangqi) {
4052 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4054 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4056 } else if (row <= 4) {
4062 square_color = ((column + row) % 2) == 1;
4065 /* [hgm] holdings: next line makes all holdings squares light */
4066 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4068 return square_color;
4071 void DrawSquare(row, column, piece, do_flash)
4072 int row, column, do_flash;
4075 int square_color, x, y, direction, font_ascent, font_descent;
4078 XCharStruct overall;
4082 /* Calculate delay in milliseconds (2-delays per complete flash) */
4083 flash_delay = 500 / appData.flashRate;
4086 x = lineGap + ((BOARD_WIDTH-1)-column) *
4087 (squareSize + lineGap);
4088 y = lineGap + row * (squareSize + lineGap);
4090 x = lineGap + column * (squareSize + lineGap);
4091 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4092 (squareSize + lineGap);
4095 square_color = SquareColor(row, column);
4097 if ( // [HGM] holdings: blank out area between board and holdings
4098 column == BOARD_LEFT-1 || column == BOARD_RGHT
4099 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4100 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4101 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4103 // [HGM] print piece counts next to holdings
4104 string[1] = NULLCHAR;
4105 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4106 string[0] = '0' + piece;
4107 XTextExtents(countFontStruct, string, 1, &direction,
4108 &font_ascent, &font_descent, &overall);
4109 if (appData.monoMode) {
4110 XDrawImageString(xDisplay, xBoardWindow, countGC,
4111 x + squareSize - overall.width - 2,
4112 y + font_ascent + 1, string, 1);
4114 XDrawString(xDisplay, xBoardWindow, countGC,
4115 x + squareSize - overall.width - 2,
4116 y + font_ascent + 1, string, 1);
4119 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4120 string[0] = '0' + piece;
4121 XTextExtents(countFontStruct, string, 1, &direction,
4122 &font_ascent, &font_descent, &overall);
4123 if (appData.monoMode) {
4124 XDrawImageString(xDisplay, xBoardWindow, countGC,
4125 x + 2, y + font_ascent + 1, string, 1);
4127 XDrawString(xDisplay, xBoardWindow, countGC,
4128 x + 2, y + font_ascent + 1, string, 1);
4132 if (piece == EmptySquare || appData.blindfold) {
4133 BlankSquare(x, y, square_color, piece, xBoardWindow);
4135 drawfunc = ChooseDrawFunc();
4136 if (do_flash && appData.flashCount > 0) {
4137 for (i=0; i<appData.flashCount; ++i) {
4139 drawfunc(piece, square_color, x, y, xBoardWindow);
4140 XSync(xDisplay, False);
4141 do_flash_delay(flash_delay);
4143 BlankSquare(x, y, square_color, piece, xBoardWindow);
4144 XSync(xDisplay, False);
4145 do_flash_delay(flash_delay);
4148 drawfunc(piece, square_color, x, y, xBoardWindow);
4152 string[1] = NULLCHAR;
4153 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4154 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4155 string[0] = 'a' + column - BOARD_LEFT;
4156 XTextExtents(coordFontStruct, string, 1, &direction,
4157 &font_ascent, &font_descent, &overall);
4158 if (appData.monoMode) {
4159 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4160 x + squareSize - overall.width - 2,
4161 y + squareSize - font_descent - 1, string, 1);
4163 XDrawString(xDisplay, xBoardWindow, coordGC,
4164 x + squareSize - overall.width - 2,
4165 y + squareSize - font_descent - 1, string, 1);
4168 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4169 string[0] = ONE + row;
4170 XTextExtents(coordFontStruct, string, 1, &direction,
4171 &font_ascent, &font_descent, &overall);
4172 if (appData.monoMode) {
4173 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4174 x + 2, y + font_ascent + 1, string, 1);
4176 XDrawString(xDisplay, xBoardWindow, coordGC,
4177 x + 2, y + font_ascent + 1, string, 1);
4183 /* Why is this needed on some versions of X? */
4184 void EventProc(widget, unused, event)
4189 if (!XtIsRealized(widget))
4192 switch (event->type) {
4194 if (event->xexpose.count > 0) return; /* no clipping is done */
4195 XDrawPosition(widget, True, NULL);
4203 void DrawPosition(fullRedraw, board)
4204 /*Boolean*/int fullRedraw;
4207 XDrawPosition(boardWidget, fullRedraw, board);
4210 /* Returns 1 if there are "too many" differences between b1 and b2
4211 (i.e. more than 1 move was made) */
4212 static int too_many_diffs(b1, b2)
4218 for (i=0; i<BOARD_HEIGHT; ++i) {
4219 for (j=0; j<BOARD_WIDTH; ++j) {
4220 if (b1[i][j] != b2[i][j]) {
4221 if (++c > 4) /* Castling causes 4 diffs */
4230 /* Matrix describing castling maneuvers */
4231 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4232 static int castling_matrix[4][5] = {
4233 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4234 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4235 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4236 { 7, 7, 4, 5, 6 } /* 0-0, black */
4239 /* Checks whether castling occurred. If it did, *rrow and *rcol
4240 are set to the destination (row,col) of the rook that moved.
4242 Returns 1 if castling occurred, 0 if not.
4244 Note: Only handles a max of 1 castling move, so be sure
4245 to call too_many_diffs() first.
4247 static int check_castle_draw(newb, oldb, rrow, rcol)
4254 /* For each type of castling... */
4255 for (i=0; i<4; ++i) {
4256 r = castling_matrix[i];
4258 /* Check the 4 squares involved in the castling move */
4260 for (j=1; j<=4; ++j) {
4261 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4268 /* All 4 changed, so it must be a castling move */
4277 static int damage[BOARD_RANKS][BOARD_FILES];
4280 * event handler for redrawing the board
4282 void XDrawPosition(w, repaint, board)
4284 /*Boolean*/int repaint;
4288 static int lastFlipView = 0;
4289 static int lastBoardValid = 0;
4290 static Board lastBoard;
4294 if (board == NULL) {
4295 if (!lastBoardValid) return;
4298 if (!lastBoardValid || lastFlipView != flipView) {
4299 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4300 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4305 * It would be simpler to clear the window with XClearWindow()
4306 * but this causes a very distracting flicker.
4309 if (!repaint && lastBoardValid && lastFlipView == flipView) {
4311 /* If too much changes (begin observing new game, etc.), don't
4313 do_flash = too_many_diffs(board, lastBoard) ? 0 : 1;
4315 /* Special check for castling so we don't flash both the king
4316 and the rook (just flash the king). */
4318 if (check_castle_draw(board, lastBoard, &rrow, &rcol)) {
4319 /* Draw rook with NO flashing. King will be drawn flashing later */
4320 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4321 lastBoard[rrow][rcol] = board[rrow][rcol];
4325 /* First pass -- Draw (newly) empty squares and repair damage.
4326 This prevents you from having a piece show up twice while it
4327 is flashing on its new square */
4328 for (i = 0; i < BOARD_HEIGHT; i++)
4329 for (j = 0; j < BOARD_WIDTH; j++)
4330 if ((board[i][j] != lastBoard[i][j] && board[i][j] == EmptySquare)
4332 DrawSquare(i, j, board[i][j], 0);
4333 damage[i][j] = False;
4336 /* Second pass -- Draw piece(s) in new position and flash them */
4337 for (i = 0; i < BOARD_HEIGHT; i++)
4338 for (j = 0; j < BOARD_WIDTH; j++)
4339 if (board[i][j] != lastBoard[i][j]) {
4340 DrawSquare(i, j, board[i][j], do_flash);
4344 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4345 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4347 for (i = 0; i < BOARD_HEIGHT; i++)
4348 for (j = 0; j < BOARD_WIDTH; j++) {
4349 DrawSquare(i, j, board[i][j], 0);
4350 damage[i][j] = False;
4354 CopyBoard(lastBoard, board);
4356 lastFlipView = flipView;
4358 /* Draw highlights */
4359 if (pm1X >= 0 && pm1Y >= 0) {
4360 drawHighlight(pm1X, pm1Y, prelineGC);
4362 if (pm2X >= 0 && pm2Y >= 0) {
4363 drawHighlight(pm2X, pm2Y, prelineGC);
4365 if (hi1X >= 0 && hi1Y >= 0) {
4366 drawHighlight(hi1X, hi1Y, highlineGC);
4368 if (hi2X >= 0 && hi2Y >= 0) {
4369 drawHighlight(hi2X, hi2Y, highlineGC);
4372 /* If piece being dragged around board, must redraw that too */
4375 XSync(xDisplay, False);
4380 * event handler for redrawing the board
4382 void DrawPositionProc(w, event, prms, nprms)
4388 XDrawPosition(w, True, NULL);
4393 * event handler for parsing user moves
4395 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4396 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4397 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4398 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4399 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4400 // and at the end FinishMove() to perform the move after optional promotion popups.
4401 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4402 void HandleUserMove(w, event, prms, nprms)
4408 if (w != boardWidget || errorExitStatus != -1) return;
4411 if (event->type == ButtonPress) {
4412 XtPopdown(promotionShell);
4413 XtDestroyWidget(promotionShell);
4414 promotionUp = False;
4422 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4423 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4424 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4427 void AnimateUserMove (Widget w, XEvent * event,
4428 String * params, Cardinal * nParams)
4430 DragPieceMove(event->xmotion.x, event->xmotion.y);
4433 Widget CommentCreate(name, text, mutable, callback, lines)
4435 int /*Boolean*/ mutable;
4436 XtCallbackProc callback;
4440 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4445 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4446 XtGetValues(boardWidget, args, j);
4449 XtSetArg(args[j], XtNresizable, True); j++;
4452 XtCreatePopupShell(name, topLevelShellWidgetClass,
4453 shellWidget, args, j);
4456 XtCreatePopupShell(name, transientShellWidgetClass,
4457 shellWidget, args, j);
4460 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4461 layoutArgs, XtNumber(layoutArgs));
4463 XtCreateManagedWidget("form", formWidgetClass, layout,
4464 formArgs, XtNumber(formArgs));
4468 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4469 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4471 XtSetArg(args[j], XtNstring, text); j++;
4472 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4473 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4474 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4475 XtSetArg(args[j], XtNright, XtChainRight); j++;
4476 XtSetArg(args[j], XtNresizable, True); j++;
4477 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4478 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4479 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4480 XtSetArg(args[j], XtNautoFill, True); j++;
4481 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4483 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4487 XtSetArg(args[j], XtNfromVert, edit); j++;
4488 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4489 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4490 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4491 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4493 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4494 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4497 XtSetArg(args[j], XtNfromVert, edit); j++;
4498 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4499 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4500 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4501 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4502 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4504 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4505 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4508 XtSetArg(args[j], XtNfromVert, edit); j++;
4509 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4510 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4511 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4512 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4513 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4515 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4516 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4519 XtSetArg(args[j], XtNfromVert, edit); j++;
4520 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4521 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4522 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4523 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4525 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4526 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4529 XtSetArg(args[j], XtNfromVert, edit); j++;
4530 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4531 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4532 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4533 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4534 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4536 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4537 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4540 XtRealizeWidget(shell);
4542 if (commentX == -1) {
4545 Dimension pw_height;
4546 Dimension ew_height;
4549 XtSetArg(args[j], XtNheight, &ew_height); j++;
4550 XtGetValues(edit, args, j);
4553 XtSetArg(args[j], XtNheight, &pw_height); j++;
4554 XtGetValues(shell, args, j);
4555 commentH = pw_height + (lines - 1) * ew_height;
4556 commentW = bw_width - 16;
4558 XSync(xDisplay, False);
4560 /* This code seems to tickle an X bug if it is executed too soon
4561 after xboard starts up. The coordinates get transformed as if
4562 the main window was positioned at (0, 0).
4564 XtTranslateCoords(shellWidget,
4565 (bw_width - commentW) / 2, 0 - commentH / 2,
4566 &commentX, &commentY);
4568 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4569 RootWindowOfScreen(XtScreen(shellWidget)),
4570 (bw_width - commentW) / 2, 0 - commentH / 2,
4575 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4578 if(wpComment.width > 0) {
4579 commentX = wpComment.x;
4580 commentY = wpComment.y;
4581 commentW = wpComment.width;
4582 commentH = wpComment.height;
4586 XtSetArg(args[j], XtNheight, commentH); j++;
4587 XtSetArg(args[j], XtNwidth, commentW); j++;
4588 XtSetArg(args[j], XtNx, commentX); j++;
4589 XtSetArg(args[j], XtNy, commentY); j++;
4590 XtSetValues(shell, args, j);
4591 XtSetKeyboardFocus(shell, edit);
4596 /* Used for analysis window and ICS input window */
4597 Widget MiscCreate(name, text, mutable, callback, lines)
4599 int /*Boolean*/ mutable;
4600 XtCallbackProc callback;
4604 Widget shell, layout, form, edit;
4606 Dimension bw_width, pw_height, ew_height, w, h;
4612 XtSetArg(args[j], XtNresizable, True); j++;
4615 XtCreatePopupShell(name, topLevelShellWidgetClass,
4616 shellWidget, args, j);
4619 XtCreatePopupShell(name, transientShellWidgetClass,
4620 shellWidget, args, j);
4623 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4624 layoutArgs, XtNumber(layoutArgs));
4626 XtCreateManagedWidget("form", formWidgetClass, layout,
4627 formArgs, XtNumber(formArgs));
4631 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4632 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4634 XtSetArg(args[j], XtNstring, text); j++;
4635 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4636 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4637 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4638 XtSetArg(args[j], XtNright, XtChainRight); j++;
4639 XtSetArg(args[j], XtNresizable, True); j++;
4640 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4641 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4642 XtSetArg(args[j], XtNautoFill, True); j++;
4643 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4645 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4647 XtRealizeWidget(shell);
4650 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4651 XtGetValues(boardWidget, args, j);
4654 XtSetArg(args[j], XtNheight, &ew_height); j++;
4655 XtGetValues(edit, args, j);
4658 XtSetArg(args[j], XtNheight, &pw_height); j++;
4659 XtGetValues(shell, args, j);
4660 h = pw_height + (lines - 1) * ew_height;
4663 XSync(xDisplay, False);
4665 /* This code seems to tickle an X bug if it is executed too soon
4666 after xboard starts up. The coordinates get transformed as if
4667 the main window was positioned at (0, 0).
4669 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4671 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4672 RootWindowOfScreen(XtScreen(shellWidget)),
4673 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4677 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4680 XtSetArg(args[j], XtNheight, h); j++;
4681 XtSetArg(args[j], XtNwidth, w); j++;
4682 XtSetArg(args[j], XtNx, x); j++;
4683 XtSetArg(args[j], XtNy, y); j++;
4684 XtSetValues(shell, args, j);
4690 static int savedIndex; /* gross that this is global */
4692 void EditCommentPopUp(index, title, text)
4701 if (text == NULL) text = "";
4703 if (editShell == NULL) {
4705 CommentCreate(title, text, True, EditCommentCallback, 4);
4706 XtRealizeWidget(editShell);
4707 CatchDeleteWindow(editShell, "EditCommentPopDown");
4709 edit = XtNameToWidget(editShell, "*form.text");
4711 XtSetArg(args[j], XtNstring, text); j++;
4712 XtSetValues(edit, args, j);
4714 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4715 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4716 XtSetValues(editShell, args, j);
4719 XtPopup(editShell, XtGrabNone);
4723 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4724 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4728 void EditCommentCallback(w, client_data, call_data)
4730 XtPointer client_data, call_data;
4738 XtSetArg(args[j], XtNlabel, &name); j++;
4739 XtGetValues(w, args, j);
4741 if (strcmp(name, _("ok")) == 0) {
4742 edit = XtNameToWidget(editShell, "*form.text");
4744 XtSetArg(args[j], XtNstring, &val); j++;
4745 XtGetValues(edit, args, j);
4746 ReplaceComment(savedIndex, val);
4747 EditCommentPopDown();
4748 } else if (strcmp(name, _("cancel")) == 0) {
4749 EditCommentPopDown();
4750 } else if (strcmp(name, _("clear")) == 0) {
4751 edit = XtNameToWidget(editShell, "*form.text");
4752 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4753 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4757 void EditCommentPopDown()
4762 if (!editUp) return;
4764 XtSetArg(args[j], XtNx, &commentX); j++;
4765 XtSetArg(args[j], XtNy, &commentY); j++;
4766 XtSetArg(args[j], XtNheight, &commentH); j++;
4767 XtSetArg(args[j], XtNwidth, &commentW); j++;
4768 XtGetValues(editShell, args, j);
4769 XtPopdown(editShell);
4772 XtSetArg(args[j], XtNleftBitmap, None); j++;
4773 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4777 void ICSInputBoxPopUp()
4782 char *title = _("ICS Input");
4785 if (ICSInputShell == NULL) {
4786 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
4787 tr = XtParseTranslationTable(ICSInputTranslations);
4788 edit = XtNameToWidget(ICSInputShell, "*form.text");
4789 XtOverrideTranslations(edit, tr);
4790 XtRealizeWidget(ICSInputShell);
4791 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
4794 edit = XtNameToWidget(ICSInputShell, "*form.text");
4796 XtSetArg(args[j], XtNstring, ""); j++;
4797 XtSetValues(edit, args, j);
4799 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4800 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4801 XtSetValues(ICSInputShell, args, j);
4804 XtPopup(ICSInputShell, XtGrabNone);
4805 XtSetKeyboardFocus(ICSInputShell, edit);
4807 ICSInputBoxUp = True;
4809 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4810 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4814 void ICSInputSendText()
4821 edit = XtNameToWidget(ICSInputShell, "*form.text");
4823 XtSetArg(args[j], XtNstring, &val); j++;
4824 XtGetValues(edit, args, j);
4825 SendMultiLineToICS(val);
4826 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4827 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4830 void ICSInputBoxPopDown()
4835 if (!ICSInputBoxUp) return;
4837 XtPopdown(ICSInputShell);
4838 ICSInputBoxUp = False;
4840 XtSetArg(args[j], XtNleftBitmap, None); j++;
4841 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4845 void CommentPopUp(title, text)
4852 if (commentShell == NULL) {
4854 CommentCreate(title, text, False, CommentCallback, 4);
4855 XtRealizeWidget(commentShell);
4856 CatchDeleteWindow(commentShell, "CommentPopDown");
4858 edit = XtNameToWidget(commentShell, "*form.text");
4860 XtSetArg(args[j], XtNstring, text); j++;
4861 XtSetValues(edit, args, j);
4863 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4864 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4865 XtSetValues(commentShell, args, j);
4868 XtPopup(commentShell, XtGrabNone);
4869 XSync(xDisplay, False);
4874 void CommentCallback(w, client_data, call_data)
4876 XtPointer client_data, call_data;
4883 XtSetArg(args[j], XtNlabel, &name); j++;
4884 XtGetValues(w, args, j);
4886 if (strcmp(name, _("close")) == 0) {
4888 } else if (strcmp(name, _("edit")) == 0) {
4895 void CommentPopDown()
4900 if (!commentUp) return;
4902 XtSetArg(args[j], XtNx, &commentX); j++;
4903 XtSetArg(args[j], XtNy, &commentY); j++;
4904 XtSetArg(args[j], XtNwidth, &commentW); j++;
4905 XtSetArg(args[j], XtNheight, &commentH); j++;
4906 XtGetValues(commentShell, args, j);
4907 XtPopdown(commentShell);
4908 XSync(xDisplay, False);
4912 void FileNamePopUp(label, def, proc, openMode)
4919 Widget popup, layout, dialog, edit;
4925 fileProc = proc; /* I can't see a way not */
4926 fileOpenMode = openMode; /* to use globals here */
4929 XtSetArg(args[i], XtNresizable, True); i++;
4930 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
4931 XtSetArg(args[i], XtNtitle, XtNewString(_("File name prompt"))); i++;
4932 fileNameShell = popup =
4933 XtCreatePopupShell("File name prompt", transientShellWidgetClass,
4934 shellWidget, args, i);
4937 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
4938 layoutArgs, XtNumber(layoutArgs));
4941 XtSetArg(args[i], XtNlabel, label); i++;
4942 XtSetArg(args[i], XtNvalue, def); i++;
4943 XtSetArg(args[i], XtNborderWidth, 0); i++;
4944 dialog = XtCreateManagedWidget("fileName", dialogWidgetClass,
4947 XawDialogAddButton(dialog, _("ok"), FileNameCallback, (XtPointer) dialog);
4948 XawDialogAddButton(dialog, _("cancel"), FileNameCallback,
4949 (XtPointer) dialog);
4951 XtRealizeWidget(popup);
4952 CatchDeleteWindow(popup, "FileNamePopDown");
4954 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
4955 &x, &y, &win_x, &win_y, &mask);
4957 XtSetArg(args[0], XtNx, x - 10);
4958 XtSetArg(args[1], XtNy, y - 30);
4959 XtSetValues(popup, args, 2);
4961 XtPopup(popup, XtGrabExclusive);
4964 edit = XtNameToWidget(dialog, "*value");
4965 XtSetKeyboardFocus(popup, edit);
4968 void FileNamePopDown()
4970 if (!filenameUp) return;
4971 XtPopdown(fileNameShell);
4972 XtDestroyWidget(fileNameShell);
4977 void FileNameCallback(w, client_data, call_data)
4979 XtPointer client_data, call_data;
4984 XtSetArg(args[0], XtNlabel, &name);
4985 XtGetValues(w, args, 1);
4987 if (strcmp(name, _("cancel")) == 0) {
4992 FileNameAction(w, NULL, NULL, NULL);
4995 void FileNameAction(w, event, prms, nprms)
5007 name = XawDialogGetValueString(w = XtParent(w));
5009 if ((name != NULL) && (*name != NULLCHAR)) {
5011 XtPopdown(w = XtParent(XtParent(w)));
5015 p = strrchr(buf, ' ');
5022 fullname = ExpandPathName(buf);
5024 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5027 f = fopen(fullname, fileOpenMode);
5029 DisplayError(_("Failed to open file"), errno);
5031 (void) (*fileProc)(f, index, buf);
5038 XtPopdown(w = XtParent(XtParent(w)));
5044 void PromotionPopUp()
5047 Widget dialog, layout;
5049 Dimension bw_width, pw_width;
5053 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5054 XtGetValues(boardWidget, args, j);
5057 XtSetArg(args[j], XtNresizable, True); j++;
5058 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5060 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5061 shellWidget, args, j);
5063 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5064 layoutArgs, XtNumber(layoutArgs));
5067 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5068 XtSetArg(args[j], XtNborderWidth, 0); j++;
5069 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5072 if(gameInfo.variant != VariantShogi) {
5073 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5074 (XtPointer) dialog);
5075 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5076 (XtPointer) dialog);
5077 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5078 (XtPointer) dialog);
5079 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5080 (XtPointer) dialog);
5081 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5082 gameInfo.variant == VariantGiveaway) {
5083 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5084 (XtPointer) dialog);
5086 if(gameInfo.variant == VariantCapablanca ||
5087 gameInfo.variant == VariantGothic ||
5088 gameInfo.variant == VariantCapaRandom) {
5089 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5090 (XtPointer) dialog);
5091 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5092 (XtPointer) dialog);
5094 } else // [HGM] shogi
5096 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5097 (XtPointer) dialog);
5098 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5099 (XtPointer) dialog);
5101 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5102 (XtPointer) dialog);
5104 XtRealizeWidget(promotionShell);
5105 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5108 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5109 XtGetValues(promotionShell, args, j);
5111 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5112 lineGap + squareSize/3 +
5113 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5114 0 : 6*(squareSize + lineGap)), &x, &y);
5117 XtSetArg(args[j], XtNx, x); j++;
5118 XtSetArg(args[j], XtNy, y); j++;
5119 XtSetValues(promotionShell, args, j);
5121 XtPopup(promotionShell, XtGrabNone);
5126 void PromotionPopDown()
5128 if (!promotionUp) return;
5129 XtPopdown(promotionShell);
5130 XtDestroyWidget(promotionShell);
5131 promotionUp = False;
5134 void PromotionCallback(w, client_data, call_data)
5136 XtPointer client_data, call_data;
5142 XtSetArg(args[0], XtNlabel, &name);
5143 XtGetValues(w, args, 1);
5147 if (fromX == -1) return;
5149 if (strcmp(name, _("cancel")) == 0) {
5153 } else if (strcmp(name, _("Knight")) == 0) {
5155 } else if (strcmp(name, _("Promote")) == 0) {
5157 } else if (strcmp(name, _("Defer")) == 0) {
5160 promoChar = ToLower(name[0]);
5163 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5165 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5166 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5171 void ErrorCallback(w, client_data, call_data)
5173 XtPointer client_data, call_data;
5176 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5178 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5184 if (!errorUp) return;
5186 XtPopdown(errorShell);
5187 XtDestroyWidget(errorShell);
5188 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5191 void ErrorPopUp(title, label, modal)
5192 char *title, *label;
5196 Widget dialog, layout;
5200 Dimension bw_width, pw_width;
5201 Dimension pw_height;
5205 XtSetArg(args[i], XtNresizable, True); i++;
5206 XtSetArg(args[i], XtNtitle, title); i++;
5208 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5209 shellWidget, args, i);
5211 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5212 layoutArgs, XtNumber(layoutArgs));
5215 XtSetArg(args[i], XtNlabel, label); i++;
5216 XtSetArg(args[i], XtNborderWidth, 0); i++;
5217 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5220 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5222 XtRealizeWidget(errorShell);
5223 CatchDeleteWindow(errorShell, "ErrorPopDown");
5226 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5227 XtGetValues(boardWidget, args, i);
5229 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5230 XtSetArg(args[i], XtNheight, &pw_height); i++;
5231 XtGetValues(errorShell, args, i);
5234 /* This code seems to tickle an X bug if it is executed too soon
5235 after xboard starts up. The coordinates get transformed as if
5236 the main window was positioned at (0, 0).
5238 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5239 0 - pw_height + squareSize / 3, &x, &y);
5241 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5242 RootWindowOfScreen(XtScreen(boardWidget)),
5243 (bw_width - pw_width) / 2,
5244 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5248 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5251 XtSetArg(args[i], XtNx, x); i++;
5252 XtSetArg(args[i], XtNy, y); i++;
5253 XtSetValues(errorShell, args, i);
5256 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5259 /* Disable all user input other than deleting the window */
5260 static int frozen = 0;
5264 /* Grab by a widget that doesn't accept input */
5265 XtAddGrab(messageWidget, TRUE, FALSE);
5269 /* Undo a FreezeUI */
5272 if (!frozen) return;
5273 XtRemoveGrab(messageWidget);
5277 char *ModeToWidgetName(mode)
5281 case BeginningOfGame:
5282 if (appData.icsActive)
5283 return "menuMode.ICS Client";
5284 else if (appData.noChessProgram ||
5285 *appData.cmailGameName != NULLCHAR)
5286 return "menuMode.Edit Game";
5288 return "menuMode.Machine Black";
5289 case MachinePlaysBlack:
5290 return "menuMode.Machine Black";
5291 case MachinePlaysWhite:
5292 return "menuMode.Machine White";
5294 return "menuMode.Analysis Mode";
5296 return "menuMode.Analyze File";
5297 case TwoMachinesPlay:
5298 return "menuMode.Two Machines";
5300 return "menuMode.Edit Game";
5301 case PlayFromGameFile:
5302 return "menuFile.Load Game";
5304 return "menuMode.Edit Position";
5306 return "menuMode.Training";
5307 case IcsPlayingWhite:
5308 case IcsPlayingBlack:
5312 return "menuMode.ICS Client";
5319 void ModeHighlight()
5322 static int oldPausing = FALSE;
5323 static GameMode oldmode = (GameMode) -1;
5326 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5328 if (pausing != oldPausing) {
5329 oldPausing = pausing;
5331 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5333 XtSetArg(args[0], XtNleftBitmap, None);
5335 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5338 if (appData.showButtonBar) {
5339 /* Always toggle, don't set. Previous code messes up when
5340 invoked while the button is pressed, as releasing it
5341 toggles the state again. */
5344 XtSetArg(args[0], XtNbackground, &oldbg);
5345 XtSetArg(args[1], XtNforeground, &oldfg);
5346 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5348 XtSetArg(args[0], XtNbackground, oldfg);
5349 XtSetArg(args[1], XtNforeground, oldbg);
5351 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5355 wname = ModeToWidgetName(oldmode);
5356 if (wname != NULL) {
5357 XtSetArg(args[0], XtNleftBitmap, None);
5358 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5360 wname = ModeToWidgetName(gameMode);
5361 if (wname != NULL) {
5362 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5363 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5367 /* Maybe all the enables should be handled here, not just this one */
5368 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5369 gameMode == Training || gameMode == PlayFromGameFile);
5374 * Button/menu procedures
5376 void ResetProc(w, event, prms, nprms)
5385 int LoadGamePopUp(f, gameNumber, title)
5390 cmailMsgLoaded = FALSE;
5391 if (gameNumber == 0) {
5392 int error = GameListBuild(f);
5394 DisplayError(_("Cannot build game list"), error);
5395 } else if (!ListEmpty(&gameList) &&
5396 ((ListGame *) gameList.tailPred)->number > 1) {
5397 GameListPopUp(f, title);
5403 return LoadGame(f, gameNumber, title, FALSE);
5406 void LoadGameProc(w, event, prms, nprms)
5412 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5415 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5418 void LoadNextGameProc(w, event, prms, nprms)
5427 void LoadPrevGameProc(w, event, prms, nprms)
5436 void ReloadGameProc(w, event, prms, nprms)
5445 void LoadNextPositionProc(w, event, prms, nprms)
5454 void LoadPrevPositionProc(w, event, prms, nprms)
5463 void ReloadPositionProc(w, event, prms, nprms)
5472 void LoadPositionProc(w, event, prms, nprms)
5478 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5481 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5484 void SaveGameProc(w, event, prms, nprms)
5490 FileNamePopUp(_("Save game file name?"),
5491 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5495 void SavePositionProc(w, event, prms, nprms)
5501 FileNamePopUp(_("Save position file name?"),
5502 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5506 void ReloadCmailMsgProc(w, event, prms, nprms)
5512 ReloadCmailMsgEvent(FALSE);
5515 void MailMoveProc(w, event, prms, nprms)
5524 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5525 char *selected_fen_position=NULL;
5528 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5529 Atom *type_return, XtPointer *value_return,
5530 unsigned long *length_return, int *format_return)
5532 char *selection_tmp;
5534 if (!selected_fen_position) return False; /* should never happen */
5535 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5536 /* note: since no XtSelectionDoneProc was registered, Xt will
5537 * automatically call XtFree on the value returned. So have to
5538 * make a copy of it allocated with XtMalloc */
5539 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5540 strcpy(selection_tmp, selected_fen_position);
5542 *value_return=selection_tmp;
5543 *length_return=strlen(selection_tmp);
5544 *type_return=*target;
5545 *format_return = 8; /* bits per byte */
5547 } else if (*target == XA_TARGETS(xDisplay)) {
5548 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5549 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5550 targets_tmp[1] = XA_STRING;
5551 *value_return = targets_tmp;
5552 *type_return = XA_ATOM;
5554 *format_return = 8 * sizeof(Atom);
5555 if (*format_return > 32) {
5556 *length_return *= *format_return / 32;
5557 *format_return = 32;
5565 /* note: when called from menu all parameters are NULL, so no clue what the
5566 * Widget which was clicked on was, or what the click event was
5568 void CopyPositionProc(w, event, prms, nprms)
5575 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5576 * have a notion of a position that is selected but not copied.
5577 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5579 if(gameMode == EditPosition) EditPositionDone(TRUE);
5580 if (selected_fen_position) free(selected_fen_position);
5581 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5582 if (!selected_fen_position) return;
5583 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5585 SendPositionSelection,
5586 NULL/* lose_ownership_proc */ ,
5587 NULL/* transfer_done_proc */);
5588 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5590 SendPositionSelection,
5591 NULL/* lose_ownership_proc */ ,
5592 NULL/* transfer_done_proc */);
5595 /* function called when the data to Paste is ready */
5597 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5598 Atom *type, XtPointer value, unsigned long *len, int *format)
5601 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5602 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5603 EditPositionPasteFEN(fenstr);
5607 /* called when Paste Position button is pressed,
5608 * all parameters will be NULL */
5609 void PastePositionProc(w, event, prms, nprms)
5615 XtGetSelectionValue(menuBarWidget,
5616 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5617 /* (XtSelectionCallbackProc) */ PastePositionCB,
5618 NULL, /* client_data passed to PastePositionCB */
5620 /* better to use the time field from the event that triggered the
5621 * call to this function, but that isn't trivial to get
5629 SendGameSelection(Widget w, Atom *selection, Atom *target,
5630 Atom *type_return, XtPointer *value_return,
5631 unsigned long *length_return, int *format_return)
5633 char *selection_tmp;
5635 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5636 FILE* f = fopen(gameCopyFilename, "r");
5639 if (f == NULL) return False;
5643 selection_tmp = XtMalloc(len + 1);
5644 count = fread(selection_tmp, 1, len, f);
5646 XtFree(selection_tmp);
5649 selection_tmp[len] = NULLCHAR;
5650 *value_return = selection_tmp;
5651 *length_return = len;
5652 *type_return = *target;
5653 *format_return = 8; /* bits per byte */
5655 } else if (*target == XA_TARGETS(xDisplay)) {
5656 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5657 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5658 targets_tmp[1] = XA_STRING;
5659 *value_return = targets_tmp;
5660 *type_return = XA_ATOM;
5662 *format_return = 8 * sizeof(Atom);
5663 if (*format_return > 32) {
5664 *length_return *= *format_return / 32;
5665 *format_return = 32;
5673 /* note: when called from menu all parameters are NULL, so no clue what the
5674 * Widget which was clicked on was, or what the click event was
5676 void CopyGameProc(w, event, prms, nprms)
5684 ret = SaveGameToFile(gameCopyFilename, FALSE);
5688 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5689 * have a notion of a game that is selected but not copied.
5690 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5692 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5695 NULL/* lose_ownership_proc */ ,
5696 NULL/* transfer_done_proc */);
5697 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5700 NULL/* lose_ownership_proc */ ,
5701 NULL/* transfer_done_proc */);
5704 /* function called when the data to Paste is ready */
5706 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5707 Atom *type, XtPointer value, unsigned long *len, int *format)
5710 if (value == NULL || *len == 0) {
5711 return; /* nothing had been selected to copy */
5713 f = fopen(gamePasteFilename, "w");
5715 DisplayError(_("Can't open temp file"), errno);
5718 fwrite(value, 1, *len, f);
5721 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5724 /* called when Paste Game button is pressed,
5725 * all parameters will be NULL */
5726 void PasteGameProc(w, event, prms, nprms)
5732 XtGetSelectionValue(menuBarWidget,
5733 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5734 /* (XtSelectionCallbackProc) */ PasteGameCB,
5735 NULL, /* client_data passed to PasteGameCB */
5737 /* better to use the time field from the event that triggered the
5738 * call to this function, but that isn't trivial to get
5748 SaveGameProc(NULL, NULL, NULL, NULL);
5752 void QuitProc(w, event, prms, nprms)
5761 void PauseProc(w, event, prms, nprms)
5771 void MachineBlackProc(w, event, prms, nprms)
5777 MachineBlackEvent();
5780 void MachineWhiteProc(w, event, prms, nprms)
5786 MachineWhiteEvent();
5789 void AnalyzeModeProc(w, event, prms, nprms)
5797 if (!first.analysisSupport) {
5798 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5799 DisplayError(buf, 0);
5802 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5803 if (appData.icsActive) {
5804 if (gameMode != IcsObserving) {
5805 sprintf(buf,_("You are not observing a game"));
5806 DisplayError(buf, 0);
5808 if (appData.icsEngineAnalyze) {
5809 if (appData.debugMode)
5810 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5816 /* if enable, use want disable icsEngineAnalyze */
5817 if (appData.icsEngineAnalyze) {
5822 appData.icsEngineAnalyze = TRUE;
5823 if (appData.debugMode)
5824 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5826 if (!appData.showThinking)
5827 ShowThinkingProc(w,event,prms,nprms);
5832 void AnalyzeFileProc(w, event, prms, nprms)
5838 if (!first.analysisSupport) {
5840 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5841 DisplayError(buf, 0);
5846 if (!appData.showThinking)
5847 ShowThinkingProc(w,event,prms,nprms);
5850 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
5851 AnalysisPeriodicEvent(1);
5854 void TwoMachinesProc(w, event, prms, nprms)
5863 void IcsClientProc(w, event, prms, nprms)
5872 void EditGameProc(w, event, prms, nprms)
5881 void EditPositionProc(w, event, prms, nprms)
5887 EditPositionEvent();
5890 void TrainingProc(w, event, prms, nprms)
5899 void EditCommentProc(w, event, prms, nprms)
5906 EditCommentPopDown();
5912 void IcsInputBoxProc(w, event, prms, nprms)
5918 if (ICSInputBoxUp) {
5919 ICSInputBoxPopDown();
5925 void AcceptProc(w, event, prms, nprms)
5934 void DeclineProc(w, event, prms, nprms)
5943 void RematchProc(w, event, prms, nprms)
5952 void CallFlagProc(w, event, prms, nprms)
5961 void DrawProc(w, event, prms, nprms)
5970 void AbortProc(w, event, prms, nprms)
5979 void AdjournProc(w, event, prms, nprms)
5988 void ResignProc(w, event, prms, nprms)
5997 void AdjuWhiteProc(w, event, prms, nprms)
6003 UserAdjudicationEvent(+1);
6006 void AdjuBlackProc(w, event, prms, nprms)
6012 UserAdjudicationEvent(-1);
6015 void AdjuDrawProc(w, event, prms, nprms)
6021 UserAdjudicationEvent(0);
6024 void EnterKeyProc(w, event, prms, nprms)
6030 if (ICSInputBoxUp == True)
6034 void StopObservingProc(w, event, prms, nprms)
6040 StopObservingEvent();
6043 void StopExaminingProc(w, event, prms, nprms)
6049 StopExaminingEvent();
6053 void ForwardProc(w, event, prms, nprms)
6063 void BackwardProc(w, event, prms, nprms)
6072 void ToStartProc(w, event, prms, nprms)
6081 void ToEndProc(w, event, prms, nprms)
6090 void RevertProc(w, event, prms, nprms)
6099 void TruncateGameProc(w, event, prms, nprms)
6105 TruncateGameEvent();
6107 void RetractMoveProc(w, event, prms, nprms)
6116 void MoveNowProc(w, event, prms, nprms)
6126 void AlwaysQueenProc(w, event, prms, nprms)
6134 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6136 if (appData.alwaysPromoteToQueen) {
6137 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6139 XtSetArg(args[0], XtNleftBitmap, None);
6141 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6145 void AnimateDraggingProc(w, event, prms, nprms)
6153 appData.animateDragging = !appData.animateDragging;
6155 if (appData.animateDragging) {
6156 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6159 XtSetArg(args[0], XtNleftBitmap, None);
6161 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6165 void AnimateMovingProc(w, event, prms, nprms)
6173 appData.animate = !appData.animate;
6175 if (appData.animate) {
6176 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6179 XtSetArg(args[0], XtNleftBitmap, None);
6181 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6185 void AutocommProc(w, event, prms, nprms)
6193 appData.autoComment = !appData.autoComment;
6195 if (appData.autoComment) {
6196 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6198 XtSetArg(args[0], XtNleftBitmap, None);
6200 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6205 void AutoflagProc(w, event, prms, nprms)
6213 appData.autoCallFlag = !appData.autoCallFlag;
6215 if (appData.autoCallFlag) {
6216 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6218 XtSetArg(args[0], XtNleftBitmap, None);
6220 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6224 void AutoflipProc(w, event, prms, nprms)
6232 appData.autoFlipView = !appData.autoFlipView;
6234 if (appData.autoFlipView) {
6235 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6237 XtSetArg(args[0], XtNleftBitmap, None);
6239 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6243 void AutobsProc(w, event, prms, nprms)
6251 appData.autoObserve = !appData.autoObserve;
6253 if (appData.autoObserve) {
6254 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6256 XtSetArg(args[0], XtNleftBitmap, None);
6258 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6262 void AutoraiseProc(w, event, prms, nprms)
6270 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6272 if (appData.autoRaiseBoard) {
6273 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6275 XtSetArg(args[0], XtNleftBitmap, None);
6277 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6281 void AutosaveProc(w, event, prms, nprms)
6289 appData.autoSaveGames = !appData.autoSaveGames;
6291 if (appData.autoSaveGames) {
6292 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6294 XtSetArg(args[0], XtNleftBitmap, None);
6296 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6300 void BlindfoldProc(w, event, prms, nprms)
6308 appData.blindfold = !appData.blindfold;
6310 if (appData.blindfold) {
6311 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6313 XtSetArg(args[0], XtNleftBitmap, None);
6315 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6318 DrawPosition(True, NULL);
6321 void TestLegalityProc(w, event, prms, nprms)
6329 appData.testLegality = !appData.testLegality;
6331 if (appData.testLegality) {
6332 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6334 XtSetArg(args[0], XtNleftBitmap, None);
6336 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6341 void FlashMovesProc(w, event, prms, nprms)
6349 if (appData.flashCount == 0) {
6350 appData.flashCount = 3;
6352 appData.flashCount = -appData.flashCount;
6355 if (appData.flashCount > 0) {
6356 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6358 XtSetArg(args[0], XtNleftBitmap, None);
6360 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6364 void FlipViewProc(w, event, prms, nprms)
6370 flipView = !flipView;
6371 DrawPosition(True, NULL);
6374 void GetMoveListProc(w, event, prms, nprms)
6382 appData.getMoveList = !appData.getMoveList;
6384 if (appData.getMoveList) {
6385 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6388 XtSetArg(args[0], XtNleftBitmap, None);
6390 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6395 void HighlightDraggingProc(w, event, prms, nprms)
6403 appData.highlightDragging = !appData.highlightDragging;
6405 if (appData.highlightDragging) {
6406 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6408 XtSetArg(args[0], XtNleftBitmap, None);
6410 XtSetValues(XtNameToWidget(menuBarWidget,
6411 "menuOptions.Highlight Dragging"), args, 1);
6415 void HighlightLastMoveProc(w, event, prms, nprms)
6423 appData.highlightLastMove = !appData.highlightLastMove;
6425 if (appData.highlightLastMove) {
6426 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6428 XtSetArg(args[0], XtNleftBitmap, None);
6430 XtSetValues(XtNameToWidget(menuBarWidget,
6431 "menuOptions.Highlight Last Move"), args, 1);
6434 void IcsAlarmProc(w, event, prms, nprms)
6442 appData.icsAlarm = !appData.icsAlarm;
6444 if (appData.icsAlarm) {
6445 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6447 XtSetArg(args[0], XtNleftBitmap, None);
6449 XtSetValues(XtNameToWidget(menuBarWidget,
6450 "menuOptions.ICS Alarm"), args, 1);
6453 void MoveSoundProc(w, event, prms, nprms)
6461 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6463 if (appData.ringBellAfterMoves) {
6464 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6466 XtSetArg(args[0], XtNleftBitmap, None);
6468 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6473 void OldSaveStyleProc(w, event, prms, nprms)
6481 appData.oldSaveStyle = !appData.oldSaveStyle;
6483 if (appData.oldSaveStyle) {
6484 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6486 XtSetArg(args[0], XtNleftBitmap, None);
6488 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6492 void PeriodicUpdatesProc(w, event, prms, nprms)
6500 PeriodicUpdatesEvent(!appData.periodicUpdates);
6502 if (appData.periodicUpdates) {
6503 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6505 XtSetArg(args[0], XtNleftBitmap, None);
6507 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6511 void PonderNextMoveProc(w, event, prms, nprms)
6519 PonderNextMoveEvent(!appData.ponderNextMove);
6521 if (appData.ponderNextMove) {
6522 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6524 XtSetArg(args[0], XtNleftBitmap, None);
6526 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6530 void PopupExitMessageProc(w, event, prms, nprms)
6538 appData.popupExitMessage = !appData.popupExitMessage;
6540 if (appData.popupExitMessage) {
6541 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6543 XtSetArg(args[0], XtNleftBitmap, None);
6545 XtSetValues(XtNameToWidget(menuBarWidget,
6546 "menuOptions.Popup Exit Message"), args, 1);
6549 void PopupMoveErrorsProc(w, event, prms, nprms)
6557 appData.popupMoveErrors = !appData.popupMoveErrors;
6559 if (appData.popupMoveErrors) {
6560 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6562 XtSetArg(args[0], XtNleftBitmap, None);
6564 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6568 void PremoveProc(w, event, prms, nprms)
6576 appData.premove = !appData.premove;
6578 if (appData.premove) {
6579 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6581 XtSetArg(args[0], XtNleftBitmap, None);
6583 XtSetValues(XtNameToWidget(menuBarWidget,
6584 "menuOptions.Premove"), args, 1);
6587 void QuietPlayProc(w, event, prms, nprms)
6595 appData.quietPlay = !appData.quietPlay;
6597 if (appData.quietPlay) {
6598 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6600 XtSetArg(args[0], XtNleftBitmap, None);
6602 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6606 void ShowCoordsProc(w, event, prms, nprms)
6614 appData.showCoords = !appData.showCoords;
6616 if (appData.showCoords) {
6617 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6619 XtSetArg(args[0], XtNleftBitmap, None);
6621 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6624 DrawPosition(True, NULL);
6627 void ShowThinkingProc(w, event, prms, nprms)
6633 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6634 ShowThinkingEvent();
6637 void HideThinkingProc(w, event, prms, nprms)
6645 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6646 ShowThinkingEvent();
6648 if (appData.hideThinkingFromHuman) {
6649 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6651 XtSetArg(args[0], XtNleftBitmap, None);
6653 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6657 void SaveOnExitProc(w, event, prms, nprms)
6665 saveSettingsOnExit = !saveSettingsOnExit;
6667 if (saveSettingsOnExit) {
6668 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6670 XtSetArg(args[0], XtNleftBitmap, None);
6672 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6676 void SaveSettingsProc(w, event, prms, nprms)
6682 SaveSettings(settingsFileName);
6685 void InfoProc(w, event, prms, nprms)
6692 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6697 void ManProc(w, event, prms, nprms)
6705 if (nprms && *nprms > 0)
6709 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6713 void HintProc(w, event, prms, nprms)
6722 void BookProc(w, event, prms, nprms)
6731 void AboutProc(w, event, prms, nprms)
6739 char *zippy = " (with Zippy code)";
6743 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6744 programVersion, zippy,
6745 "Copyright 1991 Digital Equipment Corporation",
6746 "Enhancements Copyright 1992-2009 Free Software Foundation",
6747 "Enhancements Copyright 2005 Alessandro Scotti",
6748 PACKAGE, " is free software and carries NO WARRANTY;",
6749 "see the file COPYING for more information.");
6750 ErrorPopUp(_("About XBoard"), buf, FALSE);
6753 void DebugProc(w, event, prms, nprms)
6759 appData.debugMode = !appData.debugMode;
6762 void AboutGameProc(w, event, prms, nprms)
6771 void NothingProc(w, event, prms, nprms)
6780 void Iconify(w, event, prms, nprms)
6789 XtSetArg(args[0], XtNiconic, True);
6790 XtSetValues(shellWidget, args, 1);
6793 void DisplayMessage(message, extMessage)
6794 char *message, *extMessage;
6796 /* display a message in the message widget */
6805 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
6810 message = extMessage;
6814 /* need to test if messageWidget already exists, since this function
6815 can also be called during the startup, if for example a Xresource
6816 is not set up correctly */
6819 XtSetArg(arg, XtNlabel, message);
6820 XtSetValues(messageWidget, &arg, 1);
6826 void DisplayTitle(text)
6831 char title[MSG_SIZ];
6834 if (text == NULL) text = "";
6836 if (appData.titleInWindow) {
6838 XtSetArg(args[i], XtNlabel, text); i++;
6839 XtSetValues(titleWidget, args, i);
6842 if (*text != NULLCHAR) {
6844 strcpy(title, text);
6845 } else if (appData.icsActive) {
6846 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
6847 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
6848 } else if (appData.cmailGameName[0] != NULLCHAR) {
6849 snprintf(icon, sizeof(icon), "%s", "CMail");
6850 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
6852 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
6853 } else if (gameInfo.variant == VariantGothic) {
6854 strcpy(icon, programName);
6855 strcpy(title, GOTHIC);
6858 } else if (gameInfo.variant == VariantFalcon) {
6859 strcpy(icon, programName);
6860 strcpy(title, FALCON);
6862 } else if (appData.noChessProgram) {
6863 strcpy(icon, programName);
6864 strcpy(title, programName);
6866 strcpy(icon, first.tidy);
6867 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
6870 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
6871 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
6872 XtSetValues(shellWidget, args, i);
6876 void DisplayError(message, error)
6883 if (appData.debugMode || appData.matchMode) {
6884 fprintf(stderr, "%s: %s\n", programName, message);
6887 if (appData.debugMode || appData.matchMode) {
6888 fprintf(stderr, "%s: %s: %s\n",
6889 programName, message, strerror(error));
6891 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6894 ErrorPopUp(_("Error"), message, FALSE);
6898 void DisplayMoveError(message)
6903 DrawPosition(FALSE, NULL);
6904 if (appData.debugMode || appData.matchMode) {
6905 fprintf(stderr, "%s: %s\n", programName, message);
6907 if (appData.popupMoveErrors) {
6908 ErrorPopUp(_("Error"), message, FALSE);
6910 DisplayMessage(message, "");
6915 void DisplayFatalError(message, error, status)
6921 errorExitStatus = status;
6923 fprintf(stderr, "%s: %s\n", programName, message);
6925 fprintf(stderr, "%s: %s: %s\n",
6926 programName, message, strerror(error));
6927 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6930 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
6931 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
6937 void DisplayInformation(message)
6941 ErrorPopUp(_("Information"), message, TRUE);
6944 void DisplayNote(message)
6948 ErrorPopUp(_("Note"), message, FALSE);
6952 NullXErrorCheck(dpy, error_event)
6954 XErrorEvent *error_event;
6959 void DisplayIcsInteractionTitle(message)
6962 if (oldICSInteractionTitle == NULL) {
6963 /* Magic to find the old window title, adapted from vim */
6964 char *wina = getenv("WINDOWID");
6966 Window win = (Window) atoi(wina);
6967 Window root, parent, *children;
6968 unsigned int nchildren;
6969 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
6971 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
6972 if (!XQueryTree(xDisplay, win, &root, &parent,
6973 &children, &nchildren)) break;
6974 if (children) XFree((void *)children);
6975 if (parent == root || parent == 0) break;
6978 XSetErrorHandler(oldHandler);
6980 if (oldICSInteractionTitle == NULL) {
6981 oldICSInteractionTitle = "xterm";
6984 printf("\033]0;%s\007", message);
6988 char pendingReplyPrefix[MSG_SIZ];
6989 ProcRef pendingReplyPR;
6991 void AskQuestionProc(w, event, prms, nprms)
6998 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7002 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7005 void AskQuestionPopDown()
7007 if (!askQuestionUp) return;
7008 XtPopdown(askQuestionShell);
7009 XtDestroyWidget(askQuestionShell);
7010 askQuestionUp = False;
7013 void AskQuestionReplyAction(w, event, prms, nprms)
7023 reply = XawDialogGetValueString(w = XtParent(w));
7024 strcpy(buf, pendingReplyPrefix);
7025 if (*buf) strcat(buf, " ");
7028 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7029 AskQuestionPopDown();
7031 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7034 void AskQuestionCallback(w, client_data, call_data)
7036 XtPointer client_data, call_data;
7041 XtSetArg(args[0], XtNlabel, &name);
7042 XtGetValues(w, args, 1);
7044 if (strcmp(name, _("cancel")) == 0) {
7045 AskQuestionPopDown();
7047 AskQuestionReplyAction(w, NULL, NULL, NULL);
7051 void AskQuestion(title, question, replyPrefix, pr)
7052 char *title, *question, *replyPrefix;
7056 Widget popup, layout, dialog, edit;
7062 strcpy(pendingReplyPrefix, replyPrefix);
7063 pendingReplyPR = pr;
7066 XtSetArg(args[i], XtNresizable, True); i++;
7067 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7068 askQuestionShell = popup =
7069 XtCreatePopupShell(title, transientShellWidgetClass,
7070 shellWidget, args, i);
7073 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7074 layoutArgs, XtNumber(layoutArgs));
7077 XtSetArg(args[i], XtNlabel, question); i++;
7078 XtSetArg(args[i], XtNvalue, ""); i++;
7079 XtSetArg(args[i], XtNborderWidth, 0); i++;
7080 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7083 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7084 (XtPointer) dialog);
7085 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7086 (XtPointer) dialog);
7088 XtRealizeWidget(popup);
7089 CatchDeleteWindow(popup, "AskQuestionPopDown");
7091 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7092 &x, &y, &win_x, &win_y, &mask);
7094 XtSetArg(args[0], XtNx, x - 10);
7095 XtSetArg(args[1], XtNy, y - 30);
7096 XtSetValues(popup, args, 2);
7098 XtPopup(popup, XtGrabExclusive);
7099 askQuestionUp = True;
7101 edit = XtNameToWidget(dialog, "*value");
7102 XtSetKeyboardFocus(popup, edit);
7110 if (*name == NULLCHAR) {
7112 } else if (strcmp(name, "$") == 0) {
7113 putc(BELLCHAR, stderr);
7116 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7124 PlaySound(appData.soundMove);
7130 PlaySound(appData.soundIcsWin);
7136 PlaySound(appData.soundIcsLoss);
7142 PlaySound(appData.soundIcsDraw);
7146 PlayIcsUnfinishedSound()
7148 PlaySound(appData.soundIcsUnfinished);
7154 PlaySound(appData.soundIcsAlarm);
7160 system("stty echo");
7166 system("stty -echo");
7170 Colorize(cc, continuation)
7175 int count, outCount, error;
7177 if (textColors[(int)cc].bg > 0) {
7178 if (textColors[(int)cc].fg > 0) {
7179 sprintf(buf, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7180 textColors[(int)cc].fg, textColors[(int)cc].bg);
7182 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7183 textColors[(int)cc].bg);
7186 if (textColors[(int)cc].fg > 0) {
7187 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7188 textColors[(int)cc].fg);
7190 sprintf(buf, "\033[0;%dm", textColors[(int)cc].attr);
7193 count = strlen(buf);
7194 outCount = OutputToProcess(NoProc, buf, count, &error);
7195 if (outCount < count) {
7196 DisplayFatalError(_("Error writing to display"), error, 1);
7199 if (continuation) return;
7202 PlaySound(appData.soundShout);
7205 PlaySound(appData.soundSShout);
7208 PlaySound(appData.soundChannel1);
7211 PlaySound(appData.soundChannel);
7214 PlaySound(appData.soundKibitz);
7217 PlaySound(appData.soundTell);
7219 case ColorChallenge:
7220 PlaySound(appData.soundChallenge);
7223 PlaySound(appData.soundRequest);
7226 PlaySound(appData.soundSeek);
7237 return getpwuid(getuid())->pw_name;
7240 static char *ExpandPathName(path)
7243 static char static_buf[2000];
7244 char *d, *s, buf[2000];
7250 while (*s && isspace(*s))
7259 if (*(s+1) == '/') {
7260 strcpy(d, getpwuid(getuid())->pw_dir);
7265 *strchr(buf, '/') = 0;
7266 pwd = getpwnam(buf);
7269 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7273 strcpy(d, pwd->pw_dir);
7274 strcat(d, strchr(s+1, '/'));
7285 static char host_name[MSG_SIZ];
7287 #if HAVE_GETHOSTNAME
7288 gethostname(host_name, MSG_SIZ);
7290 #else /* not HAVE_GETHOSTNAME */
7291 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7292 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7294 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7296 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7297 #endif /* not HAVE_GETHOSTNAME */
7300 XtIntervalId delayedEventTimerXID = 0;
7301 DelayedEventCallback delayedEventCallback = 0;
7306 delayedEventTimerXID = 0;
7307 delayedEventCallback();
7311 ScheduleDelayedEvent(cb, millisec)
7312 DelayedEventCallback cb; long millisec;
7314 if(delayedEventTimerXID && delayedEventCallback == cb)
7315 // [HGM] alive: replace, rather than add or flush identical event
7316 XtRemoveTimeOut(delayedEventTimerXID);
7317 delayedEventCallback = cb;
7318 delayedEventTimerXID =
7319 XtAppAddTimeOut(appContext, millisec,
7320 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7323 DelayedEventCallback
7326 if (delayedEventTimerXID) {
7327 return delayedEventCallback;
7334 CancelDelayedEvent()
7336 if (delayedEventTimerXID) {
7337 XtRemoveTimeOut(delayedEventTimerXID);
7338 delayedEventTimerXID = 0;
7342 XtIntervalId loadGameTimerXID = 0;
7344 int LoadGameTimerRunning()
7346 return loadGameTimerXID != 0;
7349 int StopLoadGameTimer()
7351 if (loadGameTimerXID != 0) {
7352 XtRemoveTimeOut(loadGameTimerXID);
7353 loadGameTimerXID = 0;
7361 LoadGameTimerCallback(arg, id)
7365 loadGameTimerXID = 0;
7370 StartLoadGameTimer(millisec)
7374 XtAppAddTimeOut(appContext, millisec,
7375 (XtTimerCallbackProc) LoadGameTimerCallback,
7379 XtIntervalId analysisClockXID = 0;
7382 AnalysisClockCallback(arg, id)
7386 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7387 || appData.icsEngineAnalyze) { // [DM]
7388 AnalysisPeriodicEvent(0);
7389 StartAnalysisClock();
7394 StartAnalysisClock()
7397 XtAppAddTimeOut(appContext, 2000,
7398 (XtTimerCallbackProc) AnalysisClockCallback,
7402 XtIntervalId clockTimerXID = 0;
7404 int ClockTimerRunning()
7406 return clockTimerXID != 0;
7409 int StopClockTimer()
7411 if (clockTimerXID != 0) {
7412 XtRemoveTimeOut(clockTimerXID);
7421 ClockTimerCallback(arg, id)
7430 StartClockTimer(millisec)
7434 XtAppAddTimeOut(appContext, millisec,
7435 (XtTimerCallbackProc) ClockTimerCallback,
7440 DisplayTimerLabel(w, color, timer, highlight)
7449 /* check for low time warning */
7450 Pixel foregroundOrWarningColor = timerForegroundPixel;
7453 appData.lowTimeWarning &&
7454 (timer / 1000) < appData.icsAlarmTime)
7455 foregroundOrWarningColor = lowTimeWarningColor;
7457 if (appData.clockMode) {
7458 sprintf(buf, "%s: %s", color, TimeString(timer));
7459 XtSetArg(args[0], XtNlabel, buf);
7461 sprintf(buf, "%s ", color);
7462 XtSetArg(args[0], XtNlabel, buf);
7467 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7468 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7470 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7471 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7474 XtSetValues(w, args, 3);
7478 DisplayWhiteClock(timeRemaining, highlight)
7484 if(appData.noGUI) return;
7485 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7486 if (highlight && iconPixmap == bIconPixmap) {
7487 iconPixmap = wIconPixmap;
7488 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7489 XtSetValues(shellWidget, args, 1);
7494 DisplayBlackClock(timeRemaining, highlight)
7500 if(appData.noGUI) return;
7501 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7502 if (highlight && iconPixmap == wIconPixmap) {
7503 iconPixmap = bIconPixmap;
7504 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7505 XtSetValues(shellWidget, args, 1);
7523 int StartChildProcess(cmdLine, dir, pr)
7530 int to_prog[2], from_prog[2];
7534 if (appData.debugMode) {
7535 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7538 /* We do NOT feed the cmdLine to the shell; we just
7539 parse it into blank-separated arguments in the
7540 most simple-minded way possible.
7543 strcpy(buf, cmdLine);
7546 while(*p == ' ') p++;
7548 if(*p == '"' || *p == '\'')
7549 p = strchr(++argv[i-1], *p);
7550 else p = strchr(p, ' ');
7551 if (p == NULL) break;
7556 SetUpChildIO(to_prog, from_prog);
7558 if ((pid = fork()) == 0) {
7560 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7561 close(to_prog[1]); // first close the unused pipe ends
7562 close(from_prog[0]);
7563 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7564 dup2(from_prog[1], 1);
7565 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7566 close(from_prog[1]); // and closing again loses one of the pipes!
7567 if(fileno(stderr) >= 2) // better safe than sorry...
7568 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7570 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7575 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7577 execvp(argv[0], argv);
7579 /* If we get here, exec failed */
7584 /* Parent process */
7586 close(from_prog[1]);
7588 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7591 cp->fdFrom = from_prog[0];
7592 cp->fdTo = to_prog[1];
7597 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7598 static RETSIGTYPE AlarmCallBack(int n)
7604 DestroyChildProcess(pr, signalType)
7608 ChildProc *cp = (ChildProc *) pr;
7610 if (cp->kind != CPReal) return;
7612 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7613 signal(SIGALRM, AlarmCallBack);
7615 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7616 kill(cp->pid, SIGKILL); // kill it forcefully
7617 wait((int *) 0); // and wait again
7621 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7623 /* Process is exiting either because of the kill or because of
7624 a quit command sent by the backend; either way, wait for it to die.
7633 InterruptChildProcess(pr)
7636 ChildProc *cp = (ChildProc *) pr;
7638 if (cp->kind != CPReal) return;
7639 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7642 int OpenTelnet(host, port, pr)
7647 char cmdLine[MSG_SIZ];
7649 if (port[0] == NULLCHAR) {
7650 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7652 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7654 return StartChildProcess(cmdLine, "", pr);
7657 int OpenTCP(host, port, pr)
7663 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7664 #else /* !OMIT_SOCKETS */
7666 struct sockaddr_in sa;
7668 unsigned short uport;
7671 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7675 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7676 sa.sin_family = AF_INET;
7677 sa.sin_addr.s_addr = INADDR_ANY;
7678 uport = (unsigned short) 0;
7679 sa.sin_port = htons(uport);
7680 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7684 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7685 if (!(hp = gethostbyname(host))) {
7687 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7688 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7689 hp->h_addrtype = AF_INET;
7691 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7692 hp->h_addr_list[0] = (char *) malloc(4);
7693 hp->h_addr_list[0][0] = b0;
7694 hp->h_addr_list[0][1] = b1;
7695 hp->h_addr_list[0][2] = b2;
7696 hp->h_addr_list[0][3] = b3;
7701 sa.sin_family = hp->h_addrtype;
7702 uport = (unsigned short) atoi(port);
7703 sa.sin_port = htons(uport);
7704 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7706 if (connect(s, (struct sockaddr *) &sa,
7707 sizeof(struct sockaddr_in)) < 0) {
7711 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7718 #endif /* !OMIT_SOCKETS */
7723 int OpenCommPort(name, pr)
7730 fd = open(name, 2, 0);
7731 if (fd < 0) return errno;
7733 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7743 int OpenLoopback(pr)
7749 SetUpChildIO(to, from);
7751 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7754 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7761 int OpenRcmd(host, user, cmd, pr)
7762 char *host, *user, *cmd;
7765 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7769 #define INPUT_SOURCE_BUF_SIZE 8192
7778 char buf[INPUT_SOURCE_BUF_SIZE];
7783 DoInputCallback(closure, source, xid)
7788 InputSource *is = (InputSource *) closure;
7793 if (is->lineByLine) {
7794 count = read(is->fd, is->unused,
7795 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7797 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7800 is->unused += count;
7802 while (p < is->unused) {
7803 q = memchr(p, '\n', is->unused - p);
7804 if (q == NULL) break;
7806 (is->func)(is, is->closure, p, q - p, 0);
7810 while (p < is->unused) {
7815 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
7820 (is->func)(is, is->closure, is->buf, count, error);
7824 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
7831 ChildProc *cp = (ChildProc *) pr;
7833 is = (InputSource *) calloc(1, sizeof(InputSource));
7834 is->lineByLine = lineByLine;
7838 is->fd = fileno(stdin);
7840 is->kind = cp->kind;
7841 is->fd = cp->fdFrom;
7844 is->unused = is->buf;
7847 is->xid = XtAppAddInput(appContext, is->fd,
7848 (XtPointer) (XtInputReadMask),
7849 (XtInputCallbackProc) DoInputCallback,
7851 is->closure = closure;
7852 return (InputSourceRef) is;
7856 RemoveInputSource(isr)
7859 InputSource *is = (InputSource *) isr;
7861 if (is->xid == 0) return;
7862 XtRemoveInput(is->xid);
7866 int OutputToProcess(pr, message, count, outError)
7872 static int line = 0;
7873 ChildProc *cp = (ChildProc *) pr;
7878 if (appData.noJoin || !appData.useInternalWrap)
7879 outCount = fwrite(message, 1, count, stdout);
7882 int width = get_term_width();
7883 int len = wrap(NULL, message, count, width, &line);
7884 char *msg = malloc(len);
7888 outCount = fwrite(message, 1, count, stdout);
7891 dbgchk = wrap(msg, message, count, width, &line);
7892 if (dbgchk != len && appData.debugMode)
7893 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
7894 outCount = fwrite(msg, 1, dbgchk, stdout);
7900 outCount = write(cp->fdTo, message, count);
7910 /* Output message to process, with "ms" milliseconds of delay
7911 between each character. This is needed when sending the logon
7912 script to ICC, which for some reason doesn't like the
7913 instantaneous send. */
7914 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
7921 ChildProc *cp = (ChildProc *) pr;
7926 r = write(cp->fdTo, message++, 1);
7939 /**** Animation code by Hugh Fisher, DCS, ANU.
7941 Known problem: if a window overlapping the board is
7942 moved away while a piece is being animated underneath,
7943 the newly exposed area won't be updated properly.
7944 I can live with this.
7946 Known problem: if you look carefully at the animation
7947 of pieces in mono mode, they are being drawn as solid
7948 shapes without interior detail while moving. Fixing
7949 this would be a major complication for minimal return.
7952 /* Masks for XPM pieces. Black and white pieces can have
7953 different shapes, but in the interest of retaining my
7954 sanity pieces must have the same outline on both light
7955 and dark squares, and all pieces must use the same
7956 background square colors/images. */
7958 static int xpmDone = 0;
7961 CreateAnimMasks (pieceDepth)
7968 unsigned long plane;
7971 /* Need a bitmap just to get a GC with right depth */
7972 buf = XCreatePixmap(xDisplay, xBoardWindow,
7974 values.foreground = 1;
7975 values.background = 0;
7976 /* Don't use XtGetGC, not read only */
7977 maskGC = XCreateGC(xDisplay, buf,
7978 GCForeground | GCBackground, &values);
7979 XFreePixmap(xDisplay, buf);
7981 buf = XCreatePixmap(xDisplay, xBoardWindow,
7982 squareSize, squareSize, pieceDepth);
7983 values.foreground = XBlackPixel(xDisplay, xScreen);
7984 values.background = XWhitePixel(xDisplay, xScreen);
7985 bufGC = XCreateGC(xDisplay, buf,
7986 GCForeground | GCBackground, &values);
7988 for (piece = WhitePawn; piece <= BlackKing; piece++) {
7989 /* Begin with empty mask */
7990 if(!xpmDone) // [HGM] pieces: keep using existing
7991 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
7992 squareSize, squareSize, 1);
7993 XSetFunction(xDisplay, maskGC, GXclear);
7994 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
7995 0, 0, squareSize, squareSize);
7997 /* Take a copy of the piece */
8002 XSetFunction(xDisplay, bufGC, GXcopy);
8003 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8005 0, 0, squareSize, squareSize, 0, 0);
8007 /* XOR the background (light) over the piece */
8008 XSetFunction(xDisplay, bufGC, GXxor);
8010 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8011 0, 0, squareSize, squareSize, 0, 0);
8013 XSetForeground(xDisplay, bufGC, lightSquareColor);
8014 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8017 /* We now have an inverted piece image with the background
8018 erased. Construct mask by just selecting all the non-zero
8019 pixels - no need to reconstruct the original image. */
8020 XSetFunction(xDisplay, maskGC, GXor);
8022 /* Might be quicker to download an XImage and create bitmap
8023 data from it rather than this N copies per piece, but it
8024 only takes a fraction of a second and there is a much
8025 longer delay for loading the pieces. */
8026 for (n = 0; n < pieceDepth; n ++) {
8027 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8028 0, 0, squareSize, squareSize,
8034 XFreePixmap(xDisplay, buf);
8035 XFreeGC(xDisplay, bufGC);
8036 XFreeGC(xDisplay, maskGC);
8040 InitAnimState (anim, info)
8042 XWindowAttributes * info;
8047 /* Each buffer is square size, same depth as window */
8048 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8049 squareSize, squareSize, info->depth);
8050 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8051 squareSize, squareSize, info->depth);
8053 /* Create a plain GC for blitting */
8054 mask = GCForeground | GCBackground | GCFunction |
8055 GCPlaneMask | GCGraphicsExposures;
8056 values.foreground = XBlackPixel(xDisplay, xScreen);
8057 values.background = XWhitePixel(xDisplay, xScreen);
8058 values.function = GXcopy;
8059 values.plane_mask = AllPlanes;
8060 values.graphics_exposures = False;
8061 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8063 /* Piece will be copied from an existing context at
8064 the start of each new animation/drag. */
8065 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8067 /* Outline will be a read-only copy of an existing */
8068 anim->outlineGC = None;
8074 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8075 XWindowAttributes info;
8077 if (xpmDone && gameInfo.variant == old) return;
8078 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8079 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8081 InitAnimState(&game, &info);
8082 InitAnimState(&player, &info);
8084 /* For XPM pieces, we need bitmaps to use as masks. */
8086 CreateAnimMasks(info.depth);
8092 static Boolean frameWaiting;
8094 static RETSIGTYPE FrameAlarm (sig)
8097 frameWaiting = False;
8098 /* In case System-V style signals. Needed?? */
8099 signal(SIGALRM, FrameAlarm);
8106 struct itimerval delay;
8108 XSync(xDisplay, False);
8111 frameWaiting = True;
8112 signal(SIGALRM, FrameAlarm);
8113 delay.it_interval.tv_sec =
8114 delay.it_value.tv_sec = time / 1000;
8115 delay.it_interval.tv_usec =
8116 delay.it_value.tv_usec = (time % 1000) * 1000;
8117 setitimer(ITIMER_REAL, &delay, NULL);
8118 while (frameWaiting) pause();
8119 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8120 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8121 setitimer(ITIMER_REAL, &delay, NULL);
8131 XSync(xDisplay, False);
8133 usleep(time * 1000);
8138 /* Convert board position to corner of screen rect and color */
8141 ScreenSquare(column, row, pt, color)
8142 int column; int row; XPoint * pt; int * color;
8145 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8146 pt->y = lineGap + row * (squareSize + lineGap);
8148 pt->x = lineGap + column * (squareSize + lineGap);
8149 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8151 *color = SquareColor(row, column);
8154 /* Convert window coords to square */
8157 BoardSquare(x, y, column, row)
8158 int x; int y; int * column; int * row;
8160 *column = EventToSquare(x, BOARD_WIDTH);
8161 if (flipView && *column >= 0)
8162 *column = BOARD_WIDTH - 1 - *column;
8163 *row = EventToSquare(y, BOARD_HEIGHT);
8164 if (!flipView && *row >= 0)
8165 *row = BOARD_HEIGHT - 1 - *row;
8170 #undef Max /* just in case */
8172 #define Max(a, b) ((a) > (b) ? (a) : (b))
8173 #define Min(a, b) ((a) < (b) ? (a) : (b))
8176 SetRect(rect, x, y, width, height)
8177 XRectangle * rect; int x; int y; int width; int height;
8181 rect->width = width;
8182 rect->height = height;
8185 /* Test if two frames overlap. If they do, return
8186 intersection rect within old and location of
8187 that rect within new. */
8190 Intersect(old, new, size, area, pt)
8191 XPoint * old; XPoint * new;
8192 int size; XRectangle * area; XPoint * pt;
8194 if (old->x > new->x + size || new->x > old->x + size ||
8195 old->y > new->y + size || new->y > old->y + size) {
8198 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8199 size - abs(old->x - new->x), size - abs(old->y - new->y));
8200 pt->x = Max(old->x - new->x, 0);
8201 pt->y = Max(old->y - new->y, 0);
8206 /* For two overlapping frames, return the rect(s)
8207 in the old that do not intersect with the new. */
8210 CalcUpdateRects(old, new, size, update, nUpdates)
8211 XPoint * old; XPoint * new; int size;
8212 XRectangle update[]; int * nUpdates;
8216 /* If old = new (shouldn't happen) then nothing to draw */
8217 if (old->x == new->x && old->y == new->y) {
8221 /* Work out what bits overlap. Since we know the rects
8222 are the same size we don't need a full intersect calc. */
8224 /* Top or bottom edge? */
8225 if (new->y > old->y) {
8226 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8228 } else if (old->y > new->y) {
8229 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8230 size, old->y - new->y);
8233 /* Left or right edge - don't overlap any update calculated above. */
8234 if (new->x > old->x) {
8235 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8236 new->x - old->x, size - abs(new->y - old->y));
8238 } else if (old->x > new->x) {
8239 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8240 old->x - new->x, size - abs(new->y - old->y));
8247 /* Generate a series of frame coords from start->mid->finish.
8248 The movement rate doubles until the half way point is
8249 reached, then halves back down to the final destination,
8250 which gives a nice slow in/out effect. The algorithmn
8251 may seem to generate too many intermediates for short
8252 moves, but remember that the purpose is to attract the
8253 viewers attention to the piece about to be moved and
8254 then to where it ends up. Too few frames would be less
8258 Tween(start, mid, finish, factor, frames, nFrames)
8259 XPoint * start; XPoint * mid;
8260 XPoint * finish; int factor;
8261 XPoint frames[]; int * nFrames;
8263 int fraction, n, count;
8267 /* Slow in, stepping 1/16th, then 1/8th, ... */
8269 for (n = 0; n < factor; n++)
8271 for (n = 0; n < factor; n++) {
8272 frames[count].x = start->x + (mid->x - start->x) / fraction;
8273 frames[count].y = start->y + (mid->y - start->y) / fraction;
8275 fraction = fraction / 2;
8279 frames[count] = *mid;
8282 /* Slow out, stepping 1/2, then 1/4, ... */
8284 for (n = 0; n < factor; n++) {
8285 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8286 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8288 fraction = fraction * 2;
8293 /* Draw a piece on the screen without disturbing what's there */
8296 SelectGCMask(piece, clip, outline, mask)
8297 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8301 /* Bitmap for piece being moved. */
8302 if (appData.monoMode) {
8303 *mask = *pieceToSolid(piece);
8304 } else if (useImages) {
8306 *mask = xpmMask[piece];
8308 *mask = ximMaskPm[piece];
8311 *mask = *pieceToSolid(piece);
8314 /* GC for piece being moved. Square color doesn't matter, but
8315 since it gets modified we make a copy of the original. */
8317 if (appData.monoMode)
8322 if (appData.monoMode)
8327 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8329 /* Outline only used in mono mode and is not modified */
8331 *outline = bwPieceGC;
8333 *outline = wbPieceGC;
8337 OverlayPiece(piece, clip, outline, dest)
8338 ChessSquare piece; GC clip; GC outline; Drawable dest;
8343 /* Draw solid rectangle which will be clipped to shape of piece */
8344 XFillRectangle(xDisplay, dest, clip,
8345 0, 0, squareSize, squareSize);
8346 if (appData.monoMode)
8347 /* Also draw outline in contrasting color for black
8348 on black / white on white cases */
8349 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8350 0, 0, squareSize, squareSize, 0, 0, 1);
8352 /* Copy the piece */
8357 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8359 0, 0, squareSize, squareSize,
8364 /* Animate the movement of a single piece */
8367 BeginAnimation(anim, piece, startColor, start)
8375 /* The old buffer is initialised with the start square (empty) */
8376 BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8377 anim->prevFrame = *start;
8379 /* The piece will be drawn using its own bitmap as a matte */
8380 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8381 XSetClipMask(xDisplay, anim->pieceGC, mask);
8385 AnimationFrame(anim, frame, piece)
8390 XRectangle updates[4];
8395 /* Save what we are about to draw into the new buffer */
8396 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8397 frame->x, frame->y, squareSize, squareSize,
8400 /* Erase bits of the previous frame */
8401 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8402 /* Where the new frame overlapped the previous,
8403 the contents in newBuf are wrong. */
8404 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8405 overlap.x, overlap.y,
8406 overlap.width, overlap.height,
8408 /* Repaint the areas in the old that don't overlap new */
8409 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8410 for (i = 0; i < count; i++)
8411 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8412 updates[i].x - anim->prevFrame.x,
8413 updates[i].y - anim->prevFrame.y,
8414 updates[i].width, updates[i].height,
8415 updates[i].x, updates[i].y);
8417 /* Easy when no overlap */
8418 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8419 0, 0, squareSize, squareSize,
8420 anim->prevFrame.x, anim->prevFrame.y);
8423 /* Save this frame for next time round */
8424 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8425 0, 0, squareSize, squareSize,
8427 anim->prevFrame = *frame;
8429 /* Draw piece over original screen contents, not current,
8430 and copy entire rect. Wipes out overlapping piece images. */
8431 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8432 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8433 0, 0, squareSize, squareSize,
8434 frame->x, frame->y);
8438 EndAnimation (anim, finish)
8442 XRectangle updates[4];
8447 /* The main code will redraw the final square, so we
8448 only need to erase the bits that don't overlap. */
8449 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8450 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8451 for (i = 0; i < count; i++)
8452 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8453 updates[i].x - anim->prevFrame.x,
8454 updates[i].y - anim->prevFrame.y,
8455 updates[i].width, updates[i].height,
8456 updates[i].x, updates[i].y);
8458 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8459 0, 0, squareSize, squareSize,
8460 anim->prevFrame.x, anim->prevFrame.y);
8465 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8467 ChessSquare piece; int startColor;
8468 XPoint * start; XPoint * finish;
8469 XPoint frames[]; int nFrames;
8473 BeginAnimation(anim, piece, startColor, start);
8474 for (n = 0; n < nFrames; n++) {
8475 AnimationFrame(anim, &(frames[n]), piece);
8476 FrameDelay(appData.animSpeed);
8478 EndAnimation(anim, finish);
8481 /* Main control logic for deciding what to animate and how */
8484 AnimateMove(board, fromX, fromY, toX, toY)
8493 XPoint start, finish, mid;
8494 XPoint frames[kFactor * 2 + 1];
8495 int nFrames, startColor, endColor;
8497 /* Are we animating? */
8498 if (!appData.animate || appData.blindfold)
8501 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8502 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8503 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8505 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8506 piece = board[fromY][fromX];
8507 if (piece >= EmptySquare) return;
8512 hop = (piece == WhiteKnight || piece == BlackKnight);
8515 if (appData.debugMode) {
8516 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8517 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8518 piece, fromX, fromY, toX, toY); }
8520 ScreenSquare(fromX, fromY, &start, &startColor);
8521 ScreenSquare(toX, toY, &finish, &endColor);
8524 /* Knight: make diagonal movement then straight */
8525 if (abs(toY - fromY) < abs(toX - fromX)) {
8526 mid.x = start.x + (finish.x - start.x) / 2;
8530 mid.y = start.y + (finish.y - start.y) / 2;
8533 mid.x = start.x + (finish.x - start.x) / 2;
8534 mid.y = start.y + (finish.y - start.y) / 2;
8537 /* Don't use as many frames for very short moves */
8538 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8539 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8541 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8542 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8544 /* Be sure end square is redrawn */
8545 damage[toY][toX] = True;
8549 DragPieceBegin(x, y)
8552 int boardX, boardY, color;
8555 /* Are we animating? */
8556 if (!appData.animateDragging || appData.blindfold)
8559 /* Figure out which square we start in and the
8560 mouse position relative to top left corner. */
8561 BoardSquare(x, y, &boardX, &boardY);
8562 player.startBoardX = boardX;
8563 player.startBoardY = boardY;
8564 ScreenSquare(boardX, boardY, &corner, &color);
8565 player.startSquare = corner;
8566 player.startColor = color;
8567 /* As soon as we start dragging, the piece will jump slightly to
8568 be centered over the mouse pointer. */
8569 player.mouseDelta.x = squareSize/2;
8570 player.mouseDelta.y = squareSize/2;
8571 /* Initialise animation */
8572 player.dragPiece = PieceForSquare(boardX, boardY);
8574 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8575 player.dragActive = True;
8576 BeginAnimation(&player, player.dragPiece, color, &corner);
8577 /* Mark this square as needing to be redrawn. Note that
8578 we don't remove the piece though, since logically (ie
8579 as seen by opponent) the move hasn't been made yet. */
8580 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8581 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8582 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8583 corner.x, corner.y, squareSize, squareSize,
8584 0, 0); // [HGM] zh: unstack in stead of grab
8585 damage[boardY][boardX] = True;
8587 player.dragActive = False;
8597 /* Are we animating? */
8598 if (!appData.animateDragging || appData.blindfold)
8602 if (! player.dragActive)
8604 /* Move piece, maintaining same relative position
8605 of mouse within square */
8606 corner.x = x - player.mouseDelta.x;
8607 corner.y = y - player.mouseDelta.y;
8608 AnimationFrame(&player, &corner, player.dragPiece);
8610 if (appData.highlightDragging) {
8612 BoardSquare(x, y, &boardX, &boardY);
8613 SetHighlights(fromX, fromY, boardX, boardY);
8622 int boardX, boardY, color;
8625 /* Are we animating? */
8626 if (!appData.animateDragging || appData.blindfold)
8630 if (! player.dragActive)
8632 /* Last frame in sequence is square piece is
8633 placed on, which may not match mouse exactly. */
8634 BoardSquare(x, y, &boardX, &boardY);
8635 ScreenSquare(boardX, boardY, &corner, &color);
8636 EndAnimation(&player, &corner);
8638 /* Be sure end square is redrawn */
8639 damage[boardY][boardX] = True;
8641 /* This prevents weird things happening with fast successive
8642 clicks which on my Sun at least can cause motion events
8643 without corresponding press/release. */
8644 player.dragActive = False;
8647 /* Handle expose event while piece being dragged */
8652 if (!player.dragActive || appData.blindfold)
8655 /* What we're doing: logically, the move hasn't been made yet,
8656 so the piece is still in it's original square. But visually
8657 it's being dragged around the board. So we erase the square
8658 that the piece is on and draw it at the last known drag point. */
8659 BlankSquare(player.startSquare.x, player.startSquare.y,
8660 player.startColor, EmptySquare, xBoardWindow);
8661 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8662 damage[player.startBoardY][player.startBoardX] = TRUE;
8665 #include <sys/ioctl.h>
8666 int get_term_width()
8668 int fd, default_width;
8671 default_width = 79; // this is FICS default anyway...
8673 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8675 if (!ioctl(fd, TIOCGSIZE, &win))
8676 default_width = win.ts_cols;
8677 #elif defined(TIOCGWINSZ)
8679 if (!ioctl(fd, TIOCGWINSZ, &win))
8680 default_width = win.ws_col;
8682 return default_width;
8685 void update_ics_width()
8687 static int old_width = 0;
8688 int new_width = get_term_width();
8690 if (old_width != new_width)
8691 ics_printf("set width %d\n", new_width);
8692 old_width = new_width;
8695 void NotifyFrontendLogin()