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(());
452 * XBoard depends on Xt R4 or higher
454 int xtVersion = XtSpecificationRelease;
459 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
460 jailSquareColor, highlightSquareColor, premoveHighlightColor;
461 Pixel lowTimeWarningColor;
462 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
463 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
464 wjPieceGC, bjPieceGC, prelineGC, countGC;
465 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
466 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
467 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
468 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
469 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
470 ICSInputShell, fileNameShell, askQuestionShell;
471 Widget historyShell, evalGraphShell, gameListShell;
472 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
473 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
474 Font clockFontID, coordFontID, countFontID;
475 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
476 XtAppContext appContext;
478 char *oldICSInteractionTitle;
482 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
484 Position commentX = -1, commentY = -1;
485 Dimension commentW, commentH;
486 typedef unsigned int BoardSize;
488 Boolean chessProgram;
490 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
491 int squareSize, smallLayout = 0, tinyLayout = 0,
492 marginW, marginH, // [HGM] for run-time resizing
493 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
494 ICSInputBoxUp = False, askQuestionUp = False,
495 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
496 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
497 Pixel timerForegroundPixel, timerBackgroundPixel;
498 Pixel buttonForegroundPixel, buttonBackgroundPixel;
499 char *chessDir, *programName, *programVersion,
500 *gameCopyFilename, *gamePasteFilename;
501 Boolean alwaysOnTop = False;
502 Boolean saveSettingsOnExit;
503 char *settingsFileName;
504 char *icsTextMenuString;
506 char *firstChessProgramNames;
507 char *secondChessProgramNames;
509 WindowPlacement wpMain;
510 WindowPlacement wpConsole;
511 WindowPlacement wpComment;
512 WindowPlacement wpMoveHistory;
513 WindowPlacement wpEvalGraph;
514 WindowPlacement wpEngineOutput;
515 WindowPlacement wpGameList;
516 WindowPlacement wpTags;
520 Pixmap pieceBitmap[2][(int)BlackPawn];
521 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
522 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
523 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
524 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
525 int useImages, useImageSqs;
526 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
527 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
528 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
529 XImage *ximLightSquare, *ximDarkSquare;
532 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
533 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
535 #define White(piece) ((int)(piece) < (int)BlackPawn)
537 /* Variables for doing smooth animation. This whole thing
538 would be much easier if the board was double-buffered,
539 but that would require a fairly major rewrite. */
544 GC blitGC, pieceGC, outlineGC;
545 XPoint startSquare, prevFrame, mouseDelta;
549 int startBoardX, startBoardY;
552 /* There can be two pieces being animated at once: a player
553 can begin dragging a piece before the remote opponent has moved. */
555 static AnimState game, player;
557 /* Bitmaps for use as masks when drawing XPM pieces.
558 Need one for each black and white piece. */
559 static Pixmap xpmMask[BlackKing + 1];
561 /* This magic number is the number of intermediate frames used
562 in each half of the animation. For short moves it's reduced
563 by 1. The total number of frames will be factor * 2 + 1. */
566 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
568 MenuItem fileMenu[] = {
569 {N_("New Game"), ResetProc},
570 {N_("New Shuffle Game ..."), ShuffleMenuProc},
571 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
572 {"----", NothingProc},
573 {N_("Load Game"), LoadGameProc},
574 {N_("Load Next Game"), LoadNextGameProc},
575 {N_("Load Previous Game"), LoadPrevGameProc},
576 {N_("Reload Same Game"), ReloadGameProc},
577 {N_("Save Game"), SaveGameProc},
578 {"----", NothingProc},
579 {N_("Copy Game"), CopyGameProc},
580 {N_("Paste Game"), PasteGameProc},
581 {"----", NothingProc},
582 {N_("Load Position"), LoadPositionProc},
583 {N_("Load Next Position"), LoadNextPositionProc},
584 {N_("Load Previous Position"), LoadPrevPositionProc},
585 {N_("Reload Same Position"), ReloadPositionProc},
586 {N_("Save Position"), SavePositionProc},
587 {"----", NothingProc},
588 {N_("Copy Position"), CopyPositionProc},
589 {N_("Paste Position"), PastePositionProc},
590 {"----", NothingProc},
591 {N_("Mail Move"), MailMoveProc},
592 {N_("Reload CMail Message"), ReloadCmailMsgProc},
593 {"----", NothingProc},
594 {N_("Exit"), QuitProc},
598 MenuItem modeMenu[] = {
599 {N_("Machine White"), MachineWhiteProc},
600 {N_("Machine Black"), MachineBlackProc},
601 {N_("Two Machines"), TwoMachinesProc},
602 {N_("Analysis Mode"), AnalyzeModeProc},
603 {N_("Analyze File"), AnalyzeFileProc },
604 {N_("ICS Client"), IcsClientProc},
605 {N_("Edit Game"), EditGameProc},
606 {N_("Edit Position"), EditPositionProc},
607 {N_("Training"), TrainingProc},
608 {"----", NothingProc},
609 {N_("Show Engine Output"), EngineOutputProc},
610 {N_("Show Evaluation Graph"), EvalGraphProc},
611 {N_("Show Game List"), ShowGameListProc},
612 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
613 {"----", NothingProc},
614 {N_("Edit Tags"), EditTagsProc},
615 {N_("Edit Comment"), EditCommentProc},
616 {N_("ICS Input Box"), IcsInputBoxProc},
617 {N_("Pause"), PauseProc},
621 MenuItem actionMenu[] = {
622 {N_("Accept"), AcceptProc},
623 {N_("Decline"), DeclineProc},
624 {N_("Rematch"), RematchProc},
625 {"----", NothingProc},
626 {N_("Call Flag"), CallFlagProc},
627 {N_("Draw"), DrawProc},
628 {N_("Adjourn"), AdjournProc},
629 {N_("Abort"), AbortProc},
630 {N_("Resign"), ResignProc},
631 {"----", NothingProc},
632 {N_("Stop Observing"), StopObservingProc},
633 {N_("Stop Examining"), StopExaminingProc},
634 {"----", NothingProc},
635 {N_("Adjudicate to White"), AdjuWhiteProc},
636 {N_("Adjudicate to Black"), AdjuBlackProc},
637 {N_("Adjudicate Draw"), AdjuDrawProc},
641 MenuItem stepMenu[] = {
642 {N_("Backward"), BackwardProc},
643 {N_("Forward"), ForwardProc},
644 {N_("Back to Start"), ToStartProc},
645 {N_("Forward to End"), ToEndProc},
646 {N_("Revert"), RevertProc},
647 {N_("Truncate Game"), TruncateGameProc},
648 {"----", NothingProc},
649 {N_("Move Now"), MoveNowProc},
650 {N_("Retract Move"), RetractMoveProc},
654 MenuItem optionsMenu[] = {
655 {N_("Flip View"), FlipViewProc},
656 {"----", NothingProc},
657 {N_("Adjudications ..."), EngineMenuProc},
658 {N_("General Settings ..."), UciMenuProc},
659 {N_("Engine #1 Settings ..."), FirstSettingsProc},
660 {N_("Engine #2 Settings ..."), SecondSettingsProc},
661 {N_("Time Control ..."), TimeControlProc},
662 {"----", NothingProc},
663 {N_("Always Queen"), AlwaysQueenProc},
664 {N_("Animate Dragging"), AnimateDraggingProc},
665 {N_("Animate Moving"), AnimateMovingProc},
666 {N_("Auto Comment"), AutocommProc},
667 {N_("Auto Flag"), AutoflagProc},
668 {N_("Auto Flip View"), AutoflipProc},
669 {N_("Auto Observe"), AutobsProc},
670 {N_("Auto Raise Board"), AutoraiseProc},
671 {N_("Auto Save"), AutosaveProc},
672 {N_("Blindfold"), BlindfoldProc},
673 {N_("Flash Moves"), FlashMovesProc},
674 {N_("Get Move List"), GetMoveListProc},
676 {N_("Highlight Dragging"), HighlightDraggingProc},
678 {N_("Highlight Last Move"), HighlightLastMoveProc},
679 {N_("Move Sound"), MoveSoundProc},
680 {N_("ICS Alarm"), IcsAlarmProc},
681 {N_("Old Save Style"), OldSaveStyleProc},
682 {N_("Periodic Updates"), PeriodicUpdatesProc},
683 {N_("Ponder Next Move"), PonderNextMoveProc},
684 {N_("Popup Exit Message"), PopupExitMessageProc},
685 {N_("Popup Move Errors"), PopupMoveErrorsProc},
686 {N_("Premove"), PremoveProc},
687 {N_("Quiet Play"), QuietPlayProc},
688 {N_("Show Coords"), ShowCoordsProc},
689 {N_("Hide Thinking"), HideThinkingProc},
690 {N_("Test Legality"), TestLegalityProc},
691 {"----", NothingProc},
692 {N_("Save Settings Now"), SaveSettingsProc},
693 {N_("Save Settings on Exit"), SaveOnExitProc},
697 MenuItem helpMenu[] = {
698 {N_("Info XBoard"), InfoProc},
699 {N_("Man XBoard"), ManProc},
700 {"----", NothingProc},
701 {N_("Hint"), HintProc},
702 {N_("Book"), BookProc},
703 {"----", NothingProc},
704 {N_("About XBoard"), AboutProc},
709 {N_("File"), fileMenu},
710 {N_("Mode"), modeMenu},
711 {N_("Action"), actionMenu},
712 {N_("Step"), stepMenu},
713 {N_("Options"), optionsMenu},
714 {N_("Help"), helpMenu},
718 #define PAUSE_BUTTON N_("P")
719 MenuItem buttonBar[] = {
722 {PAUSE_BUTTON, PauseProc},
728 #define PIECE_MENU_SIZE 18
729 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
730 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
731 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
732 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
733 N_("Empty square"), N_("Clear board") },
734 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
735 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
736 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
737 N_("Empty square"), N_("Clear board") }
739 /* must be in same order as PieceMenuStrings! */
740 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
741 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
742 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
743 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
744 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
745 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
746 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
747 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
748 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
751 #define DROP_MENU_SIZE 6
752 String dropMenuStrings[DROP_MENU_SIZE] = {
753 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
755 /* must be in same order as PieceMenuStrings! */
756 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
757 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
758 WhiteRook, WhiteQueen
766 DropMenuEnables dmEnables[] = {
784 { XtNborderWidth, 0 },
785 { XtNdefaultDistance, 0 },
789 { XtNborderWidth, 0 },
790 { XtNresizable, (XtArgVal) True },
794 { XtNborderWidth, 0 },
800 { XtNjustify, (XtArgVal) XtJustifyRight },
801 { XtNlabel, (XtArgVal) "..." },
802 { XtNresizable, (XtArgVal) True },
803 { XtNresize, (XtArgVal) False }
806 Arg messageArgs[] = {
807 { XtNjustify, (XtArgVal) XtJustifyLeft },
808 { XtNlabel, (XtArgVal) "..." },
809 { XtNresizable, (XtArgVal) True },
810 { XtNresize, (XtArgVal) False }
814 { XtNborderWidth, 0 },
815 { XtNjustify, (XtArgVal) XtJustifyLeft }
818 XtResource clientResources[] = {
819 { "flashCount", "flashCount", XtRInt, sizeof(int),
820 XtOffset(AppDataPtr, flashCount), XtRImmediate,
821 (XtPointer) FLASH_COUNT },
824 XrmOptionDescRec shellOptions[] = {
825 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
826 { "-flash", "flashCount", XrmoptionNoArg, "3" },
827 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
830 XtActionsRec boardActions[] = {
831 { "DrawPosition", DrawPositionProc },
832 { "HandleUserMove", HandleUserMove },
833 { "AnimateUserMove", AnimateUserMove },
834 { "FileNameAction", FileNameAction },
835 { "AskQuestionProc", AskQuestionProc },
836 { "AskQuestionReplyAction", AskQuestionReplyAction },
837 { "PieceMenuPopup", PieceMenuPopup },
838 { "WhiteClock", WhiteClock },
839 { "BlackClock", BlackClock },
840 { "Iconify", Iconify },
841 { "ResetProc", ResetProc },
842 { "LoadGameProc", LoadGameProc },
843 { "LoadNextGameProc", LoadNextGameProc },
844 { "LoadPrevGameProc", LoadPrevGameProc },
845 { "LoadSelectedProc", LoadSelectedProc },
846 { "ReloadGameProc", ReloadGameProc },
847 { "LoadPositionProc", LoadPositionProc },
848 { "LoadNextPositionProc", LoadNextPositionProc },
849 { "LoadPrevPositionProc", LoadPrevPositionProc },
850 { "ReloadPositionProc", ReloadPositionProc },
851 { "CopyPositionProc", CopyPositionProc },
852 { "PastePositionProc", PastePositionProc },
853 { "CopyGameProc", CopyGameProc },
854 { "PasteGameProc", PasteGameProc },
855 { "SaveGameProc", SaveGameProc },
856 { "SavePositionProc", SavePositionProc },
857 { "MailMoveProc", MailMoveProc },
858 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
859 { "QuitProc", QuitProc },
860 { "MachineWhiteProc", MachineWhiteProc },
861 { "MachineBlackProc", MachineBlackProc },
862 { "AnalysisModeProc", AnalyzeModeProc },
863 { "AnalyzeFileProc", AnalyzeFileProc },
864 { "TwoMachinesProc", TwoMachinesProc },
865 { "IcsClientProc", IcsClientProc },
866 { "EditGameProc", EditGameProc },
867 { "EditPositionProc", EditPositionProc },
868 { "TrainingProc", EditPositionProc },
869 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
870 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
871 { "ShowGameListProc", ShowGameListProc },
872 { "ShowMoveListProc", HistoryShowProc},
873 { "EditTagsProc", EditCommentProc },
874 { "EditCommentProc", EditCommentProc },
875 { "IcsAlarmProc", IcsAlarmProc },
876 { "IcsInputBoxProc", IcsInputBoxProc },
877 { "PauseProc", PauseProc },
878 { "AcceptProc", AcceptProc },
879 { "DeclineProc", DeclineProc },
880 { "RematchProc", RematchProc },
881 { "CallFlagProc", CallFlagProc },
882 { "DrawProc", DrawProc },
883 { "AdjournProc", AdjournProc },
884 { "AbortProc", AbortProc },
885 { "ResignProc", ResignProc },
886 { "AdjuWhiteProc", AdjuWhiteProc },
887 { "AdjuBlackProc", AdjuBlackProc },
888 { "AdjuDrawProc", AdjuDrawProc },
889 { "EnterKeyProc", EnterKeyProc },
890 { "StopObservingProc", StopObservingProc },
891 { "StopExaminingProc", StopExaminingProc },
892 { "BackwardProc", BackwardProc },
893 { "ForwardProc", ForwardProc },
894 { "ToStartProc", ToStartProc },
895 { "ToEndProc", ToEndProc },
896 { "RevertProc", RevertProc },
897 { "TruncateGameProc", TruncateGameProc },
898 { "MoveNowProc", MoveNowProc },
899 { "RetractMoveProc", RetractMoveProc },
900 { "AlwaysQueenProc", AlwaysQueenProc },
901 { "AnimateDraggingProc", AnimateDraggingProc },
902 { "AnimateMovingProc", AnimateMovingProc },
903 { "AutoflagProc", AutoflagProc },
904 { "AutoflipProc", AutoflipProc },
905 { "AutobsProc", AutobsProc },
906 { "AutoraiseProc", AutoraiseProc },
907 { "AutosaveProc", AutosaveProc },
908 { "BlindfoldProc", BlindfoldProc },
909 { "FlashMovesProc", FlashMovesProc },
910 { "FlipViewProc", FlipViewProc },
911 { "GetMoveListProc", GetMoveListProc },
913 { "HighlightDraggingProc", HighlightDraggingProc },
915 { "HighlightLastMoveProc", HighlightLastMoveProc },
916 { "IcsAlarmProc", IcsAlarmProc },
917 { "MoveSoundProc", MoveSoundProc },
918 { "OldSaveStyleProc", OldSaveStyleProc },
919 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
920 { "PonderNextMoveProc", PonderNextMoveProc },
921 { "PopupExitMessageProc", PopupExitMessageProc },
922 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
923 { "PremoveProc", PremoveProc },
924 { "QuietPlayProc", QuietPlayProc },
925 { "ShowCoordsProc", ShowCoordsProc },
926 { "ShowThinkingProc", ShowThinkingProc },
927 { "HideThinkingProc", HideThinkingProc },
928 { "TestLegalityProc", TestLegalityProc },
929 { "SaveSettingsProc", SaveSettingsProc },
930 { "SaveOnExitProc", SaveOnExitProc },
931 { "InfoProc", InfoProc },
932 { "ManProc", ManProc },
933 { "HintProc", HintProc },
934 { "BookProc", BookProc },
935 { "AboutGameProc", AboutGameProc },
936 { "AboutProc", AboutProc },
937 { "DebugProc", DebugProc },
938 { "NothingProc", NothingProc },
939 { "CommentPopDown", (XtActionProc) CommentPopDown },
940 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
941 { "TagsPopDown", (XtActionProc) TagsPopDown },
942 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
943 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
944 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
945 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
946 { "GameListPopDown", (XtActionProc) GameListPopDown },
947 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
948 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
949 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
950 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
951 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
952 { "EnginePopDown", (XtActionProc) EnginePopDown },
953 { "UciPopDown", (XtActionProc) UciPopDown },
954 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
955 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
956 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
959 char globalTranslations[] =
960 ":<Key>R: ResignProc() \n \
961 :<Key>r: ResetProc() \n \
962 :<Key>g: LoadGameProc() \n \
963 :<Key>N: LoadNextGameProc() \n \
964 :<Key>P: LoadPrevGameProc() \n \
965 :<Key>Q: QuitProc() \n \
966 :<Key>F: ToEndProc() \n \
967 :<Key>f: ForwardProc() \n \
968 :<Key>B: ToStartProc() \n \
969 :<Key>b: BackwardProc() \n \
970 :<Key>p: PauseProc() \n \
971 :<Key>d: DrawProc() \n \
972 :<Key>t: CallFlagProc() \n \
973 :<Key>i: Iconify() \n \
974 :<Key>c: Iconify() \n \
975 :<Key>v: FlipViewProc() \n \
976 <KeyDown>Control_L: BackwardProc() \n \
977 <KeyUp>Control_L: ForwardProc() \n \
978 <KeyDown>Control_R: BackwardProc() \n \
979 <KeyUp>Control_R: ForwardProc() \n \
980 Shift<Key>1: AskQuestionProc(\"Direct command\",\
981 \"Send to chess program:\",,1) \n \
982 Shift<Key>2: AskQuestionProc(\"Direct command\",\
983 \"Send to second chess program:\",,2) \n";
985 char boardTranslations[] =
986 "<Btn1Down>: HandleUserMove() \n \
987 <Btn1Up>: HandleUserMove() \n \
988 <Btn1Motion>: AnimateUserMove() \n \
989 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
990 PieceMenuPopup(menuB) \n \
991 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
992 PieceMenuPopup(menuW) \n \
993 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
994 PieceMenuPopup(menuW) \n \
995 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
996 PieceMenuPopup(menuB) \n";
998 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
999 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1001 char ICSInputTranslations[] =
1002 "<Key>Return: EnterKeyProc() \n";
1004 String xboardResources[] = {
1005 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1006 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1007 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1012 /* Max possible square size */
1013 #define MAXSQSIZE 256
1015 static int xpm_avail[MAXSQSIZE];
1017 #ifdef HAVE_DIR_STRUCT
1019 /* Extract piece size from filename */
1021 xpm_getsize(name, len, ext)
1032 if ((p=strchr(name, '.')) == NULL ||
1033 StrCaseCmp(p+1, ext) != 0)
1039 while (*p && isdigit(*p))
1046 /* Setup xpm_avail */
1048 xpm_getavail(dirname, ext)
1056 for (i=0; i<MAXSQSIZE; ++i)
1059 if (appData.debugMode)
1060 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1062 dir = opendir(dirname);
1065 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1066 programName, dirname);
1070 while ((ent=readdir(dir)) != NULL) {
1071 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1072 if (i > 0 && i < MAXSQSIZE)
1082 xpm_print_avail(fp, ext)
1088 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1089 for (i=1; i<MAXSQSIZE; ++i) {
1095 /* Return XPM piecesize closest to size */
1097 xpm_closest_to(dirname, size, ext)
1103 int sm_diff = MAXSQSIZE;
1107 xpm_getavail(dirname, ext);
1109 if (appData.debugMode)
1110 xpm_print_avail(stderr, ext);
1112 for (i=1; i<MAXSQSIZE; ++i) {
1115 diff = (diff<0) ? -diff : diff;
1116 if (diff < sm_diff) {
1124 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1130 #else /* !HAVE_DIR_STRUCT */
1131 /* If we are on a system without a DIR struct, we can't
1132 read the directory, so we can't collect a list of
1133 filenames, etc., so we can't do any size-fitting. */
1135 xpm_closest_to(dirname, size, ext)
1140 fprintf(stderr, _("\
1141 Warning: No DIR structure found on this system --\n\
1142 Unable to autosize for XPM/XIM pieces.\n\
1143 Please report this error to frankm@hiwaay.net.\n\
1144 Include system type & operating system in message.\n"));
1147 #endif /* HAVE_DIR_STRUCT */
1149 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1150 "magenta", "cyan", "white" };
1154 TextColors textColors[(int)NColorClasses];
1156 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1158 parse_color(str, which)
1162 char *p, buf[100], *d;
1165 if (strlen(str) > 99) /* watch bounds on buf */
1170 for (i=0; i<which; ++i) {
1177 /* Could be looking at something like:
1179 .. in which case we want to stop on a comma also */
1180 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1184 return -1; /* Use default for empty field */
1187 if (which == 2 || isdigit(*p))
1190 while (*p && isalpha(*p))
1195 for (i=0; i<8; ++i) {
1196 if (!StrCaseCmp(buf, cnames[i]))
1197 return which? (i+40) : (i+30);
1199 if (!StrCaseCmp(buf, "default")) return -1;
1201 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1206 parse_cpair(cc, str)
1210 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1211 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1216 /* bg and attr are optional */
1217 textColors[(int)cc].bg = parse_color(str, 1);
1218 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1219 textColors[(int)cc].attr = 0;
1225 /* Arrange to catch delete-window events */
1226 Atom wm_delete_window;
1228 CatchDeleteWindow(Widget w, String procname)
1231 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1232 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1233 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1240 XtSetArg(args[0], XtNiconic, False);
1241 XtSetValues(shellWidget, args, 1);
1243 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1246 //---------------------------------------------------------------------------------------------------------
1247 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1250 #define CW_USEDEFAULT (1<<31)
1251 #define ICS_TEXT_MENU_SIZE 90
1252 #define DEBUG_FILE "xboard.debug"
1253 #define SetCurrentDirectory chdir
1254 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1258 // these two must some day move to frontend.h, when they are implemented
1259 Boolean MoveHistoryIsUp();
1260 Boolean GameListIsUp();
1262 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1265 // front-end part of option handling
1267 // [HGM] This platform-dependent table provides the location for storing the color info
1268 extern char *crWhite, * crBlack;
1272 &appData.whitePieceColor,
1273 &appData.blackPieceColor,
1274 &appData.lightSquareColor,
1275 &appData.darkSquareColor,
1276 &appData.highlightSquareColor,
1277 &appData.premoveHighlightColor,
1290 ParseFont(char *name, int number)
1291 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1293 case 0: // CLOCK_FONT
1294 appData.clockFont = strdup(name);
1296 case 1: // MESSAGE_FONT
1297 appData.font = strdup(name);
1299 case 2: // COORD_FONT
1300 appData.coordFont = strdup(name);
1309 { // only 2 fonts currently
1310 appData.clockFont = CLOCK_FONT_NAME;
1311 appData.coordFont = COORD_FONT_NAME;
1312 appData.font = DEFAULT_FONT_NAME;
1317 { // no-op, until we identify the code for this already in XBoard and move it here
1321 ParseColor(int n, char *name)
1322 { // in XBoard, just copy the color-name string
1323 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1327 ParseTextAttribs(ColorClass cc, char *s)
1329 (&appData.colorShout)[cc] = strdup(s);
1333 ParseBoardSize(void *addr, char *name)
1335 appData.boardSize = strdup(name);
1340 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1344 SetCommPortDefaults()
1345 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1348 // [HGM] args: these three cases taken out to stay in front-end
1350 SaveFontArg(FILE *f, ArgDescriptor *ad)
1353 switch((int)ad->argLoc) {
1354 case 0: // CLOCK_FONT
1355 name = appData.clockFont;
1357 case 1: // MESSAGE_FONT
1358 name = appData.font;
1360 case 2: // COORD_FONT
1361 name = appData.coordFont;
1366 // Do not save fonts for now, as the saved font would be board-size specific
1367 // and not suitable for a re-start at another board size
1368 // fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, name);
1373 { // nothing to do, as the sounds are at all times represented by their text-string names already
1377 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1378 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1379 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1383 SaveColor(FILE *f, ArgDescriptor *ad)
1384 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1385 if(colorVariable[(int)ad->argLoc])
1386 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1390 SaveBoardSize(FILE *f, char *name, void *addr)
1391 { // wrapper to shield back-end from BoardSize & sizeInfo
1392 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1396 ParseCommPortSettings(char *s)
1397 { // no such option in XBoard (yet)
1400 extern Widget engineOutputShell;
1401 extern Widget tagsShell, editTagsShell;
1403 GetActualPlacement(Widget wg, WindowPlacement *wp)
1413 XtSetArg(args[i], XtNx, &x); i++;
1414 XtSetArg(args[i], XtNy, &y); i++;
1415 XtSetArg(args[i], XtNwidth, &w); i++;
1416 XtSetArg(args[i], XtNheight, &h); i++;
1417 XtGetValues(wg, args, i);
1426 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1427 // In XBoard this will have to wait until awareness of window parameters is implemented
1428 GetActualPlacement(shellWidget, &wpMain);
1429 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1430 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1431 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1432 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1433 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1434 else GetActualPlacement(editShell, &wpComment);
1435 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1436 else GetActualPlacement(editTagsShell, &wpTags);
1440 PrintCommPortSettings(FILE *f, char *name)
1441 { // This option does not exist in XBoard
1445 MySearchPath(char *installDir, char *name, char *fullname)
1446 { // just append installDir and name. Perhaps ExpandPath should be used here?
1447 name = ExpandPathName(name);
1448 if(name && name[0] == '/') strcpy(fullname, name); else {
1449 sprintf(fullname, "%s%c%s", installDir, '/', name);
1455 MyGetFullPathName(char *name, char *fullname)
1456 { // should use ExpandPath?
1457 name = ExpandPathName(name);
1458 strcpy(fullname, name);
1463 EnsureOnScreen(int *x, int *y, int minX, int minY)
1470 { // [HGM] args: allows testing if main window is realized from back-end
1471 return xBoardWindow != 0;
1475 PopUpStartupDialog()
1476 { // start menu not implemented in XBoard
1479 ConvertToLine(int argc, char **argv)
1481 static char line[128*1024], buf[1024];
1485 for(i=1; i<argc; i++) {
1486 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1487 && argv[i][0] != '{' )
1488 sprintf(buf, "{%s} ", argv[i]);
1489 else sprintf(buf, "%s ", argv[i]);
1492 line[strlen(line)-1] = NULLCHAR;
1496 //--------------------------------------------------------------------------------------------
1499 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1501 #define BoardSize int
1502 void InitDrawingSizes(BoardSize boardSize, int flags)
1503 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1504 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1506 XtGeometryResult gres;
1509 if(!formWidget) return;
1512 * Enable shell resizing.
1514 shellArgs[0].value = (XtArgVal) &w;
1515 shellArgs[1].value = (XtArgVal) &h;
1516 XtGetValues(shellWidget, shellArgs, 2);
1518 shellArgs[4].value = 2*w; shellArgs[2].value = 10;
1519 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1520 XtSetValues(shellWidget, &shellArgs[2], 4);
1522 XtSetArg(args[0], XtNdefaultDistance, &sep);
1523 XtGetValues(formWidget, args, 1);
1525 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1526 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1529 XtSetArg(args[0], XtNwidth, boardWidth);
1530 XtSetArg(args[1], XtNheight, boardHeight);
1531 XtSetValues(boardWidget, args, 2);
1533 timerWidth = (boardWidth - sep) / 2;
1534 XtSetArg(args[0], XtNwidth, timerWidth);
1535 XtSetValues(whiteTimerWidget, args, 1);
1536 XtSetValues(blackTimerWidget, args, 1);
1538 XawFormDoLayout(formWidget, False);
1540 if (appData.titleInWindow) {
1542 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1543 XtSetArg(args[i], XtNheight, &h); i++;
1544 XtGetValues(titleWidget, args, i);
1546 w = boardWidth - 2*bor;
1548 XtSetArg(args[0], XtNwidth, &w);
1549 XtGetValues(menuBarWidget, args, 1);
1550 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1553 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1554 if (gres != XtGeometryYes && appData.debugMode) {
1556 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1557 programName, gres, w, h, wr, hr);
1561 XawFormDoLayout(formWidget, True);
1564 * Inhibit shell resizing.
1566 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW;
1567 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1568 shellArgs[4].value = shellArgs[2].value = w;
1569 shellArgs[5].value = shellArgs[3].value = h;
1570 XtSetValues(shellWidget, &shellArgs[0], 6);
1572 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1575 for(i=0; i<4; i++) {
1577 for(p=0; p<=(int)WhiteKing; p++)
1578 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1579 if(gameInfo.variant == VariantShogi) {
1580 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1581 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1582 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1583 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1584 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1587 if(gameInfo.variant == VariantGothic) {
1588 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1592 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1593 for(p=0; p<=(int)WhiteKing; p++)
1594 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1595 if(gameInfo.variant == VariantShogi) {
1596 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1597 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1598 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1599 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1600 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1603 if(gameInfo.variant == VariantGothic) {
1604 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1610 for(i=0; i<2; i++) {
1612 for(p=0; p<=(int)WhiteKing; p++)
1613 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1614 if(gameInfo.variant == VariantShogi) {
1615 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1616 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1617 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1618 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1619 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1622 if(gameInfo.variant == VariantGothic) {
1623 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1634 void EscapeExpand(char *p, char *q)
1635 { // [HGM] initstring: routine to shape up string arguments
1636 while(*p++ = *q++) if(p[-1] == '\\')
1638 case 'n': p[-1] = '\n'; break;
1639 case 'r': p[-1] = '\r'; break;
1640 case 't': p[-1] = '\t'; break;
1641 case '\\': p[-1] = '\\'; break;
1642 case 0: *p = 0; return;
1643 default: p[-1] = q[-1]; break;
1652 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1653 XSetWindowAttributes window_attributes;
1655 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1656 XrmValue vFrom, vTo;
1657 XtGeometryResult gres;
1660 int forceMono = False;
1661 //define INDIRECTION
1663 // [HGM] before anything else, expand any indirection files amongst options
1664 char *argvCopy[1000]; // 1000 seems enough
1665 char newArgs[10000]; // holds actual characters
1668 srandom(time(0)); // [HGM] book: make random truly random
1671 for(i=0; i<argc; i++) {
1672 if(j >= 1000-2) { printf(_("too many arguments\n")); exit(-1); }
1673 //fprintf(stderr, "arg %s\n", argv[i]);
1674 if(argv[i][0] != '@') argvCopy[j++] = argv[i]; else {
1676 FILE *f = fopen(argv[i]+1, "rb");
1677 if(f == NULL) { fprintf(stderr, _("ignore %s\n"), argv[i]); continue; } // do not expand non-existing
1678 argvCopy[j++] = newArgs + k; // get ready for first argument from file
1679 while((c = fgetc(f)) != EOF) { // each line of file inserts 1 argument in the list
1681 if(j >= 1000-2) { printf(_("too many arguments\n")); exit(-1); }
1682 newArgs[k++] = 0; // terminate current arg
1683 if(k >= 10000-1) { printf(_("too long arguments\n")); exit(-1); }
1684 argvCopy[j++] = newArgs + k; // get ready for next
1686 if(k >= 10000-1) { printf(_("too long arguments\n")); exit(-1); }
1700 setbuf(stdout, NULL);
1701 setbuf(stderr, NULL);
1704 programName = strrchr(argv[0], '/');
1705 if (programName == NULL)
1706 programName = argv[0];
1711 XtSetLanguageProc(NULL, NULL, NULL);
1712 bindtextdomain(PACKAGE, LOCALEDIR);
1713 textdomain(PACKAGE);
1717 XtAppInitialize(&appContext, "XBoard", shellOptions,
1718 XtNumber(shellOptions),
1719 &argc, argv, xboardResources, NULL, 0);
1720 appData.boardSize = "";
1721 InitAppData(ConvertToLine(argc, argv));
1723 if (p == NULL) p = "/tmp";
1724 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1725 gameCopyFilename = (char*) malloc(i);
1726 gamePasteFilename = (char*) malloc(i);
1727 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1728 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1730 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1731 clientResources, XtNumber(clientResources),
1734 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1735 static char buf[MSG_SIZ];
1736 EscapeExpand(buf, appData.initString);
1737 appData.initString = strdup(buf);
1738 EscapeExpand(buf, appData.secondInitString);
1739 appData.secondInitString = strdup(buf);
1740 EscapeExpand(buf, appData.firstComputerString);
1741 appData.firstComputerString = strdup(buf);
1742 EscapeExpand(buf, appData.secondComputerString);
1743 appData.secondComputerString = strdup(buf);
1746 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1749 if (chdir(chessDir) != 0) {
1750 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1756 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1757 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1758 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1759 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1762 setbuf(debugFP, NULL);
1765 /* [HGM,HR] make sure board size is acceptable */
1766 if(appData.NrFiles > BOARD_FILES ||
1767 appData.NrRanks > BOARD_RANKS )
1768 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1771 /* This feature does not work; animation needs a rewrite */
1772 appData.highlightDragging = FALSE;
1776 xDisplay = XtDisplay(shellWidget);
1777 xScreen = DefaultScreen(xDisplay);
1778 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1780 gameInfo.variant = StringToVariant(appData.variant);
1781 InitPosition(FALSE);
1784 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1786 if (isdigit(appData.boardSize[0])) {
1787 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1788 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1789 &fontPxlSize, &smallLayout, &tinyLayout);
1791 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1792 programName, appData.boardSize);
1796 /* Find some defaults; use the nearest known size */
1797 SizeDefaults *szd, *nearest;
1798 int distance = 99999;
1799 nearest = szd = sizeDefaults;
1800 while (szd->name != NULL) {
1801 if (abs(szd->squareSize - squareSize) < distance) {
1803 distance = abs(szd->squareSize - squareSize);
1804 if (distance == 0) break;
1808 if (i < 2) lineGap = nearest->lineGap;
1809 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1810 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1811 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1812 if (i < 6) smallLayout = nearest->smallLayout;
1813 if (i < 7) tinyLayout = nearest->tinyLayout;
1816 SizeDefaults *szd = sizeDefaults;
1817 if (*appData.boardSize == NULLCHAR) {
1818 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1819 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1822 if (szd->name == NULL) szd--;
1823 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1825 while (szd->name != NULL &&
1826 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1827 if (szd->name == NULL) {
1828 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1829 programName, appData.boardSize);
1833 squareSize = szd->squareSize;
1834 lineGap = szd->lineGap;
1835 clockFontPxlSize = szd->clockFontPxlSize;
1836 coordFontPxlSize = szd->coordFontPxlSize;
1837 fontPxlSize = szd->fontPxlSize;
1838 smallLayout = szd->smallLayout;
1839 tinyLayout = szd->tinyLayout;
1842 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1843 if (strlen(appData.pixmapDirectory) > 0) {
1844 p = ExpandPathName(appData.pixmapDirectory);
1846 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1847 appData.pixmapDirectory);
1850 if (appData.debugMode) {
1851 fprintf(stderr, _("\
1852 XBoard square size (hint): %d\n\
1853 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1855 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1856 if (appData.debugMode) {
1857 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1861 /* [HR] height treated separately (hacked) */
1862 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1863 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1864 if (appData.showJail == 1) {
1865 /* Jail on top and bottom */
1866 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1867 XtSetArg(boardArgs[2], XtNheight,
1868 boardHeight + 2*(lineGap + squareSize));
1869 } else if (appData.showJail == 2) {
1871 XtSetArg(boardArgs[1], XtNwidth,
1872 boardWidth + 2*(lineGap + squareSize));
1873 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1876 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1877 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1881 * Determine what fonts to use.
1883 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1884 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1885 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1886 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1887 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1888 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1889 appData.font = FindFont(appData.font, fontPxlSize);
1890 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1891 countFontStruct = XQueryFont(xDisplay, countFontID);
1892 // appData.font = FindFont(appData.font, fontPxlSize);
1894 xdb = XtDatabase(xDisplay);
1895 XrmPutStringResource(&xdb, "*font", appData.font);
1898 * Detect if there are not enough colors available and adapt.
1900 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1901 appData.monoMode = True;
1904 if (!appData.monoMode) {
1905 vFrom.addr = (caddr_t) appData.lightSquareColor;
1906 vFrom.size = strlen(appData.lightSquareColor);
1907 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1908 if (vTo.addr == NULL) {
1909 appData.monoMode = True;
1912 lightSquareColor = *(Pixel *) vTo.addr;
1915 if (!appData.monoMode) {
1916 vFrom.addr = (caddr_t) appData.darkSquareColor;
1917 vFrom.size = strlen(appData.darkSquareColor);
1918 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1919 if (vTo.addr == NULL) {
1920 appData.monoMode = True;
1923 darkSquareColor = *(Pixel *) vTo.addr;
1926 if (!appData.monoMode) {
1927 vFrom.addr = (caddr_t) appData.whitePieceColor;
1928 vFrom.size = strlen(appData.whitePieceColor);
1929 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1930 if (vTo.addr == NULL) {
1931 appData.monoMode = True;
1934 whitePieceColor = *(Pixel *) vTo.addr;
1937 if (!appData.monoMode) {
1938 vFrom.addr = (caddr_t) appData.blackPieceColor;
1939 vFrom.size = strlen(appData.blackPieceColor);
1940 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1941 if (vTo.addr == NULL) {
1942 appData.monoMode = True;
1945 blackPieceColor = *(Pixel *) vTo.addr;
1949 if (!appData.monoMode) {
1950 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1951 vFrom.size = strlen(appData.highlightSquareColor);
1952 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1953 if (vTo.addr == NULL) {
1954 appData.monoMode = True;
1957 highlightSquareColor = *(Pixel *) vTo.addr;
1961 if (!appData.monoMode) {
1962 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1963 vFrom.size = strlen(appData.premoveHighlightColor);
1964 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1965 if (vTo.addr == NULL) {
1966 appData.monoMode = True;
1969 premoveHighlightColor = *(Pixel *) vTo.addr;
1974 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1977 if (appData.bitmapDirectory == NULL ||
1978 appData.bitmapDirectory[0] == NULLCHAR)
1979 appData.bitmapDirectory = DEF_BITMAP_DIR;
1982 if (appData.lowTimeWarning && !appData.monoMode) {
1983 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
1984 vFrom.size = strlen(appData.lowTimeWarningColor);
1985 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1986 if (vTo.addr == NULL)
1987 appData.monoMode = True;
1989 lowTimeWarningColor = *(Pixel *) vTo.addr;
1992 if (appData.monoMode && appData.debugMode) {
1993 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1994 (unsigned long) XWhitePixel(xDisplay, xScreen),
1995 (unsigned long) XBlackPixel(xDisplay, xScreen));
1998 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1999 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2000 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2001 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2002 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2003 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2004 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2005 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2006 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2007 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2009 if (appData.colorize) {
2011 _("%s: can't parse color names; disabling colorization\n"),
2014 appData.colorize = FALSE;
2016 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2017 textColors[ColorNone].attr = 0;
2019 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2025 layoutName = "tinyLayout";
2026 } else if (smallLayout) {
2027 layoutName = "smallLayout";
2029 layoutName = "normalLayout";
2031 /* Outer layoutWidget is there only to provide a name for use in
2032 resources that depend on the layout style */
2034 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2035 layoutArgs, XtNumber(layoutArgs));
2037 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2038 formArgs, XtNumber(formArgs));
2039 XtSetArg(args[0], XtNdefaultDistance, &sep);
2040 XtGetValues(formWidget, args, 1);
2043 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2044 XtSetArg(args[0], XtNtop, XtChainTop);
2045 XtSetArg(args[1], XtNbottom, XtChainTop);
2046 XtSetArg(args[2], XtNright, XtChainLeft);
2047 XtSetValues(menuBarWidget, args, 3);
2049 widgetList[j++] = whiteTimerWidget =
2050 XtCreateWidget("whiteTime", labelWidgetClass,
2051 formWidget, timerArgs, XtNumber(timerArgs));
2052 XtSetArg(args[0], XtNfont, clockFontStruct);
2053 XtSetArg(args[1], XtNtop, XtChainTop);
2054 XtSetArg(args[2], XtNbottom, XtChainTop);
2055 XtSetValues(whiteTimerWidget, args, 3);
2057 widgetList[j++] = blackTimerWidget =
2058 XtCreateWidget("blackTime", labelWidgetClass,
2059 formWidget, timerArgs, XtNumber(timerArgs));
2060 XtSetArg(args[0], XtNfont, clockFontStruct);
2061 XtSetArg(args[1], XtNtop, XtChainTop);
2062 XtSetArg(args[2], XtNbottom, XtChainTop);
2063 XtSetValues(blackTimerWidget, args, 3);
2065 if (appData.titleInWindow) {
2066 widgetList[j++] = titleWidget =
2067 XtCreateWidget("title", labelWidgetClass, formWidget,
2068 titleArgs, XtNumber(titleArgs));
2069 XtSetArg(args[0], XtNtop, XtChainTop);
2070 XtSetArg(args[1], XtNbottom, XtChainTop);
2071 XtSetValues(titleWidget, args, 2);
2074 if (appData.showButtonBar) {
2075 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2076 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2077 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2078 XtSetArg(args[2], XtNtop, XtChainTop);
2079 XtSetArg(args[3], XtNbottom, XtChainTop);
2080 XtSetValues(buttonBarWidget, args, 4);
2083 widgetList[j++] = messageWidget =
2084 XtCreateWidget("message", labelWidgetClass, formWidget,
2085 messageArgs, XtNumber(messageArgs));
2086 XtSetArg(args[0], XtNtop, XtChainTop);
2087 XtSetArg(args[1], XtNbottom, XtChainTop);
2088 XtSetValues(messageWidget, args, 2);
2090 widgetList[j++] = boardWidget =
2091 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2092 XtNumber(boardArgs));
2094 XtManageChildren(widgetList, j);
2096 timerWidth = (boardWidth - sep) / 2;
2097 XtSetArg(args[0], XtNwidth, timerWidth);
2098 XtSetValues(whiteTimerWidget, args, 1);
2099 XtSetValues(blackTimerWidget, args, 1);
2101 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2102 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2103 XtGetValues(whiteTimerWidget, args, 2);
2105 if (appData.showButtonBar) {
2106 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2107 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2108 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2112 * formWidget uses these constraints but they are stored
2116 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2117 XtSetValues(menuBarWidget, args, i);
2118 if (appData.titleInWindow) {
2121 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2122 XtSetValues(whiteTimerWidget, args, i);
2124 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2125 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2126 XtSetValues(blackTimerWidget, args, i);
2128 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2129 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2130 XtSetValues(titleWidget, args, i);
2132 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2133 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2134 XtSetValues(messageWidget, args, i);
2135 if (appData.showButtonBar) {
2137 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2138 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2139 XtSetValues(buttonBarWidget, args, i);
2143 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2144 XtSetValues(whiteTimerWidget, args, i);
2146 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2147 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2148 XtSetValues(blackTimerWidget, args, i);
2150 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2151 XtSetValues(titleWidget, args, i);
2153 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2154 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2155 XtSetValues(messageWidget, args, i);
2156 if (appData.showButtonBar) {
2158 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2159 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2160 XtSetValues(buttonBarWidget, args, i);
2165 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2166 XtSetValues(whiteTimerWidget, args, i);
2168 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2169 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2170 XtSetValues(blackTimerWidget, args, i);
2172 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2173 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2174 XtSetValues(messageWidget, args, i);
2175 if (appData.showButtonBar) {
2177 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2178 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2179 XtSetValues(buttonBarWidget, args, i);
2183 XtSetArg(args[0], XtNfromVert, messageWidget);
2184 XtSetArg(args[1], XtNtop, XtChainTop);
2185 XtSetArg(args[2], XtNbottom, XtChainBottom);
2186 XtSetArg(args[3], XtNleft, XtChainLeft);
2187 XtSetArg(args[4], XtNright, XtChainRight);
2188 XtSetValues(boardWidget, args, 5);
2190 XtRealizeWidget(shellWidget);
2193 XtSetArg(args[0], XtNx, wpMain.x);
2194 XtSetArg(args[1], XtNy, wpMain.y);
2195 XtSetValues(shellWidget, args, 2);
2199 * Correct the width of the message and title widgets.
2200 * It is not known why some systems need the extra fudge term.
2201 * The value "2" is probably larger than needed.
2203 XawFormDoLayout(formWidget, False);
2205 #define WIDTH_FUDGE 2
2207 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2208 XtSetArg(args[i], XtNheight, &h); i++;
2209 XtGetValues(messageWidget, args, i);
2210 if (appData.showButtonBar) {
2212 XtSetArg(args[i], XtNwidth, &w); i++;
2213 XtGetValues(buttonBarWidget, args, i);
2214 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2216 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2219 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2220 if (gres != XtGeometryYes && appData.debugMode) {
2221 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2222 programName, gres, w, h, wr, hr);
2225 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2226 /* The size used for the child widget in layout lags one resize behind
2227 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2229 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2230 if (gres != XtGeometryYes && appData.debugMode) {
2231 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2232 programName, gres, w, h, wr, hr);
2235 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2236 XtSetArg(args[1], XtNright, XtChainRight);
2237 XtSetValues(messageWidget, args, 2);
2239 if (appData.titleInWindow) {
2241 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2242 XtSetArg(args[i], XtNheight, &h); i++;
2243 XtGetValues(titleWidget, args, i);
2245 w = boardWidth - 2*bor;
2247 XtSetArg(args[0], XtNwidth, &w);
2248 XtGetValues(menuBarWidget, args, 1);
2249 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2252 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2253 if (gres != XtGeometryYes && appData.debugMode) {
2255 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2256 programName, gres, w, h, wr, hr);
2259 XawFormDoLayout(formWidget, True);
2261 xBoardWindow = XtWindow(boardWidget);
2263 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2264 // not need to go into InitDrawingSizes().
2268 * Create X checkmark bitmap and initialize option menu checks.
2270 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2271 checkmark_bits, checkmark_width, checkmark_height);
2272 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2273 if (appData.alwaysPromoteToQueen) {
2274 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2277 if (appData.animateDragging) {
2278 XtSetValues(XtNameToWidget(menuBarWidget,
2279 "menuOptions.Animate Dragging"),
2282 if (appData.animate) {
2283 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2286 if (appData.autoComment) {
2287 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2290 if (appData.autoCallFlag) {
2291 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2294 if (appData.autoFlipView) {
2295 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2298 if (appData.autoObserve) {
2299 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2302 if (appData.autoRaiseBoard) {
2303 XtSetValues(XtNameToWidget(menuBarWidget,
2304 "menuOptions.Auto Raise Board"), args, 1);
2306 if (appData.autoSaveGames) {
2307 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2310 if (appData.saveGameFile[0] != NULLCHAR) {
2311 /* Can't turn this off from menu */
2312 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2314 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2318 if (appData.blindfold) {
2319 XtSetValues(XtNameToWidget(menuBarWidget,
2320 "menuOptions.Blindfold"), args, 1);
2322 if (appData.flashCount > 0) {
2323 XtSetValues(XtNameToWidget(menuBarWidget,
2324 "menuOptions.Flash Moves"),
2327 if (appData.getMoveList) {
2328 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2332 if (appData.highlightDragging) {
2333 XtSetValues(XtNameToWidget(menuBarWidget,
2334 "menuOptions.Highlight Dragging"),
2338 if (appData.highlightLastMove) {
2339 XtSetValues(XtNameToWidget(menuBarWidget,
2340 "menuOptions.Highlight Last Move"),
2343 if (appData.icsAlarm) {
2344 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2347 if (appData.ringBellAfterMoves) {
2348 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2351 if (appData.oldSaveStyle) {
2352 XtSetValues(XtNameToWidget(menuBarWidget,
2353 "menuOptions.Old Save Style"), args, 1);
2355 if (appData.periodicUpdates) {
2356 XtSetValues(XtNameToWidget(menuBarWidget,
2357 "menuOptions.Periodic Updates"), args, 1);
2359 if (appData.ponderNextMove) {
2360 XtSetValues(XtNameToWidget(menuBarWidget,
2361 "menuOptions.Ponder Next Move"), args, 1);
2363 if (appData.popupExitMessage) {
2364 XtSetValues(XtNameToWidget(menuBarWidget,
2365 "menuOptions.Popup Exit Message"), args, 1);
2367 if (appData.popupMoveErrors) {
2368 XtSetValues(XtNameToWidget(menuBarWidget,
2369 "menuOptions.Popup Move Errors"), args, 1);
2371 if (appData.premove) {
2372 XtSetValues(XtNameToWidget(menuBarWidget,
2373 "menuOptions.Premove"), args, 1);
2375 if (appData.quietPlay) {
2376 XtSetValues(XtNameToWidget(menuBarWidget,
2377 "menuOptions.Quiet Play"), args, 1);
2379 if (appData.showCoords) {
2380 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2383 if (appData.hideThinkingFromHuman) {
2384 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2387 if (appData.testLegality) {
2388 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2391 if (saveSettingsOnExit) {
2392 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2399 ReadBitmap(&wIconPixmap, "icon_white.bm",
2400 icon_white_bits, icon_white_width, icon_white_height);
2401 ReadBitmap(&bIconPixmap, "icon_black.bm",
2402 icon_black_bits, icon_black_width, icon_black_height);
2403 iconPixmap = wIconPixmap;
2405 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2406 XtSetValues(shellWidget, args, i);
2409 * Create a cursor for the board widget.
2411 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2412 XChangeWindowAttributes(xDisplay, xBoardWindow,
2413 CWCursor, &window_attributes);
2416 * Inhibit shell resizing.
2418 shellArgs[0].value = (XtArgVal) &w;
2419 shellArgs[1].value = (XtArgVal) &h;
2420 XtGetValues(shellWidget, shellArgs, 2);
2421 shellArgs[4].value = shellArgs[2].value = w;
2422 shellArgs[5].value = shellArgs[3].value = h;
2423 XtSetValues(shellWidget, &shellArgs[2], 4);
2424 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2425 marginH = h - boardHeight;
2427 CatchDeleteWindow(shellWidget, "QuitProc");
2432 if (appData.bitmapDirectory[0] != NULLCHAR) {
2439 /* Create regular pieces */
2440 if (!useImages) CreatePieces();
2445 if (appData.animate || appData.animateDragging)
2448 XtAugmentTranslations(formWidget,
2449 XtParseTranslationTable(globalTranslations));
2450 XtAugmentTranslations(boardWidget,
2451 XtParseTranslationTable(boardTranslations));
2452 XtAugmentTranslations(whiteTimerWidget,
2453 XtParseTranslationTable(whiteTranslations));
2454 XtAugmentTranslations(blackTimerWidget,
2455 XtParseTranslationTable(blackTranslations));
2457 /* Why is the following needed on some versions of X instead
2458 * of a translation? */
2459 XtAddEventHandler(boardWidget, ExposureMask, False,
2460 (XtEventHandler) EventProc, NULL);
2463 /* [AS] Restore layout */
2464 if( wpMoveHistory.visible ) {
2468 if( wpEvalGraph.visible )
2473 if( wpEngineOutput.visible ) {
2474 EngineOutputPopUp();
2479 if (errorExitStatus == -1) {
2480 if (appData.icsActive) {
2481 /* We now wait until we see "login:" from the ICS before
2482 sending the logon script (problems with timestamp otherwise) */
2483 /*ICSInitScript();*/
2484 if (appData.icsInputBox) ICSInputBoxPopUp();
2488 signal(SIGWINCH, TermSizeSigHandler);
2490 signal(SIGINT, IntSigHandler);
2491 signal(SIGTERM, IntSigHandler);
2492 if (*appData.cmailGameName != NULLCHAR) {
2493 signal(SIGUSR1, CmailSigHandler);
2496 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2499 XtAppMainLoop(appContext);
2500 if (appData.debugMode) fclose(debugFP); // [DM] debug
2507 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2508 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2510 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2511 unlink(gameCopyFilename);
2512 unlink(gamePasteFilename);
2515 RETSIGTYPE TermSizeSigHandler(int sig)
2528 CmailSigHandler(sig)
2534 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2536 /* Activate call-back function CmailSigHandlerCallBack() */
2537 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2539 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2543 CmailSigHandlerCallBack(isr, closure, message, count, error)
2551 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2553 /**** end signal code ****/
2563 f = fopen(appData.icsLogon, "r");
2569 strcat(buf, appData.icsLogon);
2570 f = fopen(buf, "r");
2574 ProcessICSInitScript(f);
2581 EditCommentPopDown();
2596 if (!menuBarWidget) return;
2597 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2599 DisplayError("menuStep.Revert", 0);
2601 XtSetSensitive(w, !grey);
2606 SetMenuEnables(enab)
2610 if (!menuBarWidget) return;
2611 while (enab->name != NULL) {
2612 w = XtNameToWidget(menuBarWidget, enab->name);
2614 DisplayError(enab->name, 0);
2616 XtSetSensitive(w, enab->value);
2622 Enables icsEnables[] = {
2623 { "menuFile.Mail Move", False },
2624 { "menuFile.Reload CMail Message", False },
2625 { "menuMode.Machine Black", False },
2626 { "menuMode.Machine White", False },
2627 { "menuMode.Analysis Mode", False },
2628 { "menuMode.Analyze File", False },
2629 { "menuMode.Two Machines", False },
2631 { "menuHelp.Hint", False },
2632 { "menuHelp.Book", False },
2633 { "menuStep.Move Now", False },
2634 { "menuOptions.Periodic Updates", False },
2635 { "menuOptions.Hide Thinking", False },
2636 { "menuOptions.Ponder Next Move", False },
2641 Enables ncpEnables[] = {
2642 { "menuFile.Mail Move", False },
2643 { "menuFile.Reload CMail Message", False },
2644 { "menuMode.Machine White", False },
2645 { "menuMode.Machine Black", False },
2646 { "menuMode.Analysis Mode", False },
2647 { "menuMode.Analyze File", False },
2648 { "menuMode.Two Machines", False },
2649 { "menuMode.ICS Client", False },
2650 { "menuMode.ICS Input Box", False },
2651 { "Action", False },
2652 { "menuStep.Revert", False },
2653 { "menuStep.Move Now", False },
2654 { "menuStep.Retract Move", False },
2655 { "menuOptions.Auto Comment", False },
2656 { "menuOptions.Auto Flag", False },
2657 { "menuOptions.Auto Flip View", False },
2658 { "menuOptions.Auto Observe", False },
2659 { "menuOptions.Auto Raise Board", False },
2660 { "menuOptions.Get Move List", False },
2661 { "menuOptions.ICS Alarm", False },
2662 { "menuOptions.Move Sound", False },
2663 { "menuOptions.Quiet Play", False },
2664 { "menuOptions.Hide Thinking", False },
2665 { "menuOptions.Periodic Updates", False },
2666 { "menuOptions.Ponder Next Move", False },
2667 { "menuHelp.Hint", False },
2668 { "menuHelp.Book", False },
2672 Enables gnuEnables[] = {
2673 { "menuMode.ICS Client", False },
2674 { "menuMode.ICS Input Box", False },
2675 { "menuAction.Accept", False },
2676 { "menuAction.Decline", False },
2677 { "menuAction.Rematch", False },
2678 { "menuAction.Adjourn", False },
2679 { "menuAction.Stop Examining", False },
2680 { "menuAction.Stop Observing", False },
2681 { "menuStep.Revert", False },
2682 { "menuOptions.Auto Comment", False },
2683 { "menuOptions.Auto Observe", False },
2684 { "menuOptions.Auto Raise Board", False },
2685 { "menuOptions.Get Move List", False },
2686 { "menuOptions.Premove", False },
2687 { "menuOptions.Quiet Play", False },
2689 /* The next two options rely on SetCmailMode being called *after* */
2690 /* SetGNUMode so that when GNU is being used to give hints these */
2691 /* menu options are still available */
2693 { "menuFile.Mail Move", False },
2694 { "menuFile.Reload CMail Message", False },
2698 Enables cmailEnables[] = {
2700 { "menuAction.Call Flag", False },
2701 { "menuAction.Draw", True },
2702 { "menuAction.Adjourn", False },
2703 { "menuAction.Abort", False },
2704 { "menuAction.Stop Observing", False },
2705 { "menuAction.Stop Examining", False },
2706 { "menuFile.Mail Move", True },
2707 { "menuFile.Reload CMail Message", True },
2711 Enables trainingOnEnables[] = {
2712 { "menuMode.Edit Comment", False },
2713 { "menuMode.Pause", False },
2714 { "menuStep.Forward", False },
2715 { "menuStep.Backward", False },
2716 { "menuStep.Forward to End", False },
2717 { "menuStep.Back to Start", False },
2718 { "menuStep.Move Now", False },
2719 { "menuStep.Truncate Game", False },
2723 Enables trainingOffEnables[] = {
2724 { "menuMode.Edit Comment", True },
2725 { "menuMode.Pause", True },
2726 { "menuStep.Forward", True },
2727 { "menuStep.Backward", True },
2728 { "menuStep.Forward to End", True },
2729 { "menuStep.Back to Start", True },
2730 { "menuStep.Move Now", True },
2731 { "menuStep.Truncate Game", True },
2735 Enables machineThinkingEnables[] = {
2736 { "menuFile.Load Game", False },
2737 { "menuFile.Load Next Game", False },
2738 { "menuFile.Load Previous Game", False },
2739 { "menuFile.Reload Same Game", False },
2740 { "menuFile.Paste Game", False },
2741 { "menuFile.Load Position", False },
2742 { "menuFile.Load Next Position", False },
2743 { "menuFile.Load Previous Position", False },
2744 { "menuFile.Reload Same Position", False },
2745 { "menuFile.Paste Position", False },
2746 { "menuMode.Machine White", False },
2747 { "menuMode.Machine Black", False },
2748 { "menuMode.Two Machines", False },
2749 { "menuStep.Retract Move", False },
2753 Enables userThinkingEnables[] = {
2754 { "menuFile.Load Game", True },
2755 { "menuFile.Load Next Game", True },
2756 { "menuFile.Load Previous Game", True },
2757 { "menuFile.Reload Same Game", True },
2758 { "menuFile.Paste Game", True },
2759 { "menuFile.Load Position", True },
2760 { "menuFile.Load Next Position", True },
2761 { "menuFile.Load Previous Position", True },
2762 { "menuFile.Reload Same Position", True },
2763 { "menuFile.Paste Position", True },
2764 { "menuMode.Machine White", True },
2765 { "menuMode.Machine Black", True },
2766 { "menuMode.Two Machines", True },
2767 { "menuStep.Retract Move", True },
2773 SetMenuEnables(icsEnables);
2776 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2777 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2784 SetMenuEnables(ncpEnables);
2790 SetMenuEnables(gnuEnables);
2796 SetMenuEnables(cmailEnables);
2802 SetMenuEnables(trainingOnEnables);
2803 if (appData.showButtonBar) {
2804 XtSetSensitive(buttonBarWidget, False);
2810 SetTrainingModeOff()
2812 SetMenuEnables(trainingOffEnables);
2813 if (appData.showButtonBar) {
2814 XtSetSensitive(buttonBarWidget, True);
2819 SetUserThinkingEnables()
2821 if (appData.noChessProgram) return;
2822 SetMenuEnables(userThinkingEnables);
2826 SetMachineThinkingEnables()
2828 if (appData.noChessProgram) return;
2829 SetMenuEnables(machineThinkingEnables);
2831 case MachinePlaysBlack:
2832 case MachinePlaysWhite:
2833 case TwoMachinesPlay:
2834 XtSetSensitive(XtNameToWidget(menuBarWidget,
2835 ModeToWidgetName(gameMode)), True);
2842 #define Abs(n) ((n)<0 ? -(n) : (n))
2845 * Find a font that matches "pattern" that is as close as
2846 * possible to the targetPxlSize. Prefer fonts that are k
2847 * pixels smaller to fonts that are k pixels larger. The
2848 * pattern must be in the X Consortium standard format,
2849 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2850 * The return value should be freed with XtFree when no
2853 char *FindFont(pattern, targetPxlSize)
2857 char **fonts, *p, *best, *scalable, *scalableTail;
2858 int i, j, nfonts, minerr, err, pxlSize;
2861 char **missing_list;
2863 char *def_string, *base_fnt_lst, strInt[3];
2865 XFontStruct **fnt_list;
2867 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2868 sprintf(strInt, "%d", targetPxlSize);
2869 p = strstr(pattern, "--");
2870 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2871 strcat(base_fnt_lst, strInt);
2872 strcat(base_fnt_lst, strchr(p + 2, '-'));
2874 if ((fntSet = XCreateFontSet(xDisplay,
2878 &def_string)) == NULL) {
2880 fprintf(stderr, _("Unable to create font set.\n"));
2884 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2886 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2888 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2889 programName, pattern);
2897 for (i=0; i<nfonts; i++) {
2900 if (*p != '-') continue;
2902 if (*p == NULLCHAR) break;
2903 if (*p++ == '-') j++;
2905 if (j < 7) continue;
2908 scalable = fonts[i];
2911 err = pxlSize - targetPxlSize;
2912 if (Abs(err) < Abs(minerr) ||
2913 (minerr > 0 && err < 0 && -err == minerr)) {
2919 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
2920 /* If the error is too big and there is a scalable font,
2921 use the scalable font. */
2922 int headlen = scalableTail - scalable;
2923 p = (char *) XtMalloc(strlen(scalable) + 10);
2924 while (isdigit(*scalableTail)) scalableTail++;
2925 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
2927 p = (char *) XtMalloc(strlen(best) + 1);
2930 if (appData.debugMode) {
2931 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
2932 pattern, targetPxlSize, p);
2935 if (missing_count > 0)
2936 XFreeStringList(missing_list);
2937 XFreeFontSet(xDisplay, fntSet);
2939 XFreeFontNames(fonts);
2946 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
2947 | GCBackground | GCFunction | GCPlaneMask;
2948 XGCValues gc_values;
2951 gc_values.plane_mask = AllPlanes;
2952 gc_values.line_width = lineGap;
2953 gc_values.line_style = LineSolid;
2954 gc_values.function = GXcopy;
2956 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2957 gc_values.background = XBlackPixel(xDisplay, xScreen);
2958 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2960 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2961 gc_values.background = XWhitePixel(xDisplay, xScreen);
2962 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
2963 XSetFont(xDisplay, coordGC, coordFontID);
2965 // [HGM] make font for holdings counts (white on black0
2966 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2967 gc_values.background = XBlackPixel(xDisplay, xScreen);
2968 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
2969 XSetFont(xDisplay, countGC, countFontID);
2971 if (appData.monoMode) {
2972 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2973 gc_values.background = XWhitePixel(xDisplay, xScreen);
2974 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2976 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2977 gc_values.background = XBlackPixel(xDisplay, xScreen);
2978 lightSquareGC = wbPieceGC
2979 = XtGetGC(shellWidget, value_mask, &gc_values);
2981 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2982 gc_values.background = XWhitePixel(xDisplay, xScreen);
2983 darkSquareGC = bwPieceGC
2984 = XtGetGC(shellWidget, value_mask, &gc_values);
2986 if (DefaultDepth(xDisplay, xScreen) == 1) {
2987 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
2988 gc_values.function = GXcopyInverted;
2989 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
2990 gc_values.function = GXcopy;
2991 if (XBlackPixel(xDisplay, xScreen) == 1) {
2992 bwPieceGC = darkSquareGC;
2993 wbPieceGC = copyInvertedGC;
2995 bwPieceGC = copyInvertedGC;
2996 wbPieceGC = lightSquareGC;
3000 gc_values.foreground = highlightSquareColor;
3001 gc_values.background = highlightSquareColor;
3002 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3004 gc_values.foreground = premoveHighlightColor;
3005 gc_values.background = premoveHighlightColor;
3006 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3008 gc_values.foreground = lightSquareColor;
3009 gc_values.background = darkSquareColor;
3010 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3012 gc_values.foreground = darkSquareColor;
3013 gc_values.background = lightSquareColor;
3014 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3016 gc_values.foreground = jailSquareColor;
3017 gc_values.background = jailSquareColor;
3018 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3020 gc_values.foreground = whitePieceColor;
3021 gc_values.background = darkSquareColor;
3022 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3024 gc_values.foreground = whitePieceColor;
3025 gc_values.background = lightSquareColor;
3026 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3028 gc_values.foreground = whitePieceColor;
3029 gc_values.background = jailSquareColor;
3030 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3032 gc_values.foreground = blackPieceColor;
3033 gc_values.background = darkSquareColor;
3034 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3036 gc_values.foreground = blackPieceColor;
3037 gc_values.background = lightSquareColor;
3038 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3040 gc_values.foreground = blackPieceColor;
3041 gc_values.background = jailSquareColor;
3042 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3046 void loadXIM(xim, xmask, filename, dest, mask)
3059 fp = fopen(filename, "rb");
3061 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3068 for (y=0; y<h; ++y) {
3069 for (x=0; x<h; ++x) {
3074 XPutPixel(xim, x, y, blackPieceColor);
3076 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3079 XPutPixel(xim, x, y, darkSquareColor);
3081 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3084 XPutPixel(xim, x, y, whitePieceColor);
3086 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3089 XPutPixel(xim, x, y, lightSquareColor);
3091 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3097 /* create Pixmap of piece */
3098 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3100 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3103 /* create Pixmap of clipmask
3104 Note: We assume the white/black pieces have the same
3105 outline, so we make only 6 masks. This is okay
3106 since the XPM clipmask routines do the same. */
3108 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3110 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3113 /* now create the 1-bit version */
3114 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3117 values.foreground = 1;
3118 values.background = 0;
3120 /* Don't use XtGetGC, not read only */
3121 maskGC = XCreateGC(xDisplay, *mask,
3122 GCForeground | GCBackground, &values);
3123 XCopyPlane(xDisplay, temp, *mask, maskGC,
3124 0, 0, squareSize, squareSize, 0, 0, 1);
3125 XFreePixmap(xDisplay, temp);
3130 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3132 void CreateXIMPieces()
3137 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3142 /* The XSynchronize calls were copied from CreatePieces.
3143 Not sure if needed, but can't hurt */
3144 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3147 /* temp needed by loadXIM() */
3148 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3149 0, 0, ss, ss, AllPlanes, XYPixmap);
3151 if (strlen(appData.pixmapDirectory) == 0) {
3155 if (appData.monoMode) {
3156 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3160 fprintf(stderr, _("\nLoading XIMs...\n"));
3162 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3163 fprintf(stderr, "%d", piece+1);
3164 for (kind=0; kind<4; kind++) {
3165 fprintf(stderr, ".");
3166 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3167 ExpandPathName(appData.pixmapDirectory),
3168 piece <= (int) WhiteKing ? "" : "w",
3169 pieceBitmapNames[piece],
3171 ximPieceBitmap[kind][piece] =
3172 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3173 0, 0, ss, ss, AllPlanes, XYPixmap);
3174 if (appData.debugMode)
3175 fprintf(stderr, _("(File:%s:) "), buf);
3176 loadXIM(ximPieceBitmap[kind][piece],
3178 &(xpmPieceBitmap2[kind][piece]),
3179 &(ximMaskPm2[piece]));
3180 if(piece <= (int)WhiteKing)
3181 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3183 fprintf(stderr," ");
3185 /* Load light and dark squares */
3186 /* If the LSQ and DSQ pieces don't exist, we will
3187 draw them with solid squares. */
3188 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3189 if (access(buf, 0) != 0) {
3193 fprintf(stderr, _("light square "));
3195 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3196 0, 0, ss, ss, AllPlanes, XYPixmap);
3197 if (appData.debugMode)
3198 fprintf(stderr, _("(File:%s:) "), buf);
3200 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3201 fprintf(stderr, _("dark square "));
3202 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3203 ExpandPathName(appData.pixmapDirectory), ss);
3204 if (appData.debugMode)
3205 fprintf(stderr, _("(File:%s:) "), buf);
3207 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3208 0, 0, ss, ss, AllPlanes, XYPixmap);
3209 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3210 xpmJailSquare = xpmLightSquare;
3212 fprintf(stderr, _("Done.\n"));
3214 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3218 void CreateXPMPieces()
3222 u_int ss = squareSize;
3224 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3225 XpmColorSymbol symbols[4];
3227 /* The XSynchronize calls were copied from CreatePieces.
3228 Not sure if needed, but can't hurt */
3229 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3231 /* Setup translations so piece colors match square colors */
3232 symbols[0].name = "light_piece";
3233 symbols[0].value = appData.whitePieceColor;
3234 symbols[1].name = "dark_piece";
3235 symbols[1].value = appData.blackPieceColor;
3236 symbols[2].name = "light_square";
3237 symbols[2].value = appData.lightSquareColor;
3238 symbols[3].name = "dark_square";
3239 symbols[3].value = appData.darkSquareColor;
3241 attr.valuemask = XpmColorSymbols;
3242 attr.colorsymbols = symbols;
3243 attr.numsymbols = 4;
3245 if (appData.monoMode) {
3246 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3250 if (strlen(appData.pixmapDirectory) == 0) {
3251 XpmPieces* pieces = builtInXpms;
3254 while (pieces->size != squareSize && pieces->size) pieces++;
3255 if (!pieces->size) {
3256 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3259 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3260 for (kind=0; kind<4; kind++) {
3262 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3263 pieces->xpm[piece][kind],
3264 &(xpmPieceBitmap2[kind][piece]),
3265 NULL, &attr)) != 0) {
3266 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3270 if(piece <= (int) WhiteKing)
3271 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3275 xpmJailSquare = xpmLightSquare;
3279 fprintf(stderr, _("\nLoading XPMs...\n"));
3282 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3283 fprintf(stderr, "%d ", piece+1);
3284 for (kind=0; kind<4; kind++) {
3285 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3286 ExpandPathName(appData.pixmapDirectory),
3287 piece > (int) WhiteKing ? "w" : "",
3288 pieceBitmapNames[piece],
3290 if (appData.debugMode) {
3291 fprintf(stderr, _("(File:%s:) "), buf);
3293 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3294 &(xpmPieceBitmap2[kind][piece]),
3295 NULL, &attr)) != 0) {
3296 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3297 // [HGM] missing: read of unorthodox piece failed; substitute King.
3298 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3299 ExpandPathName(appData.pixmapDirectory),
3301 if (appData.debugMode) {
3302 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3304 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3305 &(xpmPieceBitmap2[kind][piece]),
3309 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3314 if(piece <= (int) WhiteKing)
3315 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3318 /* Load light and dark squares */
3319 /* If the LSQ and DSQ pieces don't exist, we will
3320 draw them with solid squares. */
3321 fprintf(stderr, _("light square "));
3322 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3323 if (access(buf, 0) != 0) {
3327 if (appData.debugMode)
3328 fprintf(stderr, _("(File:%s:) "), buf);
3330 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3331 &xpmLightSquare, NULL, &attr)) != 0) {
3332 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3335 fprintf(stderr, _("dark square "));
3336 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3337 ExpandPathName(appData.pixmapDirectory), ss);
3338 if (appData.debugMode) {
3339 fprintf(stderr, _("(File:%s:) "), buf);
3341 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3342 &xpmDarkSquare, NULL, &attr)) != 0) {
3343 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3347 xpmJailSquare = xpmLightSquare;
3348 fprintf(stderr, _("Done.\n"));
3350 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3353 #endif /* HAVE_LIBXPM */
3356 /* No built-in bitmaps */
3361 u_int ss = squareSize;
3363 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3366 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3367 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3368 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3369 pieceBitmapNames[piece],
3370 ss, kind == SOLID ? 's' : 'o');
3371 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3372 if(piece <= (int)WhiteKing)
3373 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3377 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3381 /* With built-in bitmaps */
3384 BuiltInBits* bib = builtInBits;
3387 u_int ss = squareSize;
3389 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3392 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3394 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3395 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3396 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3397 pieceBitmapNames[piece],
3398 ss, kind == SOLID ? 's' : 'o');
3399 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3400 bib->bits[kind][piece], ss, ss);
3401 if(piece <= (int)WhiteKing)
3402 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3406 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3411 void ReadBitmap(pm, name, bits, wreq, hreq)
3414 unsigned char bits[];
3420 char msg[MSG_SIZ], fullname[MSG_SIZ];
3422 if (*appData.bitmapDirectory != NULLCHAR) {
3423 strcpy(fullname, appData.bitmapDirectory);
3424 strcat(fullname, "/");
3425 strcat(fullname, name);
3426 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3427 &w, &h, pm, &x_hot, &y_hot);
3428 fprintf(stderr, "load %s\n", name);
3429 if (errcode != BitmapSuccess) {
3431 case BitmapOpenFailed:
3432 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3434 case BitmapFileInvalid:
3435 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3437 case BitmapNoMemory:
3438 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3442 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3446 fprintf(stderr, _("%s: %s...using built-in\n"),
3448 } else if (w != wreq || h != hreq) {
3450 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3451 programName, fullname, w, h, wreq, hreq);
3457 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3466 if (lineGap == 0) return;
3468 /* [HR] Split this into 2 loops for non-square boards. */
3470 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3471 gridSegments[i].x1 = 0;
3472 gridSegments[i].x2 =
3473 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3474 gridSegments[i].y1 = gridSegments[i].y2
3475 = lineGap / 2 + (i * (squareSize + lineGap));
3478 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3479 gridSegments[j + i].y1 = 0;
3480 gridSegments[j + i].y2 =
3481 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3482 gridSegments[j + i].x1 = gridSegments[j + i].x2
3483 = lineGap / 2 + (j * (squareSize + lineGap));
3487 static void MenuBarSelect(w, addr, index)
3492 XtActionProc proc = (XtActionProc) addr;
3494 (proc)(NULL, NULL, NULL, NULL);
3497 void CreateMenuBarPopup(parent, name, mb)
3507 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3510 XtSetArg(args[j], XtNleftMargin, 20); j++;
3511 XtSetArg(args[j], XtNrightMargin, 20); j++;
3513 while (mi->string != NULL) {
3514 if (strcmp(mi->string, "----") == 0) {
3515 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3518 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3519 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3521 XtAddCallback(entry, XtNcallback,
3522 (XtCallbackProc) MenuBarSelect,
3523 (caddr_t) mi->proc);
3529 Widget CreateMenuBar(mb)
3533 Widget anchor, menuBar;
3535 char menuName[MSG_SIZ];
3538 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3539 XtSetArg(args[j], XtNvSpace, 0); j++;
3540 XtSetArg(args[j], XtNborderWidth, 0); j++;
3541 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3542 formWidget, args, j);
3544 while (mb->name != NULL) {
3545 strcpy(menuName, "menu");
3546 strcat(menuName, mb->name);
3548 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3551 shortName[0] = _(mb->name)[0];
3552 shortName[1] = NULLCHAR;
3553 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3556 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3559 XtSetArg(args[j], XtNborderWidth, 0); j++;
3560 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3562 CreateMenuBarPopup(menuBar, menuName, mb);
3568 Widget CreateButtonBar(mi)
3572 Widget button, buttonBar;
3576 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3578 XtSetArg(args[j], XtNhSpace, 0); j++;
3580 XtSetArg(args[j], XtNborderWidth, 0); j++;
3581 XtSetArg(args[j], XtNvSpace, 0); j++;
3582 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3583 formWidget, args, j);
3585 while (mi->string != NULL) {
3588 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3589 XtSetArg(args[j], XtNborderWidth, 0); j++;
3591 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3592 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3593 buttonBar, args, j);
3594 XtAddCallback(button, XtNcallback,
3595 (XtCallbackProc) MenuBarSelect,
3596 (caddr_t) mi->proc);
3603 CreatePieceMenu(name, color)
3610 ChessSquare selection;
3612 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3613 boardWidget, args, 0);
3615 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3616 String item = pieceMenuStrings[color][i];
3618 if (strcmp(item, "----") == 0) {
3619 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3622 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3623 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3625 selection = pieceMenuTranslation[color][i];
3626 XtAddCallback(entry, XtNcallback,
3627 (XtCallbackProc) PieceMenuSelect,
3628 (caddr_t) selection);
3629 if (selection == WhitePawn || selection == BlackPawn) {
3630 XtSetArg(args[0], XtNpopupOnEntry, entry);
3631 XtSetValues(menu, args, 1);
3644 ChessSquare selection;
3646 whitePieceMenu = CreatePieceMenu("menuW", 0);
3647 blackPieceMenu = CreatePieceMenu("menuB", 1);
3649 XtRegisterGrabAction(PieceMenuPopup, True,
3650 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3651 GrabModeAsync, GrabModeAsync);
3653 XtSetArg(args[0], XtNlabel, _("Drop"));
3654 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3655 boardWidget, args, 1);
3656 for (i = 0; i < DROP_MENU_SIZE; i++) {
3657 String item = dropMenuStrings[i];
3659 if (strcmp(item, "----") == 0) {
3660 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3663 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3664 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3666 selection = dropMenuTranslation[i];
3667 XtAddCallback(entry, XtNcallback,
3668 (XtCallbackProc) DropMenuSelect,
3669 (caddr_t) selection);
3674 void SetupDropMenu()
3682 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3683 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3684 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3685 dmEnables[i].piece);
3686 XtSetSensitive(entry, p != NULL || !appData.testLegality
3687 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3688 && !appData.icsActive));
3690 while (p && *p++ == dmEnables[i].piece) count++;
3691 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3693 XtSetArg(args[j], XtNlabel, label); j++;
3694 XtSetValues(entry, args, j);
3698 void PieceMenuPopup(w, event, params, num_params)
3702 Cardinal *num_params;
3705 if (event->type != ButtonPress) return;
3706 if (errorUp) ErrorPopDown();
3710 whichMenu = params[0];
3712 case IcsPlayingWhite:
3713 case IcsPlayingBlack:
3715 case MachinePlaysWhite:
3716 case MachinePlaysBlack:
3717 if (appData.testLegality &&
3718 gameInfo.variant != VariantBughouse &&
3719 gameInfo.variant != VariantCrazyhouse) return;
3721 whichMenu = "menuD";
3727 if (((pmFromX = EventToSquare(event->xbutton.x, BOARD_WIDTH)) < 0) ||
3728 ((pmFromY = EventToSquare(event->xbutton.y, BOARD_HEIGHT)) < 0)) {
3729 pmFromX = pmFromY = -1;
3733 pmFromX = BOARD_WIDTH - 1 - pmFromX;
3735 pmFromY = BOARD_HEIGHT - 1 - pmFromY;
3737 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3740 static void PieceMenuSelect(w, piece, junk)
3745 if (pmFromX < 0 || pmFromY < 0) return;
3746 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3749 static void DropMenuSelect(w, piece, junk)
3754 if (pmFromX < 0 || pmFromY < 0) return;
3755 DropMenuEvent(piece, pmFromX, pmFromY);
3758 void WhiteClock(w, event, prms, nprms)
3764 if (gameMode == EditPosition || gameMode == IcsExamining) {
3765 SetWhiteToPlayEvent();
3766 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3771 void BlackClock(w, event, prms, nprms)
3777 if (gameMode == EditPosition || gameMode == IcsExamining) {
3778 SetBlackToPlayEvent();
3779 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3786 * If the user selects on a border boundary, return -1; if off the board,
3787 * return -2. Otherwise map the event coordinate to the square.
3789 int EventToSquare(x, limit)
3797 if ((x % (squareSize + lineGap)) >= squareSize)
3799 x /= (squareSize + lineGap);
3805 static void do_flash_delay(msec)
3811 static void drawHighlight(file, rank, gc)
3817 if (lineGap == 0 || appData.blindfold) return;
3820 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3821 (squareSize + lineGap);
3822 y = lineGap/2 + rank * (squareSize + lineGap);
3824 x = lineGap/2 + file * (squareSize + lineGap);
3825 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3826 (squareSize + lineGap);
3829 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3830 squareSize+lineGap, squareSize+lineGap);
3833 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3834 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3837 SetHighlights(fromX, fromY, toX, toY)
3838 int fromX, fromY, toX, toY;
3840 if (hi1X != fromX || hi1Y != fromY) {
3841 if (hi1X >= 0 && hi1Y >= 0) {
3842 drawHighlight(hi1X, hi1Y, lineGC);
3844 if (fromX >= 0 && fromY >= 0) {
3845 drawHighlight(fromX, fromY, highlineGC);
3848 if (hi2X != toX || hi2Y != toY) {
3849 if (hi2X >= 0 && hi2Y >= 0) {
3850 drawHighlight(hi2X, hi2Y, lineGC);
3852 if (toX >= 0 && toY >= 0) {
3853 drawHighlight(toX, toY, highlineGC);
3865 SetHighlights(-1, -1, -1, -1);
3870 SetPremoveHighlights(fromX, fromY, toX, toY)
3871 int fromX, fromY, toX, toY;
3873 if (pm1X != fromX || pm1Y != fromY) {
3874 if (pm1X >= 0 && pm1Y >= 0) {
3875 drawHighlight(pm1X, pm1Y, lineGC);
3877 if (fromX >= 0 && fromY >= 0) {
3878 drawHighlight(fromX, fromY, prelineGC);
3881 if (pm2X != toX || pm2Y != toY) {
3882 if (pm2X >= 0 && pm2Y >= 0) {
3883 drawHighlight(pm2X, pm2Y, lineGC);
3885 if (toX >= 0 && toY >= 0) {
3886 drawHighlight(toX, toY, prelineGC);
3896 ClearPremoveHighlights()
3898 SetPremoveHighlights(-1, -1, -1, -1);
3901 static void BlankSquare(x, y, color, piece, dest)
3906 if (useImages && useImageSqs) {
3910 pm = xpmLightSquare;
3915 case 2: /* neutral */
3920 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
3921 squareSize, squareSize, x, y);
3931 case 2: /* neutral */
3936 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
3941 I split out the routines to draw a piece so that I could
3942 make a generic flash routine.
3944 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
3946 int square_color, x, y;
3949 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3950 switch (square_color) {
3952 case 2: /* neutral */
3954 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3955 ? *pieceToOutline(piece)
3956 : *pieceToSolid(piece),
3957 dest, bwPieceGC, 0, 0,
3958 squareSize, squareSize, x, y);
3961 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3962 ? *pieceToSolid(piece)
3963 : *pieceToOutline(piece),
3964 dest, wbPieceGC, 0, 0,
3965 squareSize, squareSize, x, y);
3970 static void monoDrawPiece(piece, square_color, x, y, dest)
3972 int square_color, x, y;
3975 switch (square_color) {
3977 case 2: /* neutral */
3979 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3980 ? *pieceToOutline(piece)
3981 : *pieceToSolid(piece),
3982 dest, bwPieceGC, 0, 0,
3983 squareSize, squareSize, x, y, 1);
3986 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3987 ? *pieceToSolid(piece)
3988 : *pieceToOutline(piece),
3989 dest, wbPieceGC, 0, 0,
3990 squareSize, squareSize, x, y, 1);
3995 static void colorDrawPiece(piece, square_color, x, y, dest)
3997 int square_color, x, y;
4000 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4001 switch (square_color) {
4003 XCopyPlane(xDisplay, *pieceToSolid(piece),
4004 dest, (int) piece < (int) BlackPawn
4005 ? wlPieceGC : blPieceGC, 0, 0,
4006 squareSize, squareSize, x, y, 1);
4009 XCopyPlane(xDisplay, *pieceToSolid(piece),
4010 dest, (int) piece < (int) BlackPawn
4011 ? wdPieceGC : bdPieceGC, 0, 0,
4012 squareSize, squareSize, x, y, 1);
4014 case 2: /* neutral */
4016 XCopyPlane(xDisplay, *pieceToSolid(piece),
4017 dest, (int) piece < (int) BlackPawn
4018 ? wjPieceGC : bjPieceGC, 0, 0,
4019 squareSize, squareSize, x, y, 1);
4024 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4026 int square_color, x, y;
4031 switch (square_color) {
4033 case 2: /* neutral */
4035 if ((int)piece < (int) BlackPawn) {
4043 if ((int)piece < (int) BlackPawn) {
4051 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4052 dest, wlPieceGC, 0, 0,
4053 squareSize, squareSize, x, y);
4056 typedef void (*DrawFunc)();
4058 DrawFunc ChooseDrawFunc()
4060 if (appData.monoMode) {
4061 if (DefaultDepth(xDisplay, xScreen) == 1) {
4062 return monoDrawPiece_1bit;
4064 return monoDrawPiece;
4068 return colorDrawPieceImage;
4070 return colorDrawPiece;
4074 /* [HR] determine square color depending on chess variant. */
4075 static int SquareColor(row, column)
4080 if (gameInfo.variant == VariantXiangqi) {
4081 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4083 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4085 } else if (row <= 4) {
4091 square_color = ((column + row) % 2) == 1;
4094 /* [hgm] holdings: next line makes all holdings squares light */
4095 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4097 return square_color;
4100 void DrawSquare(row, column, piece, do_flash)
4101 int row, column, do_flash;
4104 int square_color, x, y, direction, font_ascent, font_descent;
4107 XCharStruct overall;
4111 /* Calculate delay in milliseconds (2-delays per complete flash) */
4112 flash_delay = 500 / appData.flashRate;
4115 x = lineGap + ((BOARD_WIDTH-1)-column) *
4116 (squareSize + lineGap);
4117 y = lineGap + row * (squareSize + lineGap);
4119 x = lineGap + column * (squareSize + lineGap);
4120 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4121 (squareSize + lineGap);
4124 square_color = SquareColor(row, column);
4126 if ( // [HGM] holdings: blank out area between board and holdings
4127 column == BOARD_LEFT-1 || column == BOARD_RGHT
4128 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4129 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4130 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4132 // [HGM] print piece counts next to holdings
4133 string[1] = NULLCHAR;
4134 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4135 string[0] = '0' + piece;
4136 XTextExtents(countFontStruct, string, 1, &direction,
4137 &font_ascent, &font_descent, &overall);
4138 if (appData.monoMode) {
4139 XDrawImageString(xDisplay, xBoardWindow, countGC,
4140 x + squareSize - overall.width - 2,
4141 y + font_ascent + 1, string, 1);
4143 XDrawString(xDisplay, xBoardWindow, countGC,
4144 x + squareSize - overall.width - 2,
4145 y + font_ascent + 1, string, 1);
4148 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4149 string[0] = '0' + piece;
4150 XTextExtents(countFontStruct, string, 1, &direction,
4151 &font_ascent, &font_descent, &overall);
4152 if (appData.monoMode) {
4153 XDrawImageString(xDisplay, xBoardWindow, countGC,
4154 x + 2, y + font_ascent + 1, string, 1);
4156 XDrawString(xDisplay, xBoardWindow, countGC,
4157 x + 2, y + font_ascent + 1, string, 1);
4161 if (piece == EmptySquare || appData.blindfold) {
4162 BlankSquare(x, y, square_color, piece, xBoardWindow);
4164 drawfunc = ChooseDrawFunc();
4165 if (do_flash && appData.flashCount > 0) {
4166 for (i=0; i<appData.flashCount; ++i) {
4168 drawfunc(piece, square_color, x, y, xBoardWindow);
4169 XSync(xDisplay, False);
4170 do_flash_delay(flash_delay);
4172 BlankSquare(x, y, square_color, piece, xBoardWindow);
4173 XSync(xDisplay, False);
4174 do_flash_delay(flash_delay);
4177 drawfunc(piece, square_color, x, y, xBoardWindow);
4181 string[1] = NULLCHAR;
4182 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4183 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4184 string[0] = 'a' + column - BOARD_LEFT;
4185 XTextExtents(coordFontStruct, string, 1, &direction,
4186 &font_ascent, &font_descent, &overall);
4187 if (appData.monoMode) {
4188 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4189 x + squareSize - overall.width - 2,
4190 y + squareSize - font_descent - 1, string, 1);
4192 XDrawString(xDisplay, xBoardWindow, coordGC,
4193 x + squareSize - overall.width - 2,
4194 y + squareSize - font_descent - 1, string, 1);
4197 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4198 string[0] = ONE + row;
4199 XTextExtents(coordFontStruct, string, 1, &direction,
4200 &font_ascent, &font_descent, &overall);
4201 if (appData.monoMode) {
4202 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4203 x + 2, y + font_ascent + 1, string, 1);
4205 XDrawString(xDisplay, xBoardWindow, coordGC,
4206 x + 2, y + font_ascent + 1, string, 1);
4212 /* Why is this needed on some versions of X? */
4213 void EventProc(widget, unused, event)
4218 if (!XtIsRealized(widget))
4221 switch (event->type) {
4223 if (event->xexpose.count > 0) return; /* no clipping is done */
4224 XDrawPosition(widget, True, NULL);
4232 void DrawPosition(fullRedraw, board)
4233 /*Boolean*/int fullRedraw;
4236 XDrawPosition(boardWidget, fullRedraw, board);
4239 /* Returns 1 if there are "too many" differences between b1 and b2
4240 (i.e. more than 1 move was made) */
4241 static int too_many_diffs(b1, b2)
4247 for (i=0; i<BOARD_HEIGHT; ++i) {
4248 for (j=0; j<BOARD_WIDTH; ++j) {
4249 if (b1[i][j] != b2[i][j]) {
4250 if (++c > 4) /* Castling causes 4 diffs */
4259 /* Matrix describing castling maneuvers */
4260 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4261 static int castling_matrix[4][5] = {
4262 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4263 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4264 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4265 { 7, 7, 4, 5, 6 } /* 0-0, black */
4268 /* Checks whether castling occurred. If it did, *rrow and *rcol
4269 are set to the destination (row,col) of the rook that moved.
4271 Returns 1 if castling occurred, 0 if not.
4273 Note: Only handles a max of 1 castling move, so be sure
4274 to call too_many_diffs() first.
4276 static int check_castle_draw(newb, oldb, rrow, rcol)
4283 /* For each type of castling... */
4284 for (i=0; i<4; ++i) {
4285 r = castling_matrix[i];
4287 /* Check the 4 squares involved in the castling move */
4289 for (j=1; j<=4; ++j) {
4290 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4297 /* All 4 changed, so it must be a castling move */
4306 static int damage[BOARD_RANKS][BOARD_FILES];
4309 * event handler for redrawing the board
4311 void XDrawPosition(w, repaint, board)
4313 /*Boolean*/int repaint;
4317 static int lastFlipView = 0;
4318 static int lastBoardValid = 0;
4319 static Board lastBoard;
4323 if (board == NULL) {
4324 if (!lastBoardValid) return;
4327 if (!lastBoardValid || lastFlipView != flipView) {
4328 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4329 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4334 * It would be simpler to clear the window with XClearWindow()
4335 * but this causes a very distracting flicker.
4338 if (!repaint && lastBoardValid && lastFlipView == flipView) {
4340 /* If too much changes (begin observing new game, etc.), don't
4342 do_flash = too_many_diffs(board, lastBoard) ? 0 : 1;
4344 /* Special check for castling so we don't flash both the king
4345 and the rook (just flash the king). */
4347 if (check_castle_draw(board, lastBoard, &rrow, &rcol)) {
4348 /* Draw rook with NO flashing. King will be drawn flashing later */
4349 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4350 lastBoard[rrow][rcol] = board[rrow][rcol];
4354 /* First pass -- Draw (newly) empty squares and repair damage.
4355 This prevents you from having a piece show up twice while it
4356 is flashing on its new square */
4357 for (i = 0; i < BOARD_HEIGHT; i++)
4358 for (j = 0; j < BOARD_WIDTH; j++)
4359 if ((board[i][j] != lastBoard[i][j] && board[i][j] == EmptySquare)
4361 DrawSquare(i, j, board[i][j], 0);
4362 damage[i][j] = False;
4365 /* Second pass -- Draw piece(s) in new position and flash them */
4366 for (i = 0; i < BOARD_HEIGHT; i++)
4367 for (j = 0; j < BOARD_WIDTH; j++)
4368 if (board[i][j] != lastBoard[i][j]) {
4369 DrawSquare(i, j, board[i][j], do_flash);
4373 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4374 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4376 for (i = 0; i < BOARD_HEIGHT; i++)
4377 for (j = 0; j < BOARD_WIDTH; j++) {
4378 DrawSquare(i, j, board[i][j], 0);
4379 damage[i][j] = False;
4383 CopyBoard(lastBoard, board);
4385 lastFlipView = flipView;
4387 /* Draw highlights */
4388 if (pm1X >= 0 && pm1Y >= 0) {
4389 drawHighlight(pm1X, pm1Y, prelineGC);
4391 if (pm2X >= 0 && pm2Y >= 0) {
4392 drawHighlight(pm2X, pm2Y, prelineGC);
4394 if (hi1X >= 0 && hi1Y >= 0) {
4395 drawHighlight(hi1X, hi1Y, highlineGC);
4397 if (hi2X >= 0 && hi2Y >= 0) {
4398 drawHighlight(hi2X, hi2Y, highlineGC);
4401 /* If piece being dragged around board, must redraw that too */
4404 XSync(xDisplay, False);
4409 * event handler for redrawing the board
4411 void DrawPositionProc(w, event, prms, nprms)
4417 XDrawPosition(w, True, NULL);
4422 * event handler for parsing user moves
4424 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4425 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4426 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4427 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4428 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4429 // and at the end FinishMove() to perform the move after optional promotion popups.
4430 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4431 void HandleUserMove(w, event, prms, nprms)
4437 if (w != boardWidget || errorExitStatus != -1) return;
4440 if (event->type == ButtonPress) {
4441 XtPopdown(promotionShell);
4442 XtDestroyWidget(promotionShell);
4443 promotionUp = False;
4451 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4452 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4453 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4456 void AnimateUserMove (Widget w, XEvent * event,
4457 String * params, Cardinal * nParams)
4459 DragPieceMove(event->xmotion.x, event->xmotion.y);
4462 Widget CommentCreate(name, text, mutable, callback, lines)
4464 int /*Boolean*/ mutable;
4465 XtCallbackProc callback;
4469 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4474 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4475 XtGetValues(boardWidget, args, j);
4478 XtSetArg(args[j], XtNresizable, True); j++;
4481 XtCreatePopupShell(name, topLevelShellWidgetClass,
4482 shellWidget, args, j);
4485 XtCreatePopupShell(name, transientShellWidgetClass,
4486 shellWidget, args, j);
4489 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4490 layoutArgs, XtNumber(layoutArgs));
4492 XtCreateManagedWidget("form", formWidgetClass, layout,
4493 formArgs, XtNumber(formArgs));
4497 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4498 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4500 XtSetArg(args[j], XtNstring, text); j++;
4501 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4502 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4503 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4504 XtSetArg(args[j], XtNright, XtChainRight); j++;
4505 XtSetArg(args[j], XtNresizable, True); j++;
4506 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4507 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4508 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4509 XtSetArg(args[j], XtNautoFill, True); j++;
4510 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4512 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4516 XtSetArg(args[j], XtNfromVert, edit); j++;
4517 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4518 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4519 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4520 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4522 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4523 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4526 XtSetArg(args[j], XtNfromVert, edit); j++;
4527 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4528 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4529 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4530 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4531 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4533 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4534 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4537 XtSetArg(args[j], XtNfromVert, edit); j++;
4538 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4539 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4540 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4541 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4542 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4544 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4545 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4548 XtSetArg(args[j], XtNfromVert, edit); j++;
4549 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4550 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4551 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4552 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4554 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4555 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4558 XtSetArg(args[j], XtNfromVert, edit); j++;
4559 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4560 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4561 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4562 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4563 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4565 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4566 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4569 XtRealizeWidget(shell);
4571 if (commentX == -1) {
4574 Dimension pw_height;
4575 Dimension ew_height;
4578 XtSetArg(args[j], XtNheight, &ew_height); j++;
4579 XtGetValues(edit, args, j);
4582 XtSetArg(args[j], XtNheight, &pw_height); j++;
4583 XtGetValues(shell, args, j);
4584 commentH = pw_height + (lines - 1) * ew_height;
4585 commentW = bw_width - 16;
4587 XSync(xDisplay, False);
4589 /* This code seems to tickle an X bug if it is executed too soon
4590 after xboard starts up. The coordinates get transformed as if
4591 the main window was positioned at (0, 0).
4593 XtTranslateCoords(shellWidget,
4594 (bw_width - commentW) / 2, 0 - commentH / 2,
4595 &commentX, &commentY);
4597 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4598 RootWindowOfScreen(XtScreen(shellWidget)),
4599 (bw_width - commentW) / 2, 0 - commentH / 2,
4604 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4607 if(wpComment.width > 0) {
4608 commentX = wpComment.x;
4609 commentY = wpComment.y;
4610 commentW = wpComment.width;
4611 commentH = wpComment.height;
4615 XtSetArg(args[j], XtNheight, commentH); j++;
4616 XtSetArg(args[j], XtNwidth, commentW); j++;
4617 XtSetArg(args[j], XtNx, commentX); j++;
4618 XtSetArg(args[j], XtNy, commentY); j++;
4619 XtSetValues(shell, args, j);
4620 XtSetKeyboardFocus(shell, edit);
4625 /* Used for analysis window and ICS input window */
4626 Widget MiscCreate(name, text, mutable, callback, lines)
4628 int /*Boolean*/ mutable;
4629 XtCallbackProc callback;
4633 Widget shell, layout, form, edit;
4635 Dimension bw_width, pw_height, ew_height, w, h;
4641 XtSetArg(args[j], XtNresizable, True); j++;
4644 XtCreatePopupShell(name, topLevelShellWidgetClass,
4645 shellWidget, args, j);
4648 XtCreatePopupShell(name, transientShellWidgetClass,
4649 shellWidget, args, j);
4652 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4653 layoutArgs, XtNumber(layoutArgs));
4655 XtCreateManagedWidget("form", formWidgetClass, layout,
4656 formArgs, XtNumber(formArgs));
4660 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4661 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4663 XtSetArg(args[j], XtNstring, text); j++;
4664 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4665 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4666 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4667 XtSetArg(args[j], XtNright, XtChainRight); j++;
4668 XtSetArg(args[j], XtNresizable, True); j++;
4669 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4670 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4671 XtSetArg(args[j], XtNautoFill, True); j++;
4672 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4674 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4676 XtRealizeWidget(shell);
4679 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4680 XtGetValues(boardWidget, args, j);
4683 XtSetArg(args[j], XtNheight, &ew_height); j++;
4684 XtGetValues(edit, args, j);
4687 XtSetArg(args[j], XtNheight, &pw_height); j++;
4688 XtGetValues(shell, args, j);
4689 h = pw_height + (lines - 1) * ew_height;
4692 XSync(xDisplay, False);
4694 /* This code seems to tickle an X bug if it is executed too soon
4695 after xboard starts up. The coordinates get transformed as if
4696 the main window was positioned at (0, 0).
4698 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4700 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4701 RootWindowOfScreen(XtScreen(shellWidget)),
4702 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4706 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4709 XtSetArg(args[j], XtNheight, h); j++;
4710 XtSetArg(args[j], XtNwidth, w); j++;
4711 XtSetArg(args[j], XtNx, x); j++;
4712 XtSetArg(args[j], XtNy, y); j++;
4713 XtSetValues(shell, args, j);
4719 static int savedIndex; /* gross that this is global */
4721 void EditCommentPopUp(index, title, text)
4730 if (text == NULL) text = "";
4732 if (editShell == NULL) {
4734 CommentCreate(title, text, True, EditCommentCallback, 4);
4735 XtRealizeWidget(editShell);
4736 CatchDeleteWindow(editShell, "EditCommentPopDown");
4738 edit = XtNameToWidget(editShell, "*form.text");
4740 XtSetArg(args[j], XtNstring, text); j++;
4741 XtSetValues(edit, args, j);
4743 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4744 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4745 XtSetValues(editShell, args, j);
4748 XtPopup(editShell, XtGrabNone);
4752 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4753 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4757 void EditCommentCallback(w, client_data, call_data)
4759 XtPointer client_data, call_data;
4767 XtSetArg(args[j], XtNlabel, &name); j++;
4768 XtGetValues(w, args, j);
4770 if (strcmp(name, _("ok")) == 0) {
4771 edit = XtNameToWidget(editShell, "*form.text");
4773 XtSetArg(args[j], XtNstring, &val); j++;
4774 XtGetValues(edit, args, j);
4775 ReplaceComment(savedIndex, val);
4776 EditCommentPopDown();
4777 } else if (strcmp(name, _("cancel")) == 0) {
4778 EditCommentPopDown();
4779 } else if (strcmp(name, _("clear")) == 0) {
4780 edit = XtNameToWidget(editShell, "*form.text");
4781 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4782 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4786 void EditCommentPopDown()
4791 if (!editUp) return;
4793 XtSetArg(args[j], XtNx, &commentX); j++;
4794 XtSetArg(args[j], XtNy, &commentY); j++;
4795 XtSetArg(args[j], XtNheight, &commentH); j++;
4796 XtSetArg(args[j], XtNwidth, &commentW); j++;
4797 XtGetValues(editShell, args, j);
4798 XtPopdown(editShell);
4801 XtSetArg(args[j], XtNleftBitmap, None); j++;
4802 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4806 void ICSInputBoxPopUp()
4811 char *title = _("ICS Input");
4814 if (ICSInputShell == NULL) {
4815 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
4816 tr = XtParseTranslationTable(ICSInputTranslations);
4817 edit = XtNameToWidget(ICSInputShell, "*form.text");
4818 XtOverrideTranslations(edit, tr);
4819 XtRealizeWidget(ICSInputShell);
4820 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
4823 edit = XtNameToWidget(ICSInputShell, "*form.text");
4825 XtSetArg(args[j], XtNstring, ""); j++;
4826 XtSetValues(edit, args, j);
4828 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4829 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4830 XtSetValues(ICSInputShell, args, j);
4833 XtPopup(ICSInputShell, XtGrabNone);
4834 XtSetKeyboardFocus(ICSInputShell, edit);
4836 ICSInputBoxUp = True;
4838 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4839 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4843 void ICSInputSendText()
4850 edit = XtNameToWidget(ICSInputShell, "*form.text");
4852 XtSetArg(args[j], XtNstring, &val); j++;
4853 XtGetValues(edit, args, j);
4854 SendMultiLineToICS(val);
4855 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4856 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4859 void ICSInputBoxPopDown()
4864 if (!ICSInputBoxUp) return;
4866 XtPopdown(ICSInputShell);
4867 ICSInputBoxUp = False;
4869 XtSetArg(args[j], XtNleftBitmap, None); j++;
4870 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4874 void CommentPopUp(title, text)
4881 if (commentShell == NULL) {
4883 CommentCreate(title, text, False, CommentCallback, 4);
4884 XtRealizeWidget(commentShell);
4885 CatchDeleteWindow(commentShell, "CommentPopDown");
4887 edit = XtNameToWidget(commentShell, "*form.text");
4889 XtSetArg(args[j], XtNstring, text); j++;
4890 XtSetValues(edit, args, j);
4892 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4893 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4894 XtSetValues(commentShell, args, j);
4897 XtPopup(commentShell, XtGrabNone);
4898 XSync(xDisplay, False);
4903 void CommentCallback(w, client_data, call_data)
4905 XtPointer client_data, call_data;
4912 XtSetArg(args[j], XtNlabel, &name); j++;
4913 XtGetValues(w, args, j);
4915 if (strcmp(name, _("close")) == 0) {
4917 } else if (strcmp(name, _("edit")) == 0) {
4924 void CommentPopDown()
4929 if (!commentUp) return;
4931 XtSetArg(args[j], XtNx, &commentX); j++;
4932 XtSetArg(args[j], XtNy, &commentY); j++;
4933 XtSetArg(args[j], XtNwidth, &commentW); j++;
4934 XtSetArg(args[j], XtNheight, &commentH); j++;
4935 XtGetValues(commentShell, args, j);
4936 XtPopdown(commentShell);
4937 XSync(xDisplay, False);
4941 void FileNamePopUp(label, def, proc, openMode)
4948 Widget popup, layout, dialog, edit;
4954 fileProc = proc; /* I can't see a way not */
4955 fileOpenMode = openMode; /* to use globals here */
4958 XtSetArg(args[i], XtNresizable, True); i++;
4959 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
4960 XtSetArg(args[i], XtNtitle, XtNewString(_("File name prompt"))); i++;
4961 fileNameShell = popup =
4962 XtCreatePopupShell("File name prompt", transientShellWidgetClass,
4963 shellWidget, args, i);
4966 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
4967 layoutArgs, XtNumber(layoutArgs));
4970 XtSetArg(args[i], XtNlabel, label); i++;
4971 XtSetArg(args[i], XtNvalue, def); i++;
4972 XtSetArg(args[i], XtNborderWidth, 0); i++;
4973 dialog = XtCreateManagedWidget("fileName", dialogWidgetClass,
4976 XawDialogAddButton(dialog, _("ok"), FileNameCallback, (XtPointer) dialog);
4977 XawDialogAddButton(dialog, _("cancel"), FileNameCallback,
4978 (XtPointer) dialog);
4980 XtRealizeWidget(popup);
4981 CatchDeleteWindow(popup, "FileNamePopDown");
4983 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
4984 &x, &y, &win_x, &win_y, &mask);
4986 XtSetArg(args[0], XtNx, x - 10);
4987 XtSetArg(args[1], XtNy, y - 30);
4988 XtSetValues(popup, args, 2);
4990 XtPopup(popup, XtGrabExclusive);
4993 edit = XtNameToWidget(dialog, "*value");
4994 XtSetKeyboardFocus(popup, edit);
4997 void FileNamePopDown()
4999 if (!filenameUp) return;
5000 XtPopdown(fileNameShell);
5001 XtDestroyWidget(fileNameShell);
5006 void FileNameCallback(w, client_data, call_data)
5008 XtPointer client_data, call_data;
5013 XtSetArg(args[0], XtNlabel, &name);
5014 XtGetValues(w, args, 1);
5016 if (strcmp(name, _("cancel")) == 0) {
5021 FileNameAction(w, NULL, NULL, NULL);
5024 void FileNameAction(w, event, prms, nprms)
5036 name = XawDialogGetValueString(w = XtParent(w));
5038 if ((name != NULL) && (*name != NULLCHAR)) {
5040 XtPopdown(w = XtParent(XtParent(w)));
5044 p = strrchr(buf, ' ');
5051 fullname = ExpandPathName(buf);
5053 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5056 f = fopen(fullname, fileOpenMode);
5058 DisplayError(_("Failed to open file"), errno);
5060 (void) (*fileProc)(f, index, buf);
5067 XtPopdown(w = XtParent(XtParent(w)));
5073 void PromotionPopUp()
5076 Widget dialog, layout;
5078 Dimension bw_width, pw_width;
5082 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5083 XtGetValues(boardWidget, args, j);
5086 XtSetArg(args[j], XtNresizable, True); j++;
5087 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5089 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5090 shellWidget, args, j);
5092 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5093 layoutArgs, XtNumber(layoutArgs));
5096 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5097 XtSetArg(args[j], XtNborderWidth, 0); j++;
5098 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5101 if(gameInfo.variant != VariantShogi) {
5102 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5103 (XtPointer) dialog);
5104 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5105 (XtPointer) dialog);
5106 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5107 (XtPointer) dialog);
5108 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5109 (XtPointer) dialog);
5110 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5111 gameInfo.variant == VariantGiveaway) {
5112 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5113 (XtPointer) dialog);
5115 if(gameInfo.variant == VariantCapablanca ||
5116 gameInfo.variant == VariantGothic ||
5117 gameInfo.variant == VariantCapaRandom) {
5118 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5119 (XtPointer) dialog);
5120 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5121 (XtPointer) dialog);
5123 } else // [HGM] shogi
5125 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5126 (XtPointer) dialog);
5127 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5128 (XtPointer) dialog);
5130 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5131 (XtPointer) dialog);
5133 XtRealizeWidget(promotionShell);
5134 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5137 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5138 XtGetValues(promotionShell, args, j);
5140 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5141 lineGap + squareSize/3 +
5142 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5143 0 : 6*(squareSize + lineGap)), &x, &y);
5146 XtSetArg(args[j], XtNx, x); j++;
5147 XtSetArg(args[j], XtNy, y); j++;
5148 XtSetValues(promotionShell, args, j);
5150 XtPopup(promotionShell, XtGrabNone);
5155 void PromotionPopDown()
5157 if (!promotionUp) return;
5158 XtPopdown(promotionShell);
5159 XtDestroyWidget(promotionShell);
5160 promotionUp = False;
5163 void PromotionCallback(w, client_data, call_data)
5165 XtPointer client_data, call_data;
5171 XtSetArg(args[0], XtNlabel, &name);
5172 XtGetValues(w, args, 1);
5176 if (fromX == -1) return;
5178 if (strcmp(name, _("cancel")) == 0) {
5182 } else if (strcmp(name, _("Knight")) == 0) {
5184 } else if (strcmp(name, _("Promote")) == 0) {
5186 } else if (strcmp(name, _("Defer")) == 0) {
5189 promoChar = ToLower(name[0]);
5192 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5194 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5195 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5200 void ErrorCallback(w, client_data, call_data)
5202 XtPointer client_data, call_data;
5205 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5207 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5213 if (!errorUp) return;
5215 XtPopdown(errorShell);
5216 XtDestroyWidget(errorShell);
5217 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5220 void ErrorPopUp(title, label, modal)
5221 char *title, *label;
5225 Widget dialog, layout;
5229 Dimension bw_width, pw_width;
5230 Dimension pw_height;
5234 XtSetArg(args[i], XtNresizable, True); i++;
5235 XtSetArg(args[i], XtNtitle, title); i++;
5237 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5238 shellWidget, args, i);
5240 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5241 layoutArgs, XtNumber(layoutArgs));
5244 XtSetArg(args[i], XtNlabel, label); i++;
5245 XtSetArg(args[i], XtNborderWidth, 0); i++;
5246 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5249 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5251 XtRealizeWidget(errorShell);
5252 CatchDeleteWindow(errorShell, "ErrorPopDown");
5255 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5256 XtGetValues(boardWidget, args, i);
5258 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5259 XtSetArg(args[i], XtNheight, &pw_height); i++;
5260 XtGetValues(errorShell, args, i);
5263 /* This code seems to tickle an X bug if it is executed too soon
5264 after xboard starts up. The coordinates get transformed as if
5265 the main window was positioned at (0, 0).
5267 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5268 0 - pw_height + squareSize / 3, &x, &y);
5270 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5271 RootWindowOfScreen(XtScreen(boardWidget)),
5272 (bw_width - pw_width) / 2,
5273 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5277 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5280 XtSetArg(args[i], XtNx, x); i++;
5281 XtSetArg(args[i], XtNy, y); i++;
5282 XtSetValues(errorShell, args, i);
5285 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5288 /* Disable all user input other than deleting the window */
5289 static int frozen = 0;
5293 /* Grab by a widget that doesn't accept input */
5294 XtAddGrab(messageWidget, TRUE, FALSE);
5298 /* Undo a FreezeUI */
5301 if (!frozen) return;
5302 XtRemoveGrab(messageWidget);
5306 char *ModeToWidgetName(mode)
5310 case BeginningOfGame:
5311 if (appData.icsActive)
5312 return "menuMode.ICS Client";
5313 else if (appData.noChessProgram ||
5314 *appData.cmailGameName != NULLCHAR)
5315 return "menuMode.Edit Game";
5317 return "menuMode.Machine Black";
5318 case MachinePlaysBlack:
5319 return "menuMode.Machine Black";
5320 case MachinePlaysWhite:
5321 return "menuMode.Machine White";
5323 return "menuMode.Analysis Mode";
5325 return "menuMode.Analyze File";
5326 case TwoMachinesPlay:
5327 return "menuMode.Two Machines";
5329 return "menuMode.Edit Game";
5330 case PlayFromGameFile:
5331 return "menuFile.Load Game";
5333 return "menuMode.Edit Position";
5335 return "menuMode.Training";
5336 case IcsPlayingWhite:
5337 case IcsPlayingBlack:
5341 return "menuMode.ICS Client";
5348 void ModeHighlight()
5351 static int oldPausing = FALSE;
5352 static GameMode oldmode = (GameMode) -1;
5355 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5357 if (pausing != oldPausing) {
5358 oldPausing = pausing;
5360 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5362 XtSetArg(args[0], XtNleftBitmap, None);
5364 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5367 if (appData.showButtonBar) {
5368 /* Always toggle, don't set. Previous code messes up when
5369 invoked while the button is pressed, as releasing it
5370 toggles the state again. */
5373 XtSetArg(args[0], XtNbackground, &oldbg);
5374 XtSetArg(args[1], XtNforeground, &oldfg);
5375 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5377 XtSetArg(args[0], XtNbackground, oldfg);
5378 XtSetArg(args[1], XtNforeground, oldbg);
5380 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5384 wname = ModeToWidgetName(oldmode);
5385 if (wname != NULL) {
5386 XtSetArg(args[0], XtNleftBitmap, None);
5387 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5389 wname = ModeToWidgetName(gameMode);
5390 if (wname != NULL) {
5391 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5392 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5396 /* Maybe all the enables should be handled here, not just this one */
5397 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5398 gameMode == Training || gameMode == PlayFromGameFile);
5403 * Button/menu procedures
5405 void ResetProc(w, event, prms, nprms)
5414 int LoadGamePopUp(f, gameNumber, title)
5419 cmailMsgLoaded = FALSE;
5420 if (gameNumber == 0) {
5421 int error = GameListBuild(f);
5423 DisplayError(_("Cannot build game list"), error);
5424 } else if (!ListEmpty(&gameList) &&
5425 ((ListGame *) gameList.tailPred)->number > 1) {
5426 GameListPopUp(f, title);
5432 return LoadGame(f, gameNumber, title, FALSE);
5435 void LoadGameProc(w, event, prms, nprms)
5441 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5444 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5447 void LoadNextGameProc(w, event, prms, nprms)
5456 void LoadPrevGameProc(w, event, prms, nprms)
5465 void ReloadGameProc(w, event, prms, nprms)
5474 void LoadNextPositionProc(w, event, prms, nprms)
5483 void LoadPrevPositionProc(w, event, prms, nprms)
5492 void ReloadPositionProc(w, event, prms, nprms)
5501 void LoadPositionProc(w, event, prms, nprms)
5507 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5510 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5513 void SaveGameProc(w, event, prms, nprms)
5519 FileNamePopUp(_("Save game file name?"),
5520 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5524 void SavePositionProc(w, event, prms, nprms)
5530 FileNamePopUp(_("Save position file name?"),
5531 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5535 void ReloadCmailMsgProc(w, event, prms, nprms)
5541 ReloadCmailMsgEvent(FALSE);
5544 void MailMoveProc(w, event, prms, nprms)
5553 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5554 static char *selected_fen_position=NULL;
5557 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5558 Atom *type_return, XtPointer *value_return,
5559 unsigned long *length_return, int *format_return)
5561 char *selection_tmp;
5563 if (!selected_fen_position) return False; /* should never happen */
5564 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5565 /* note: since no XtSelectionDoneProc was registered, Xt will
5566 * automatically call XtFree on the value returned. So have to
5567 * make a copy of it allocated with XtMalloc */
5568 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5569 strcpy(selection_tmp, selected_fen_position);
5571 *value_return=selection_tmp;
5572 *length_return=strlen(selection_tmp);
5573 *type_return=*target;
5574 *format_return = 8; /* bits per byte */
5576 } else if (*target == XA_TARGETS(xDisplay)) {
5577 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5578 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5579 targets_tmp[1] = XA_STRING;
5580 *value_return = targets_tmp;
5581 *type_return = XA_ATOM;
5583 *format_return = 8 * sizeof(Atom);
5584 if (*format_return > 32) {
5585 *length_return *= *format_return / 32;
5586 *format_return = 32;
5594 /* note: when called from menu all parameters are NULL, so no clue what the
5595 * Widget which was clicked on was, or what the click event was
5597 void CopyPositionProc(w, event, prms, nprms)
5604 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5605 * have a notion of a position that is selected but not copied.
5606 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5608 if(gameMode == EditPosition) EditPositionDone(TRUE);
5609 if (selected_fen_position) free(selected_fen_position);
5610 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5611 if (!selected_fen_position) return;
5612 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5614 SendPositionSelection,
5615 NULL/* lose_ownership_proc */ ,
5616 NULL/* transfer_done_proc */);
5617 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5619 SendPositionSelection,
5620 NULL/* lose_ownership_proc */ ,
5621 NULL/* transfer_done_proc */);
5624 /* function called when the data to Paste is ready */
5626 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5627 Atom *type, XtPointer value, unsigned long *len, int *format)
5630 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5631 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5632 EditPositionPasteFEN(fenstr);
5636 /* called when Paste Position button is pressed,
5637 * all parameters will be NULL */
5638 void PastePositionProc(w, event, prms, nprms)
5644 XtGetSelectionValue(menuBarWidget,
5645 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5646 /* (XtSelectionCallbackProc) */ PastePositionCB,
5647 NULL, /* client_data passed to PastePositionCB */
5649 /* better to use the time field from the event that triggered the
5650 * call to this function, but that isn't trivial to get
5658 SendGameSelection(Widget w, Atom *selection, Atom *target,
5659 Atom *type_return, XtPointer *value_return,
5660 unsigned long *length_return, int *format_return)
5662 char *selection_tmp;
5664 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5665 FILE* f = fopen(gameCopyFilename, "r");
5668 if (f == NULL) return False;
5672 selection_tmp = XtMalloc(len + 1);
5673 count = fread(selection_tmp, 1, len, f);
5675 XtFree(selection_tmp);
5678 selection_tmp[len] = NULLCHAR;
5679 *value_return = selection_tmp;
5680 *length_return = len;
5681 *type_return = *target;
5682 *format_return = 8; /* bits per byte */
5684 } else if (*target == XA_TARGETS(xDisplay)) {
5685 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5686 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5687 targets_tmp[1] = XA_STRING;
5688 *value_return = targets_tmp;
5689 *type_return = XA_ATOM;
5691 *format_return = 8 * sizeof(Atom);
5692 if (*format_return > 32) {
5693 *length_return *= *format_return / 32;
5694 *format_return = 32;
5702 /* note: when called from menu all parameters are NULL, so no clue what the
5703 * Widget which was clicked on was, or what the click event was
5705 void CopyGameProc(w, event, prms, nprms)
5713 ret = SaveGameToFile(gameCopyFilename, FALSE);
5717 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5718 * have a notion of a game that is selected but not copied.
5719 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5721 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5724 NULL/* lose_ownership_proc */ ,
5725 NULL/* transfer_done_proc */);
5726 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5729 NULL/* lose_ownership_proc */ ,
5730 NULL/* transfer_done_proc */);
5733 /* function called when the data to Paste is ready */
5735 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5736 Atom *type, XtPointer value, unsigned long *len, int *format)
5739 if (value == NULL || *len == 0) {
5740 return; /* nothing had been selected to copy */
5742 f = fopen(gamePasteFilename, "w");
5744 DisplayError(_("Can't open temp file"), errno);
5747 fwrite(value, 1, *len, f);
5750 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5753 /* called when Paste Game button is pressed,
5754 * all parameters will be NULL */
5755 void PasteGameProc(w, event, prms, nprms)
5761 XtGetSelectionValue(menuBarWidget,
5762 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5763 /* (XtSelectionCallbackProc) */ PasteGameCB,
5764 NULL, /* client_data passed to PasteGameCB */
5766 /* better to use the time field from the event that triggered the
5767 * call to this function, but that isn't trivial to get
5777 SaveGameProc(NULL, NULL, NULL, NULL);
5781 void QuitProc(w, event, prms, nprms)
5790 void PauseProc(w, event, prms, nprms)
5800 void MachineBlackProc(w, event, prms, nprms)
5806 MachineBlackEvent();
5809 void MachineWhiteProc(w, event, prms, nprms)
5815 MachineWhiteEvent();
5818 void AnalyzeModeProc(w, event, prms, nprms)
5826 if (!first.analysisSupport) {
5827 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5828 DisplayError(buf, 0);
5831 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5832 if (appData.icsActive) {
5833 if (gameMode != IcsObserving) {
5834 sprintf(buf,_("You are not observing a game"));
5835 DisplayError(buf, 0);
5837 if (appData.icsEngineAnalyze) {
5838 if (appData.debugMode)
5839 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5845 /* if enable, use want disable icsEngineAnalyze */
5846 if (appData.icsEngineAnalyze) {
5851 appData.icsEngineAnalyze = TRUE;
5852 if (appData.debugMode)
5853 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5855 if (!appData.showThinking)
5856 ShowThinkingProc(w,event,prms,nprms);
5861 void AnalyzeFileProc(w, event, prms, nprms)
5867 if (!first.analysisSupport) {
5869 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5870 DisplayError(buf, 0);
5875 if (!appData.showThinking)
5876 ShowThinkingProc(w,event,prms,nprms);
5879 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
5880 AnalysisPeriodicEvent(1);
5883 void TwoMachinesProc(w, event, prms, nprms)
5892 void IcsClientProc(w, event, prms, nprms)
5901 void EditGameProc(w, event, prms, nprms)
5910 void EditPositionProc(w, event, prms, nprms)
5916 EditPositionEvent();
5919 void TrainingProc(w, event, prms, nprms)
5928 void EditCommentProc(w, event, prms, nprms)
5935 EditCommentPopDown();
5941 void IcsInputBoxProc(w, event, prms, nprms)
5947 if (ICSInputBoxUp) {
5948 ICSInputBoxPopDown();
5954 void AcceptProc(w, event, prms, nprms)
5963 void DeclineProc(w, event, prms, nprms)
5972 void RematchProc(w, event, prms, nprms)
5981 void CallFlagProc(w, event, prms, nprms)
5990 void DrawProc(w, event, prms, nprms)
5999 void AbortProc(w, event, prms, nprms)
6008 void AdjournProc(w, event, prms, nprms)
6017 void ResignProc(w, event, prms, nprms)
6026 void AdjuWhiteProc(w, event, prms, nprms)
6032 UserAdjudicationEvent(+1);
6035 void AdjuBlackProc(w, event, prms, nprms)
6041 UserAdjudicationEvent(-1);
6044 void AdjuDrawProc(w, event, prms, nprms)
6050 UserAdjudicationEvent(0);
6053 void EnterKeyProc(w, event, prms, nprms)
6059 if (ICSInputBoxUp == True)
6063 void StopObservingProc(w, event, prms, nprms)
6069 StopObservingEvent();
6072 void StopExaminingProc(w, event, prms, nprms)
6078 StopExaminingEvent();
6082 void ForwardProc(w, event, prms, nprms)
6092 void BackwardProc(w, event, prms, nprms)
6101 void ToStartProc(w, event, prms, nprms)
6110 void ToEndProc(w, event, prms, nprms)
6119 void RevertProc(w, event, prms, nprms)
6128 void TruncateGameProc(w, event, prms, nprms)
6134 TruncateGameEvent();
6136 void RetractMoveProc(w, event, prms, nprms)
6145 void MoveNowProc(w, event, prms, nprms)
6155 void AlwaysQueenProc(w, event, prms, nprms)
6163 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6165 if (appData.alwaysPromoteToQueen) {
6166 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6168 XtSetArg(args[0], XtNleftBitmap, None);
6170 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6174 void AnimateDraggingProc(w, event, prms, nprms)
6182 appData.animateDragging = !appData.animateDragging;
6184 if (appData.animateDragging) {
6185 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6188 XtSetArg(args[0], XtNleftBitmap, None);
6190 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6194 void AnimateMovingProc(w, event, prms, nprms)
6202 appData.animate = !appData.animate;
6204 if (appData.animate) {
6205 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6208 XtSetArg(args[0], XtNleftBitmap, None);
6210 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6214 void AutocommProc(w, event, prms, nprms)
6222 appData.autoComment = !appData.autoComment;
6224 if (appData.autoComment) {
6225 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6227 XtSetArg(args[0], XtNleftBitmap, None);
6229 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6234 void AutoflagProc(w, event, prms, nprms)
6242 appData.autoCallFlag = !appData.autoCallFlag;
6244 if (appData.autoCallFlag) {
6245 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6247 XtSetArg(args[0], XtNleftBitmap, None);
6249 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6253 void AutoflipProc(w, event, prms, nprms)
6261 appData.autoFlipView = !appData.autoFlipView;
6263 if (appData.autoFlipView) {
6264 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6266 XtSetArg(args[0], XtNleftBitmap, None);
6268 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6272 void AutobsProc(w, event, prms, nprms)
6280 appData.autoObserve = !appData.autoObserve;
6282 if (appData.autoObserve) {
6283 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6285 XtSetArg(args[0], XtNleftBitmap, None);
6287 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6291 void AutoraiseProc(w, event, prms, nprms)
6299 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6301 if (appData.autoRaiseBoard) {
6302 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6304 XtSetArg(args[0], XtNleftBitmap, None);
6306 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6310 void AutosaveProc(w, event, prms, nprms)
6318 appData.autoSaveGames = !appData.autoSaveGames;
6320 if (appData.autoSaveGames) {
6321 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6323 XtSetArg(args[0], XtNleftBitmap, None);
6325 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6329 void BlindfoldProc(w, event, prms, nprms)
6337 appData.blindfold = !appData.blindfold;
6339 if (appData.blindfold) {
6340 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6342 XtSetArg(args[0], XtNleftBitmap, None);
6344 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6347 DrawPosition(True, NULL);
6350 void TestLegalityProc(w, event, prms, nprms)
6358 appData.testLegality = !appData.testLegality;
6360 if (appData.testLegality) {
6361 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6363 XtSetArg(args[0], XtNleftBitmap, None);
6365 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6370 void FlashMovesProc(w, event, prms, nprms)
6378 if (appData.flashCount == 0) {
6379 appData.flashCount = 3;
6381 appData.flashCount = -appData.flashCount;
6384 if (appData.flashCount > 0) {
6385 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6387 XtSetArg(args[0], XtNleftBitmap, None);
6389 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6393 void FlipViewProc(w, event, prms, nprms)
6399 flipView = !flipView;
6400 DrawPosition(True, NULL);
6403 void GetMoveListProc(w, event, prms, nprms)
6411 appData.getMoveList = !appData.getMoveList;
6413 if (appData.getMoveList) {
6414 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6417 XtSetArg(args[0], XtNleftBitmap, None);
6419 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6424 void HighlightDraggingProc(w, event, prms, nprms)
6432 appData.highlightDragging = !appData.highlightDragging;
6434 if (appData.highlightDragging) {
6435 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6437 XtSetArg(args[0], XtNleftBitmap, None);
6439 XtSetValues(XtNameToWidget(menuBarWidget,
6440 "menuOptions.Highlight Dragging"), args, 1);
6444 void HighlightLastMoveProc(w, event, prms, nprms)
6452 appData.highlightLastMove = !appData.highlightLastMove;
6454 if (appData.highlightLastMove) {
6455 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6457 XtSetArg(args[0], XtNleftBitmap, None);
6459 XtSetValues(XtNameToWidget(menuBarWidget,
6460 "menuOptions.Highlight Last Move"), args, 1);
6463 void IcsAlarmProc(w, event, prms, nprms)
6471 appData.icsAlarm = !appData.icsAlarm;
6473 if (appData.icsAlarm) {
6474 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6476 XtSetArg(args[0], XtNleftBitmap, None);
6478 XtSetValues(XtNameToWidget(menuBarWidget,
6479 "menuOptions.ICS Alarm"), args, 1);
6482 void MoveSoundProc(w, event, prms, nprms)
6490 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6492 if (appData.ringBellAfterMoves) {
6493 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6495 XtSetArg(args[0], XtNleftBitmap, None);
6497 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6502 void OldSaveStyleProc(w, event, prms, nprms)
6510 appData.oldSaveStyle = !appData.oldSaveStyle;
6512 if (appData.oldSaveStyle) {
6513 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6515 XtSetArg(args[0], XtNleftBitmap, None);
6517 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6521 void PeriodicUpdatesProc(w, event, prms, nprms)
6529 PeriodicUpdatesEvent(!appData.periodicUpdates);
6531 if (appData.periodicUpdates) {
6532 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6534 XtSetArg(args[0], XtNleftBitmap, None);
6536 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6540 void PonderNextMoveProc(w, event, prms, nprms)
6548 PonderNextMoveEvent(!appData.ponderNextMove);
6550 if (appData.ponderNextMove) {
6551 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6553 XtSetArg(args[0], XtNleftBitmap, None);
6555 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6559 void PopupExitMessageProc(w, event, prms, nprms)
6567 appData.popupExitMessage = !appData.popupExitMessage;
6569 if (appData.popupExitMessage) {
6570 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6572 XtSetArg(args[0], XtNleftBitmap, None);
6574 XtSetValues(XtNameToWidget(menuBarWidget,
6575 "menuOptions.Popup Exit Message"), args, 1);
6578 void PopupMoveErrorsProc(w, event, prms, nprms)
6586 appData.popupMoveErrors = !appData.popupMoveErrors;
6588 if (appData.popupMoveErrors) {
6589 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6591 XtSetArg(args[0], XtNleftBitmap, None);
6593 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6597 void PremoveProc(w, event, prms, nprms)
6605 appData.premove = !appData.premove;
6607 if (appData.premove) {
6608 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6610 XtSetArg(args[0], XtNleftBitmap, None);
6612 XtSetValues(XtNameToWidget(menuBarWidget,
6613 "menuOptions.Premove"), args, 1);
6616 void QuietPlayProc(w, event, prms, nprms)
6624 appData.quietPlay = !appData.quietPlay;
6626 if (appData.quietPlay) {
6627 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6629 XtSetArg(args[0], XtNleftBitmap, None);
6631 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6635 void ShowCoordsProc(w, event, prms, nprms)
6643 appData.showCoords = !appData.showCoords;
6645 if (appData.showCoords) {
6646 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6648 XtSetArg(args[0], XtNleftBitmap, None);
6650 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6653 DrawPosition(True, NULL);
6656 void ShowThinkingProc(w, event, prms, nprms)
6662 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6663 ShowThinkingEvent();
6666 void HideThinkingProc(w, event, prms, nprms)
6674 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6675 ShowThinkingEvent();
6677 if (appData.hideThinkingFromHuman) {
6678 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6680 XtSetArg(args[0], XtNleftBitmap, None);
6682 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6686 void SaveOnExitProc(w, event, prms, nprms)
6694 saveSettingsOnExit = !saveSettingsOnExit;
6696 if (saveSettingsOnExit) {
6697 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6699 XtSetArg(args[0], XtNleftBitmap, None);
6701 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6705 void SaveSettingsProc(w, event, prms, nprms)
6711 SaveSettings(settingsFileName);
6714 void InfoProc(w, event, prms, nprms)
6721 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6726 void ManProc(w, event, prms, nprms)
6734 if (nprms && *nprms > 0)
6738 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6742 void HintProc(w, event, prms, nprms)
6751 void BookProc(w, event, prms, nprms)
6760 void AboutProc(w, event, prms, nprms)
6768 char *zippy = " (with Zippy code)";
6772 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6773 programVersion, zippy,
6774 "Copyright 1991 Digital Equipment Corporation",
6775 "Enhancements Copyright 1992-2009 Free Software Foundation",
6776 "Enhancements Copyright 2005 Alessandro Scotti",
6777 PACKAGE, " is free software and carries NO WARRANTY;",
6778 "see the file COPYING for more information.");
6779 ErrorPopUp(_("About XBoard"), buf, FALSE);
6782 void DebugProc(w, event, prms, nprms)
6788 appData.debugMode = !appData.debugMode;
6791 void AboutGameProc(w, event, prms, nprms)
6800 void NothingProc(w, event, prms, nprms)
6809 void Iconify(w, event, prms, nprms)
6818 XtSetArg(args[0], XtNiconic, True);
6819 XtSetValues(shellWidget, args, 1);
6822 void DisplayMessage(message, extMessage)
6823 char *message, *extMessage;
6825 /* display a message in the message widget */
6834 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
6839 message = extMessage;
6843 /* need to test if messageWidget already exists, since this function
6844 can also be called during the startup, if for example a Xresource
6845 is not set up correctly */
6848 XtSetArg(arg, XtNlabel, message);
6849 XtSetValues(messageWidget, &arg, 1);
6855 void DisplayTitle(text)
6860 char title[MSG_SIZ];
6863 if (text == NULL) text = "";
6865 if (appData.titleInWindow) {
6867 XtSetArg(args[i], XtNlabel, text); i++;
6868 XtSetValues(titleWidget, args, i);
6871 if (*text != NULLCHAR) {
6873 strcpy(title, text);
6874 } else if (appData.icsActive) {
6875 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
6876 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
6877 } else if (appData.cmailGameName[0] != NULLCHAR) {
6878 snprintf(icon, sizeof(icon), "%s", "CMail");
6879 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
6881 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
6882 } else if (gameInfo.variant == VariantGothic) {
6883 strcpy(icon, programName);
6884 strcpy(title, GOTHIC);
6887 } else if (gameInfo.variant == VariantFalcon) {
6888 strcpy(icon, programName);
6889 strcpy(title, FALCON);
6891 } else if (appData.noChessProgram) {
6892 strcpy(icon, programName);
6893 strcpy(title, programName);
6895 strcpy(icon, first.tidy);
6896 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
6899 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
6900 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
6901 XtSetValues(shellWidget, args, i);
6905 void DisplayError(message, error)
6912 if (appData.debugMode || appData.matchMode) {
6913 fprintf(stderr, "%s: %s\n", programName, message);
6916 if (appData.debugMode || appData.matchMode) {
6917 fprintf(stderr, "%s: %s: %s\n",
6918 programName, message, strerror(error));
6920 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6923 ErrorPopUp(_("Error"), message, FALSE);
6927 void DisplayMoveError(message)
6932 DrawPosition(FALSE, NULL);
6933 if (appData.debugMode || appData.matchMode) {
6934 fprintf(stderr, "%s: %s\n", programName, message);
6936 if (appData.popupMoveErrors) {
6937 ErrorPopUp(_("Error"), message, FALSE);
6939 DisplayMessage(message, "");
6944 void DisplayFatalError(message, error, status)
6950 errorExitStatus = status;
6952 fprintf(stderr, "%s: %s\n", programName, message);
6954 fprintf(stderr, "%s: %s: %s\n",
6955 programName, message, strerror(error));
6956 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6959 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
6960 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
6966 void DisplayInformation(message)
6970 ErrorPopUp(_("Information"), message, TRUE);
6973 void DisplayNote(message)
6977 ErrorPopUp(_("Note"), message, FALSE);
6981 NullXErrorCheck(dpy, error_event)
6983 XErrorEvent *error_event;
6988 void DisplayIcsInteractionTitle(message)
6991 if (oldICSInteractionTitle == NULL) {
6992 /* Magic to find the old window title, adapted from vim */
6993 char *wina = getenv("WINDOWID");
6995 Window win = (Window) atoi(wina);
6996 Window root, parent, *children;
6997 unsigned int nchildren;
6998 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7000 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7001 if (!XQueryTree(xDisplay, win, &root, &parent,
7002 &children, &nchildren)) break;
7003 if (children) XFree((void *)children);
7004 if (parent == root || parent == 0) break;
7007 XSetErrorHandler(oldHandler);
7009 if (oldICSInteractionTitle == NULL) {
7010 oldICSInteractionTitle = "xterm";
7013 printf("\033]0;%s\007", message);
7017 char pendingReplyPrefix[MSG_SIZ];
7018 ProcRef pendingReplyPR;
7020 void AskQuestionProc(w, event, prms, nprms)
7027 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7031 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7034 void AskQuestionPopDown()
7036 if (!askQuestionUp) return;
7037 XtPopdown(askQuestionShell);
7038 XtDestroyWidget(askQuestionShell);
7039 askQuestionUp = False;
7042 void AskQuestionReplyAction(w, event, prms, nprms)
7052 reply = XawDialogGetValueString(w = XtParent(w));
7053 strcpy(buf, pendingReplyPrefix);
7054 if (*buf) strcat(buf, " ");
7057 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7058 AskQuestionPopDown();
7060 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7063 void AskQuestionCallback(w, client_data, call_data)
7065 XtPointer client_data, call_data;
7070 XtSetArg(args[0], XtNlabel, &name);
7071 XtGetValues(w, args, 1);
7073 if (strcmp(name, _("cancel")) == 0) {
7074 AskQuestionPopDown();
7076 AskQuestionReplyAction(w, NULL, NULL, NULL);
7080 void AskQuestion(title, question, replyPrefix, pr)
7081 char *title, *question, *replyPrefix;
7085 Widget popup, layout, dialog, edit;
7091 strcpy(pendingReplyPrefix, replyPrefix);
7092 pendingReplyPR = pr;
7095 XtSetArg(args[i], XtNresizable, True); i++;
7096 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7097 askQuestionShell = popup =
7098 XtCreatePopupShell(title, transientShellWidgetClass,
7099 shellWidget, args, i);
7102 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7103 layoutArgs, XtNumber(layoutArgs));
7106 XtSetArg(args[i], XtNlabel, question); i++;
7107 XtSetArg(args[i], XtNvalue, ""); i++;
7108 XtSetArg(args[i], XtNborderWidth, 0); i++;
7109 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7112 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7113 (XtPointer) dialog);
7114 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7115 (XtPointer) dialog);
7117 XtRealizeWidget(popup);
7118 CatchDeleteWindow(popup, "AskQuestionPopDown");
7120 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7121 &x, &y, &win_x, &win_y, &mask);
7123 XtSetArg(args[0], XtNx, x - 10);
7124 XtSetArg(args[1], XtNy, y - 30);
7125 XtSetValues(popup, args, 2);
7127 XtPopup(popup, XtGrabExclusive);
7128 askQuestionUp = True;
7130 edit = XtNameToWidget(dialog, "*value");
7131 XtSetKeyboardFocus(popup, edit);
7139 if (*name == NULLCHAR) {
7141 } else if (strcmp(name, "$") == 0) {
7142 putc(BELLCHAR, stderr);
7145 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7153 PlaySound(appData.soundMove);
7159 PlaySound(appData.soundIcsWin);
7165 PlaySound(appData.soundIcsLoss);
7171 PlaySound(appData.soundIcsDraw);
7175 PlayIcsUnfinishedSound()
7177 PlaySound(appData.soundIcsUnfinished);
7183 PlaySound(appData.soundIcsAlarm);
7189 system("stty echo");
7195 system("stty -echo");
7199 Colorize(cc, continuation)
7204 int count, outCount, error;
7206 if (textColors[(int)cc].bg > 0) {
7207 if (textColors[(int)cc].fg > 0) {
7208 sprintf(buf, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7209 textColors[(int)cc].fg, textColors[(int)cc].bg);
7211 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7212 textColors[(int)cc].bg);
7215 if (textColors[(int)cc].fg > 0) {
7216 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7217 textColors[(int)cc].fg);
7219 sprintf(buf, "\033[0;%dm", textColors[(int)cc].attr);
7222 count = strlen(buf);
7223 outCount = OutputToProcess(NoProc, buf, count, &error);
7224 if (outCount < count) {
7225 DisplayFatalError(_("Error writing to display"), error, 1);
7228 if (continuation) return;
7231 PlaySound(appData.soundShout);
7234 PlaySound(appData.soundSShout);
7237 PlaySound(appData.soundChannel1);
7240 PlaySound(appData.soundChannel);
7243 PlaySound(appData.soundKibitz);
7246 PlaySound(appData.soundTell);
7248 case ColorChallenge:
7249 PlaySound(appData.soundChallenge);
7252 PlaySound(appData.soundRequest);
7255 PlaySound(appData.soundSeek);
7266 return getpwuid(getuid())->pw_name;
7269 static char *ExpandPathName(path)
7272 static char static_buf[2000];
7273 char *d, *s, buf[2000];
7279 while (*s && isspace(*s))
7288 if (*(s+1) == '/') {
7289 strcpy(d, getpwuid(getuid())->pw_dir);
7294 *strchr(buf, '/') = 0;
7295 pwd = getpwnam(buf);
7298 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7302 strcpy(d, pwd->pw_dir);
7303 strcat(d, strchr(s+1, '/'));
7314 static char host_name[MSG_SIZ];
7316 #if HAVE_GETHOSTNAME
7317 gethostname(host_name, MSG_SIZ);
7319 #else /* not HAVE_GETHOSTNAME */
7320 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7321 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7323 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7325 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7326 #endif /* not HAVE_GETHOSTNAME */
7329 XtIntervalId delayedEventTimerXID = 0;
7330 DelayedEventCallback delayedEventCallback = 0;
7335 delayedEventTimerXID = 0;
7336 delayedEventCallback();
7340 ScheduleDelayedEvent(cb, millisec)
7341 DelayedEventCallback cb; long millisec;
7343 if(delayedEventTimerXID && delayedEventCallback == cb)
7344 // [HGM] alive: replace, rather than add or flush identical event
7345 XtRemoveTimeOut(delayedEventTimerXID);
7346 delayedEventCallback = cb;
7347 delayedEventTimerXID =
7348 XtAppAddTimeOut(appContext, millisec,
7349 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7352 DelayedEventCallback
7355 if (delayedEventTimerXID) {
7356 return delayedEventCallback;
7363 CancelDelayedEvent()
7365 if (delayedEventTimerXID) {
7366 XtRemoveTimeOut(delayedEventTimerXID);
7367 delayedEventTimerXID = 0;
7371 XtIntervalId loadGameTimerXID = 0;
7373 int LoadGameTimerRunning()
7375 return loadGameTimerXID != 0;
7378 int StopLoadGameTimer()
7380 if (loadGameTimerXID != 0) {
7381 XtRemoveTimeOut(loadGameTimerXID);
7382 loadGameTimerXID = 0;
7390 LoadGameTimerCallback(arg, id)
7394 loadGameTimerXID = 0;
7399 StartLoadGameTimer(millisec)
7403 XtAppAddTimeOut(appContext, millisec,
7404 (XtTimerCallbackProc) LoadGameTimerCallback,
7408 XtIntervalId analysisClockXID = 0;
7411 AnalysisClockCallback(arg, id)
7415 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7416 || appData.icsEngineAnalyze) { // [DM]
7417 AnalysisPeriodicEvent(0);
7418 StartAnalysisClock();
7423 StartAnalysisClock()
7426 XtAppAddTimeOut(appContext, 2000,
7427 (XtTimerCallbackProc) AnalysisClockCallback,
7431 XtIntervalId clockTimerXID = 0;
7433 int ClockTimerRunning()
7435 return clockTimerXID != 0;
7438 int StopClockTimer()
7440 if (clockTimerXID != 0) {
7441 XtRemoveTimeOut(clockTimerXID);
7450 ClockTimerCallback(arg, id)
7459 StartClockTimer(millisec)
7463 XtAppAddTimeOut(appContext, millisec,
7464 (XtTimerCallbackProc) ClockTimerCallback,
7469 DisplayTimerLabel(w, color, timer, highlight)
7478 /* check for low time warning */
7479 Pixel foregroundOrWarningColor = timerForegroundPixel;
7482 appData.lowTimeWarning &&
7483 (timer / 1000) < appData.icsAlarmTime)
7484 foregroundOrWarningColor = lowTimeWarningColor;
7486 if (appData.clockMode) {
7487 sprintf(buf, "%s: %s", color, TimeString(timer));
7488 XtSetArg(args[0], XtNlabel, buf);
7490 sprintf(buf, "%s ", color);
7491 XtSetArg(args[0], XtNlabel, buf);
7496 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7497 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7499 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7500 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7503 XtSetValues(w, args, 3);
7507 DisplayWhiteClock(timeRemaining, highlight)
7513 if(appData.noGUI) return;
7514 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7515 if (highlight && iconPixmap == bIconPixmap) {
7516 iconPixmap = wIconPixmap;
7517 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7518 XtSetValues(shellWidget, args, 1);
7523 DisplayBlackClock(timeRemaining, highlight)
7529 if(appData.noGUI) return;
7530 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7531 if (highlight && iconPixmap == wIconPixmap) {
7532 iconPixmap = bIconPixmap;
7533 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7534 XtSetValues(shellWidget, args, 1);
7552 int StartChildProcess(cmdLine, dir, pr)
7559 int to_prog[2], from_prog[2];
7563 if (appData.debugMode) {
7564 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7567 /* We do NOT feed the cmdLine to the shell; we just
7568 parse it into blank-separated arguments in the
7569 most simple-minded way possible.
7572 strcpy(buf, cmdLine);
7575 while(*p == ' ') p++;
7577 if(*p == '"' || *p == '\'')
7578 p = strchr(++argv[i-1], *p);
7579 else p = strchr(p, ' ');
7580 if (p == NULL) break;
7585 SetUpChildIO(to_prog, from_prog);
7587 if ((pid = fork()) == 0) {
7589 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7590 close(to_prog[1]); // first close the unused pipe ends
7591 close(from_prog[0]);
7592 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7593 dup2(from_prog[1], 1);
7594 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7595 close(from_prog[1]); // and closing again loses one of the pipes!
7596 if(fileno(stderr) >= 2) // better safe than sorry...
7597 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7599 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7604 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7606 execvp(argv[0], argv);
7608 /* If we get here, exec failed */
7613 /* Parent process */
7615 close(from_prog[1]);
7617 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7620 cp->fdFrom = from_prog[0];
7621 cp->fdTo = to_prog[1];
7626 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7627 static RETSIGTYPE AlarmCallBack(int n)
7633 DestroyChildProcess(pr, signalType)
7637 ChildProc *cp = (ChildProc *) pr;
7639 if (cp->kind != CPReal) return;
7641 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7642 signal(SIGALRM, AlarmCallBack);
7644 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7645 kill(cp->pid, SIGKILL); // kill it forcefully
7646 wait((int *) 0); // and wait again
7650 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7652 /* Process is exiting either because of the kill or because of
7653 a quit command sent by the backend; either way, wait for it to die.
7662 InterruptChildProcess(pr)
7665 ChildProc *cp = (ChildProc *) pr;
7667 if (cp->kind != CPReal) return;
7668 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7671 int OpenTelnet(host, port, pr)
7676 char cmdLine[MSG_SIZ];
7678 if (port[0] == NULLCHAR) {
7679 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7681 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7683 return StartChildProcess(cmdLine, "", pr);
7686 int OpenTCP(host, port, pr)
7692 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7693 #else /* !OMIT_SOCKETS */
7695 struct sockaddr_in sa;
7697 unsigned short uport;
7700 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7704 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7705 sa.sin_family = AF_INET;
7706 sa.sin_addr.s_addr = INADDR_ANY;
7707 uport = (unsigned short) 0;
7708 sa.sin_port = htons(uport);
7709 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7713 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7714 if (!(hp = gethostbyname(host))) {
7716 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7717 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7718 hp->h_addrtype = AF_INET;
7720 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7721 hp->h_addr_list[0] = (char *) malloc(4);
7722 hp->h_addr_list[0][0] = b0;
7723 hp->h_addr_list[0][1] = b1;
7724 hp->h_addr_list[0][2] = b2;
7725 hp->h_addr_list[0][3] = b3;
7730 sa.sin_family = hp->h_addrtype;
7731 uport = (unsigned short) atoi(port);
7732 sa.sin_port = htons(uport);
7733 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7735 if (connect(s, (struct sockaddr *) &sa,
7736 sizeof(struct sockaddr_in)) < 0) {
7740 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7747 #endif /* !OMIT_SOCKETS */
7752 int OpenCommPort(name, pr)
7759 fd = open(name, 2, 0);
7760 if (fd < 0) return errno;
7762 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7772 int OpenLoopback(pr)
7778 SetUpChildIO(to, from);
7780 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7783 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7790 int OpenRcmd(host, user, cmd, pr)
7791 char *host, *user, *cmd;
7794 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7798 #define INPUT_SOURCE_BUF_SIZE 8192
7807 char buf[INPUT_SOURCE_BUF_SIZE];
7812 DoInputCallback(closure, source, xid)
7817 InputSource *is = (InputSource *) closure;
7822 if (is->lineByLine) {
7823 count = read(is->fd, is->unused,
7824 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7826 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7829 is->unused += count;
7831 while (p < is->unused) {
7832 q = memchr(p, '\n', is->unused - p);
7833 if (q == NULL) break;
7835 (is->func)(is, is->closure, p, q - p, 0);
7839 while (p < is->unused) {
7844 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
7849 (is->func)(is, is->closure, is->buf, count, error);
7853 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
7860 ChildProc *cp = (ChildProc *) pr;
7862 is = (InputSource *) calloc(1, sizeof(InputSource));
7863 is->lineByLine = lineByLine;
7867 is->fd = fileno(stdin);
7869 is->kind = cp->kind;
7870 is->fd = cp->fdFrom;
7873 is->unused = is->buf;
7876 is->xid = XtAppAddInput(appContext, is->fd,
7877 (XtPointer) (XtInputReadMask),
7878 (XtInputCallbackProc) DoInputCallback,
7880 is->closure = closure;
7881 return (InputSourceRef) is;
7885 RemoveInputSource(isr)
7888 InputSource *is = (InputSource *) isr;
7890 if (is->xid == 0) return;
7891 XtRemoveInput(is->xid);
7895 int OutputToProcess(pr, message, count, outError)
7901 static int line = 0;
7902 ChildProc *cp = (ChildProc *) pr;
7907 if (appData.noJoin || !appData.useInternalWrap)
7908 outCount = fwrite(message, 1, count, stdout);
7911 int width = get_term_width();
7912 int len = wrap(NULL, message, count, width, &line);
7913 char *msg = malloc(len);
7917 outCount = fwrite(message, 1, count, stdout);
7920 dbgchk = wrap(msg, message, count, width, &line);
7921 if (dbgchk != len && appData.debugMode)
7922 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
7923 outCount = fwrite(msg, 1, dbgchk, stdout);
7929 outCount = write(cp->fdTo, message, count);
7939 /* Output message to process, with "ms" milliseconds of delay
7940 between each character. This is needed when sending the logon
7941 script to ICC, which for some reason doesn't like the
7942 instantaneous send. */
7943 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
7950 ChildProc *cp = (ChildProc *) pr;
7955 r = write(cp->fdTo, message++, 1);
7968 /**** Animation code by Hugh Fisher, DCS, ANU.
7970 Known problem: if a window overlapping the board is
7971 moved away while a piece is being animated underneath,
7972 the newly exposed area won't be updated properly.
7973 I can live with this.
7975 Known problem: if you look carefully at the animation
7976 of pieces in mono mode, they are being drawn as solid
7977 shapes without interior detail while moving. Fixing
7978 this would be a major complication for minimal return.
7981 /* Masks for XPM pieces. Black and white pieces can have
7982 different shapes, but in the interest of retaining my
7983 sanity pieces must have the same outline on both light
7984 and dark squares, and all pieces must use the same
7985 background square colors/images. */
7987 static int xpmDone = 0;
7990 CreateAnimMasks (pieceDepth)
7997 unsigned long plane;
8000 /* Need a bitmap just to get a GC with right depth */
8001 buf = XCreatePixmap(xDisplay, xBoardWindow,
8003 values.foreground = 1;
8004 values.background = 0;
8005 /* Don't use XtGetGC, not read only */
8006 maskGC = XCreateGC(xDisplay, buf,
8007 GCForeground | GCBackground, &values);
8008 XFreePixmap(xDisplay, buf);
8010 buf = XCreatePixmap(xDisplay, xBoardWindow,
8011 squareSize, squareSize, pieceDepth);
8012 values.foreground = XBlackPixel(xDisplay, xScreen);
8013 values.background = XWhitePixel(xDisplay, xScreen);
8014 bufGC = XCreateGC(xDisplay, buf,
8015 GCForeground | GCBackground, &values);
8017 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8018 /* Begin with empty mask */
8019 if(!xpmDone) // [HGM] pieces: keep using existing
8020 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8021 squareSize, squareSize, 1);
8022 XSetFunction(xDisplay, maskGC, GXclear);
8023 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8024 0, 0, squareSize, squareSize);
8026 /* Take a copy of the piece */
8031 XSetFunction(xDisplay, bufGC, GXcopy);
8032 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8034 0, 0, squareSize, squareSize, 0, 0);
8036 /* XOR the background (light) over the piece */
8037 XSetFunction(xDisplay, bufGC, GXxor);
8039 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8040 0, 0, squareSize, squareSize, 0, 0);
8042 XSetForeground(xDisplay, bufGC, lightSquareColor);
8043 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8046 /* We now have an inverted piece image with the background
8047 erased. Construct mask by just selecting all the non-zero
8048 pixels - no need to reconstruct the original image. */
8049 XSetFunction(xDisplay, maskGC, GXor);
8051 /* Might be quicker to download an XImage and create bitmap
8052 data from it rather than this N copies per piece, but it
8053 only takes a fraction of a second and there is a much
8054 longer delay for loading the pieces. */
8055 for (n = 0; n < pieceDepth; n ++) {
8056 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8057 0, 0, squareSize, squareSize,
8063 XFreePixmap(xDisplay, buf);
8064 XFreeGC(xDisplay, bufGC);
8065 XFreeGC(xDisplay, maskGC);
8069 InitAnimState (anim, info)
8071 XWindowAttributes * info;
8076 /* Each buffer is square size, same depth as window */
8077 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8078 squareSize, squareSize, info->depth);
8079 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8080 squareSize, squareSize, info->depth);
8082 /* Create a plain GC for blitting */
8083 mask = GCForeground | GCBackground | GCFunction |
8084 GCPlaneMask | GCGraphicsExposures;
8085 values.foreground = XBlackPixel(xDisplay, xScreen);
8086 values.background = XWhitePixel(xDisplay, xScreen);
8087 values.function = GXcopy;
8088 values.plane_mask = AllPlanes;
8089 values.graphics_exposures = False;
8090 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8092 /* Piece will be copied from an existing context at
8093 the start of each new animation/drag. */
8094 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8096 /* Outline will be a read-only copy of an existing */
8097 anim->outlineGC = None;
8103 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8104 XWindowAttributes info;
8106 if (xpmDone && gameInfo.variant == old) return;
8107 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8108 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8110 InitAnimState(&game, &info);
8111 InitAnimState(&player, &info);
8113 /* For XPM pieces, we need bitmaps to use as masks. */
8115 CreateAnimMasks(info.depth);
8121 static Boolean frameWaiting;
8123 static RETSIGTYPE FrameAlarm (sig)
8126 frameWaiting = False;
8127 /* In case System-V style signals. Needed?? */
8128 signal(SIGALRM, FrameAlarm);
8135 struct itimerval delay;
8137 XSync(xDisplay, False);
8140 frameWaiting = True;
8141 signal(SIGALRM, FrameAlarm);
8142 delay.it_interval.tv_sec =
8143 delay.it_value.tv_sec = time / 1000;
8144 delay.it_interval.tv_usec =
8145 delay.it_value.tv_usec = (time % 1000) * 1000;
8146 setitimer(ITIMER_REAL, &delay, NULL);
8147 while (frameWaiting) pause();
8148 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8149 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8150 setitimer(ITIMER_REAL, &delay, NULL);
8160 XSync(xDisplay, False);
8162 usleep(time * 1000);
8167 /* Convert board position to corner of screen rect and color */
8170 ScreenSquare(column, row, pt, color)
8171 int column; int row; XPoint * pt; int * color;
8174 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8175 pt->y = lineGap + row * (squareSize + lineGap);
8177 pt->x = lineGap + column * (squareSize + lineGap);
8178 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8180 *color = SquareColor(row, column);
8183 /* Convert window coords to square */
8186 BoardSquare(x, y, column, row)
8187 int x; int y; int * column; int * row;
8189 *column = EventToSquare(x, BOARD_WIDTH);
8190 if (flipView && *column >= 0)
8191 *column = BOARD_WIDTH - 1 - *column;
8192 *row = EventToSquare(y, BOARD_HEIGHT);
8193 if (!flipView && *row >= 0)
8194 *row = BOARD_HEIGHT - 1 - *row;
8199 #undef Max /* just in case */
8201 #define Max(a, b) ((a) > (b) ? (a) : (b))
8202 #define Min(a, b) ((a) < (b) ? (a) : (b))
8205 SetRect(rect, x, y, width, height)
8206 XRectangle * rect; int x; int y; int width; int height;
8210 rect->width = width;
8211 rect->height = height;
8214 /* Test if two frames overlap. If they do, return
8215 intersection rect within old and location of
8216 that rect within new. */
8219 Intersect(old, new, size, area, pt)
8220 XPoint * old; XPoint * new;
8221 int size; XRectangle * area; XPoint * pt;
8223 if (old->x > new->x + size || new->x > old->x + size ||
8224 old->y > new->y + size || new->y > old->y + size) {
8227 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8228 size - abs(old->x - new->x), size - abs(old->y - new->y));
8229 pt->x = Max(old->x - new->x, 0);
8230 pt->y = Max(old->y - new->y, 0);
8235 /* For two overlapping frames, return the rect(s)
8236 in the old that do not intersect with the new. */
8239 CalcUpdateRects(old, new, size, update, nUpdates)
8240 XPoint * old; XPoint * new; int size;
8241 XRectangle update[]; int * nUpdates;
8245 /* If old = new (shouldn't happen) then nothing to draw */
8246 if (old->x == new->x && old->y == new->y) {
8250 /* Work out what bits overlap. Since we know the rects
8251 are the same size we don't need a full intersect calc. */
8253 /* Top or bottom edge? */
8254 if (new->y > old->y) {
8255 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8257 } else if (old->y > new->y) {
8258 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8259 size, old->y - new->y);
8262 /* Left or right edge - don't overlap any update calculated above. */
8263 if (new->x > old->x) {
8264 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8265 new->x - old->x, size - abs(new->y - old->y));
8267 } else if (old->x > new->x) {
8268 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8269 old->x - new->x, size - abs(new->y - old->y));
8276 /* Generate a series of frame coords from start->mid->finish.
8277 The movement rate doubles until the half way point is
8278 reached, then halves back down to the final destination,
8279 which gives a nice slow in/out effect. The algorithmn
8280 may seem to generate too many intermediates for short
8281 moves, but remember that the purpose is to attract the
8282 viewers attention to the piece about to be moved and
8283 then to where it ends up. Too few frames would be less
8287 Tween(start, mid, finish, factor, frames, nFrames)
8288 XPoint * start; XPoint * mid;
8289 XPoint * finish; int factor;
8290 XPoint frames[]; int * nFrames;
8292 int fraction, n, count;
8296 /* Slow in, stepping 1/16th, then 1/8th, ... */
8298 for (n = 0; n < factor; n++)
8300 for (n = 0; n < factor; n++) {
8301 frames[count].x = start->x + (mid->x - start->x) / fraction;
8302 frames[count].y = start->y + (mid->y - start->y) / fraction;
8304 fraction = fraction / 2;
8308 frames[count] = *mid;
8311 /* Slow out, stepping 1/2, then 1/4, ... */
8313 for (n = 0; n < factor; n++) {
8314 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8315 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8317 fraction = fraction * 2;
8322 /* Draw a piece on the screen without disturbing what's there */
8325 SelectGCMask(piece, clip, outline, mask)
8326 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8330 /* Bitmap for piece being moved. */
8331 if (appData.monoMode) {
8332 *mask = *pieceToSolid(piece);
8333 } else if (useImages) {
8335 *mask = xpmMask[piece];
8337 *mask = ximMaskPm[piece];
8340 *mask = *pieceToSolid(piece);
8343 /* GC for piece being moved. Square color doesn't matter, but
8344 since it gets modified we make a copy of the original. */
8346 if (appData.monoMode)
8351 if (appData.monoMode)
8356 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8358 /* Outline only used in mono mode and is not modified */
8360 *outline = bwPieceGC;
8362 *outline = wbPieceGC;
8366 OverlayPiece(piece, clip, outline, dest)
8367 ChessSquare piece; GC clip; GC outline; Drawable dest;
8372 /* Draw solid rectangle which will be clipped to shape of piece */
8373 XFillRectangle(xDisplay, dest, clip,
8374 0, 0, squareSize, squareSize);
8375 if (appData.monoMode)
8376 /* Also draw outline in contrasting color for black
8377 on black / white on white cases */
8378 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8379 0, 0, squareSize, squareSize, 0, 0, 1);
8381 /* Copy the piece */
8386 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8388 0, 0, squareSize, squareSize,
8393 /* Animate the movement of a single piece */
8396 BeginAnimation(anim, piece, startColor, start)
8404 /* The old buffer is initialised with the start square (empty) */
8405 BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8406 anim->prevFrame = *start;
8408 /* The piece will be drawn using its own bitmap as a matte */
8409 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8410 XSetClipMask(xDisplay, anim->pieceGC, mask);
8414 AnimationFrame(anim, frame, piece)
8419 XRectangle updates[4];
8424 /* Save what we are about to draw into the new buffer */
8425 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8426 frame->x, frame->y, squareSize, squareSize,
8429 /* Erase bits of the previous frame */
8430 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8431 /* Where the new frame overlapped the previous,
8432 the contents in newBuf are wrong. */
8433 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8434 overlap.x, overlap.y,
8435 overlap.width, overlap.height,
8437 /* Repaint the areas in the old that don't overlap new */
8438 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8439 for (i = 0; i < count; i++)
8440 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8441 updates[i].x - anim->prevFrame.x,
8442 updates[i].y - anim->prevFrame.y,
8443 updates[i].width, updates[i].height,
8444 updates[i].x, updates[i].y);
8446 /* Easy when no overlap */
8447 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8448 0, 0, squareSize, squareSize,
8449 anim->prevFrame.x, anim->prevFrame.y);
8452 /* Save this frame for next time round */
8453 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8454 0, 0, squareSize, squareSize,
8456 anim->prevFrame = *frame;
8458 /* Draw piece over original screen contents, not current,
8459 and copy entire rect. Wipes out overlapping piece images. */
8460 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8461 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8462 0, 0, squareSize, squareSize,
8463 frame->x, frame->y);
8467 EndAnimation (anim, finish)
8471 XRectangle updates[4];
8476 /* The main code will redraw the final square, so we
8477 only need to erase the bits that don't overlap. */
8478 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8479 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8480 for (i = 0; i < count; i++)
8481 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8482 updates[i].x - anim->prevFrame.x,
8483 updates[i].y - anim->prevFrame.y,
8484 updates[i].width, updates[i].height,
8485 updates[i].x, updates[i].y);
8487 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8488 0, 0, squareSize, squareSize,
8489 anim->prevFrame.x, anim->prevFrame.y);
8494 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8496 ChessSquare piece; int startColor;
8497 XPoint * start; XPoint * finish;
8498 XPoint frames[]; int nFrames;
8502 BeginAnimation(anim, piece, startColor, start);
8503 for (n = 0; n < nFrames; n++) {
8504 AnimationFrame(anim, &(frames[n]), piece);
8505 FrameDelay(appData.animSpeed);
8507 EndAnimation(anim, finish);
8510 /* Main control logic for deciding what to animate and how */
8513 AnimateMove(board, fromX, fromY, toX, toY)
8522 XPoint start, finish, mid;
8523 XPoint frames[kFactor * 2 + 1];
8524 int nFrames, startColor, endColor;
8526 /* Are we animating? */
8527 if (!appData.animate || appData.blindfold)
8530 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8531 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8532 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8534 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8535 piece = board[fromY][fromX];
8536 if (piece >= EmptySquare) return;
8541 hop = (piece == WhiteKnight || piece == BlackKnight);
8544 if (appData.debugMode) {
8545 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8546 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8547 piece, fromX, fromY, toX, toY); }
8549 ScreenSquare(fromX, fromY, &start, &startColor);
8550 ScreenSquare(toX, toY, &finish, &endColor);
8553 /* Knight: make diagonal movement then straight */
8554 if (abs(toY - fromY) < abs(toX - fromX)) {
8555 mid.x = start.x + (finish.x - start.x) / 2;
8559 mid.y = start.y + (finish.y - start.y) / 2;
8562 mid.x = start.x + (finish.x - start.x) / 2;
8563 mid.y = start.y + (finish.y - start.y) / 2;
8566 /* Don't use as many frames for very short moves */
8567 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8568 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8570 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8571 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8573 /* Be sure end square is redrawn */
8574 damage[toY][toX] = True;
8578 DragPieceBegin(x, y)
8581 int boardX, boardY, color;
8584 /* Are we animating? */
8585 if (!appData.animateDragging || appData.blindfold)
8588 /* Figure out which square we start in and the
8589 mouse position relative to top left corner. */
8590 BoardSquare(x, y, &boardX, &boardY);
8591 player.startBoardX = boardX;
8592 player.startBoardY = boardY;
8593 ScreenSquare(boardX, boardY, &corner, &color);
8594 player.startSquare = corner;
8595 player.startColor = color;
8596 /* As soon as we start dragging, the piece will jump slightly to
8597 be centered over the mouse pointer. */
8598 player.mouseDelta.x = squareSize/2;
8599 player.mouseDelta.y = squareSize/2;
8600 /* Initialise animation */
8601 player.dragPiece = PieceForSquare(boardX, boardY);
8603 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8604 player.dragActive = True;
8605 BeginAnimation(&player, player.dragPiece, color, &corner);
8606 /* Mark this square as needing to be redrawn. Note that
8607 we don't remove the piece though, since logically (ie
8608 as seen by opponent) the move hasn't been made yet. */
8609 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8610 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8611 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8612 corner.x, corner.y, squareSize, squareSize,
8613 0, 0); // [HGM] zh: unstack in stead of grab
8614 damage[boardY][boardX] = True;
8616 player.dragActive = False;
8626 /* Are we animating? */
8627 if (!appData.animateDragging || appData.blindfold)
8631 if (! player.dragActive)
8633 /* Move piece, maintaining same relative position
8634 of mouse within square */
8635 corner.x = x - player.mouseDelta.x;
8636 corner.y = y - player.mouseDelta.y;
8637 AnimationFrame(&player, &corner, player.dragPiece);
8639 if (appData.highlightDragging) {
8641 BoardSquare(x, y, &boardX, &boardY);
8642 SetHighlights(fromX, fromY, boardX, boardY);
8651 int boardX, boardY, color;
8654 /* Are we animating? */
8655 if (!appData.animateDragging || appData.blindfold)
8659 if (! player.dragActive)
8661 /* Last frame in sequence is square piece is
8662 placed on, which may not match mouse exactly. */
8663 BoardSquare(x, y, &boardX, &boardY);
8664 ScreenSquare(boardX, boardY, &corner, &color);
8665 EndAnimation(&player, &corner);
8667 /* Be sure end square is redrawn */
8668 damage[boardY][boardX] = True;
8670 /* This prevents weird things happening with fast successive
8671 clicks which on my Sun at least can cause motion events
8672 without corresponding press/release. */
8673 player.dragActive = False;
8676 /* Handle expose event while piece being dragged */
8681 if (!player.dragActive || appData.blindfold)
8684 /* What we're doing: logically, the move hasn't been made yet,
8685 so the piece is still in it's original square. But visually
8686 it's being dragged around the board. So we erase the square
8687 that the piece is on and draw it at the last known drag point. */
8688 BlankSquare(player.startSquare.x, player.startSquare.y,
8689 player.startColor, EmptySquare, xBoardWindow);
8690 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8691 damage[player.startBoardY][player.startBoardX] = TRUE;
8694 #include <sys/ioctl.h>
8695 int get_term_width()
8697 int fd, default_width;
8700 default_width = 79; // this is FICS default anyway...
8702 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8704 if (!ioctl(fd, TIOCGSIZE, &win))
8705 default_width = win.ts_cols;
8706 #elif defined(TIOCGWINSZ)
8708 if (!ioctl(fd, TIOCGWINSZ, &win))
8709 default_width = win.ws_col;
8711 return default_width;
8714 void update_ics_width()
8716 static int old_width = 0;
8717 int new_width = get_term_width();
8719 if (old_width != new_width)
8720 ics_printf("set width %d\n", new_width);
8721 old_width = new_width;
8724 void NotifyFrontendLogin()