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, 2010, 2011 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. */
60 #include <sys/types.h>
66 # if HAVE_SYS_SOCKET_H
67 # include <sys/socket.h>
68 # include <netinet/in.h>
70 # else /* not HAVE_SYS_SOCKET_H */
71 # if HAVE_LAN_SOCKET_H
72 # include <lan/socket.h>
74 # include <lan/netdb.h>
75 # else /* not HAVE_LAN_SOCKET_H */
76 # define OMIT_SOCKETS 1
77 # endif /* not HAVE_LAN_SOCKET_H */
78 # endif /* not HAVE_SYS_SOCKET_H */
79 #endif /* !OMIT_SOCKETS */
84 #else /* not STDC_HEADERS */
85 extern char *getenv();
88 # else /* not HAVE_STRING_H */
90 # endif /* not HAVE_STRING_H */
91 #endif /* not STDC_HEADERS */
94 # include <sys/fcntl.h>
95 #else /* not HAVE_SYS_FCNTL_H */
98 # endif /* HAVE_FCNTL_H */
99 #endif /* not HAVE_SYS_FCNTL_H */
101 #if HAVE_SYS_SYSTEMINFO_H
102 # include <sys/systeminfo.h>
103 #endif /* HAVE_SYS_SYSTEMINFO_H */
105 #if TIME_WITH_SYS_TIME
106 # include <sys/time.h>
110 # include <sys/time.h>
121 # include <sys/wait.h>
126 # define NAMLEN(dirent) strlen((dirent)->d_name)
127 # define HAVE_DIR_STRUCT
129 # define dirent direct
130 # define NAMLEN(dirent) (dirent)->d_namlen
132 # include <sys/ndir.h>
133 # define HAVE_DIR_STRUCT
136 # include <sys/dir.h>
137 # define HAVE_DIR_STRUCT
141 # define HAVE_DIR_STRUCT
145 #include <X11/Intrinsic.h>
146 #include <X11/StringDefs.h>
147 #include <X11/Shell.h>
148 #include <X11/cursorfont.h>
149 #include <X11/Xatom.h>
150 #include <X11/Xmu/Atoms.h>
152 #include <X11/Xaw3d/Dialog.h>
153 #include <X11/Xaw3d/Form.h>
154 #include <X11/Xaw3d/List.h>
155 #include <X11/Xaw3d/Label.h>
156 #include <X11/Xaw3d/SimpleMenu.h>
157 #include <X11/Xaw3d/SmeBSB.h>
158 #include <X11/Xaw3d/SmeLine.h>
159 #include <X11/Xaw3d/Box.h>
160 #include <X11/Xaw3d/MenuButton.h>
161 #include <X11/Xaw3d/Text.h>
162 #include <X11/Xaw3d/AsciiText.h>
164 #include <X11/Xaw/Dialog.h>
165 #include <X11/Xaw/Form.h>
166 #include <X11/Xaw/List.h>
167 #include <X11/Xaw/Label.h>
168 #include <X11/Xaw/SimpleMenu.h>
169 #include <X11/Xaw/SmeBSB.h>
170 #include <X11/Xaw/SmeLine.h>
171 #include <X11/Xaw/Box.h>
172 #include <X11/Xaw/MenuButton.h>
173 #include <X11/Xaw/Text.h>
174 #include <X11/Xaw/AsciiText.h>
177 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
182 #include "pixmaps/pixmaps.h"
183 #define IMAGE_EXT "xpm"
185 #define IMAGE_EXT "xim"
186 #include "bitmaps/bitmaps.h"
189 #include "bitmaps/icon_white.bm"
190 #include "bitmaps/icon_black.bm"
191 #include "bitmaps/checkmark.bm"
193 #include "frontend.h"
195 #include "backendz.h"
199 #include "xgamelist.h"
200 #include "xhistory.h"
201 #include "xedittags.h"
204 // must be moved to xengineoutput.h
206 void EngineOutputProc P((Widget w, XEvent *event,
207 String *prms, Cardinal *nprms));
208 void EvalGraphProc P((Widget w, XEvent *event,
209 String *prms, Cardinal *nprms));
216 #define usleep(t) _sleep2(((t)+500)/1000)
220 # define _(s) gettext (s)
221 # define N_(s) gettext_noop (s)
239 int main P((int argc, char **argv));
240 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
241 char *init_path, char *mode, int (*show_entry)(), char **name_return));
242 RETSIGTYPE CmailSigHandler P((int sig));
243 RETSIGTYPE IntSigHandler P((int sig));
244 RETSIGTYPE TermSizeSigHandler P((int sig));
245 void CreateGCs P((int redo));
246 void CreateXIMPieces P((void));
247 void CreateXPMPieces P((void));
248 void CreateXPMBoard P((char *s, int n));
249 void CreatePieces P((void));
250 void CreatePieceMenus P((void));
251 Widget CreateMenuBar P((Menu *mb));
252 Widget CreateButtonBar P ((MenuItem *mi));
253 char *FindFont P((char *pattern, int targetPxlSize));
254 void PieceMenuPopup P((Widget w, XEvent *event,
255 String *params, Cardinal *num_params));
256 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
257 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
258 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
259 u_int wreq, u_int hreq));
260 void CreateGrid P((void));
261 int EventToSquare P((int x, int limit));
262 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
263 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
264 void HandleUserMove P((Widget w, XEvent *event,
265 String *prms, Cardinal *nprms));
266 void AnimateUserMove P((Widget w, XEvent * event,
267 String * params, Cardinal * nParams));
268 void HandlePV P((Widget w, XEvent * event,
269 String * params, Cardinal * nParams));
270 void SelectPV P((Widget w, XEvent * event,
271 String * params, Cardinal * nParams));
272 void StopPV P((Widget w, XEvent * event,
273 String * params, Cardinal * nParams));
274 void WhiteClock P((Widget w, XEvent *event,
275 String *prms, Cardinal *nprms));
276 void BlackClock P((Widget w, XEvent *event,
277 String *prms, Cardinal *nprms));
278 void DrawPositionProc P((Widget w, XEvent *event,
279 String *prms, Cardinal *nprms));
280 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
282 void CommentClick P((Widget w, XEvent * event,
283 String * params, Cardinal * nParams));
284 void CommentPopUp P((char *title, char *label));
285 void CommentPopDown P((void));
286 void CommentCallback P((Widget w, XtPointer client_data,
287 XtPointer call_data));
288 void ICSInputBoxPopUp P((void));
289 void ICSInputBoxPopDown P((void));
290 void FileNamePopUp P((char *label, char *def,
291 FileProc proc, char *openMode));
292 void FileNamePopDown P((void));
293 void FileNameCallback P((Widget w, XtPointer client_data,
294 XtPointer call_data));
295 void FileNameAction P((Widget w, XEvent *event,
296 String *prms, Cardinal *nprms));
297 void AskQuestionReplyAction P((Widget w, XEvent *event,
298 String *prms, Cardinal *nprms));
299 void AskQuestionProc P((Widget w, XEvent *event,
300 String *prms, Cardinal *nprms));
301 void AskQuestionPopDown P((void));
302 void PromotionPopDown P((void));
303 void PromotionCallback P((Widget w, XtPointer client_data,
304 XtPointer call_data));
305 void EditCommentPopDown P((void));
306 void EditCommentCallback P((Widget w, XtPointer client_data,
307 XtPointer call_data));
308 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
309 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
310 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
311 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
313 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
315 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
317 void LoadPositionProc P((Widget w, XEvent *event,
318 String *prms, Cardinal *nprms));
319 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
321 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
323 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
325 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
327 void PastePositionProc P((Widget w, XEvent *event, String *prms,
329 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
330 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
331 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
332 void SavePositionProc P((Widget w, XEvent *event,
333 String *prms, Cardinal *nprms));
334 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
335 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
337 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
338 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
339 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
341 void MachineWhiteProc P((Widget w, XEvent *event,
342 String *prms, Cardinal *nprms));
343 void AnalyzeModeProc P((Widget w, XEvent *event,
344 String *prms, Cardinal *nprms));
345 void AnalyzeFileProc P((Widget w, XEvent *event,
346 String *prms, Cardinal *nprms));
347 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
349 void MatchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
350 void MatchOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
351 void IcsClientProc P((Widget w, XEvent *event, String *prms,
353 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
354 void EditPositionProc P((Widget w, XEvent *event,
355 String *prms, Cardinal *nprms));
356 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
357 void EditCommentProc P((Widget w, XEvent *event,
358 String *prms, Cardinal *nprms));
359 void IcsInputBoxProc P((Widget w, XEvent *event,
360 String *prms, Cardinal *nprms));
361 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
365 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
370 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
371 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
372 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
373 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
374 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
375 void StopObservingProc P((Widget w, XEvent *event, String *prms,
377 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
379 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
380 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
384 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
385 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
386 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
388 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
390 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
391 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
393 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
395 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
397 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
398 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
399 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
400 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
402 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
403 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
405 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
407 void HighlightArrowProc P((Widget w, XEvent *event, String *prms,
409 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
410 //void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
411 void OneClickProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
412 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
414 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
416 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
418 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
420 //void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
421 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
423 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
425 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
427 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
429 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
430 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
431 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
432 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
433 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
434 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
435 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
436 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void DisplayMove P((int moveNumber));
441 void DisplayTitle P((char *title));
442 void ICSInitScript P((void));
443 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
444 void ErrorPopUp P((char *title, char *text, int modal));
445 void ErrorPopDown P((void));
446 static char *ExpandPathName P((char *path));
447 static void CreateAnimVars P((void));
448 static void DragPieceMove P((int x, int y));
449 static void DrawDragPiece P((void));
450 char *ModeToWidgetName P((GameMode mode));
451 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
452 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
453 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
454 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
455 void OptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
456 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
457 void IcsTextProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
458 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
459 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
460 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
461 void IcsOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
462 void SoundOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
463 void BoardOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
464 void LoadOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
465 void SaveOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
466 void GameListOptionsPopDown P(());
467 void ShufflePopDown P(());
468 void TimeControlPopDown P(());
469 void GenericPopDown P(());
470 void update_ics_width P(());
471 int get_term_width P(());
472 int CopyMemoProc P(());
473 void DrawArrowHighlight P((int fromX, int fromY, int toX,int toY));
474 Boolean IsDrawArrowEnabled P(());
477 * XBoard depends on Xt R4 or higher
479 int xtVersion = XtSpecificationRelease;
484 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
485 jailSquareColor, highlightSquareColor, premoveHighlightColor;
486 Pixel lowTimeWarningColor;
487 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
488 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
489 wjPieceGC, bjPieceGC, prelineGC, countGC;
490 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
491 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
492 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
493 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
494 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
495 ICSInputShell, fileNameShell, askQuestionShell;
496 Widget historyShell, evalGraphShell, gameListShell;
497 int hOffset; // [HGM] dual
498 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
499 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
500 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
501 Font clockFontID, coordFontID, countFontID;
502 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
503 XtAppContext appContext;
505 char *oldICSInteractionTitle;
509 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
511 Position commentX = -1, commentY = -1;
512 Dimension commentW, commentH;
513 typedef unsigned int BoardSize;
515 Boolean chessProgram;
517 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
518 int squareSize, smallLayout = 0, tinyLayout = 0,
519 marginW, marginH, // [HGM] for run-time resizing
520 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
521 ICSInputBoxUp = False, askQuestionUp = False,
522 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
523 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
524 Pixel timerForegroundPixel, timerBackgroundPixel;
525 Pixel buttonForegroundPixel, buttonBackgroundPixel;
526 char *chessDir, *programName, *programVersion,
527 *gameCopyFilename, *gamePasteFilename;
528 Boolean alwaysOnTop = False;
529 Boolean saveSettingsOnExit;
530 char *settingsFileName;
531 char *icsTextMenuString;
533 char *firstChessProgramNames;
534 char *secondChessProgramNames;
536 WindowPlacement wpMain;
537 WindowPlacement wpConsole;
538 WindowPlacement wpComment;
539 WindowPlacement wpMoveHistory;
540 WindowPlacement wpEvalGraph;
541 WindowPlacement wpEngineOutput;
542 WindowPlacement wpGameList;
543 WindowPlacement wpTags;
547 Pixmap pieceBitmap[2][(int)BlackPawn];
548 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
549 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
550 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
551 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
552 Pixmap xpmBoardBitmap[2];
553 int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
554 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
555 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
556 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
557 XImage *ximLightSquare, *ximDarkSquare;
560 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
561 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
563 #define White(piece) ((int)(piece) < (int)BlackPawn)
565 /* Variables for doing smooth animation. This whole thing
566 would be much easier if the board was double-buffered,
567 but that would require a fairly major rewrite. */
572 GC blitGC, pieceGC, outlineGC;
573 XPoint startSquare, prevFrame, mouseDelta;
577 int startBoardX, startBoardY;
580 /* There can be two pieces being animated at once: a player
581 can begin dragging a piece before the remote opponent has moved. */
583 static AnimState game, player;
585 /* Bitmaps for use as masks when drawing XPM pieces.
586 Need one for each black and white piece. */
587 static Pixmap xpmMask[BlackKing + 1];
589 /* This magic number is the number of intermediate frames used
590 in each half of the animation. For short moves it's reduced
591 by 1. The total number of frames will be factor * 2 + 1. */
594 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
596 MenuItem fileMenu[] = {
597 {N_("New Game Ctrl+N"), "New Game", ResetProc},
598 {N_("New Shuffle Game ..."), "New Shuffle Game", ShuffleMenuProc},
599 {N_("New Variant ... Alt+Shift+V"), "New Variant", NewVariantProc}, // [HGM] variant: not functional yet
600 {"----", NULL, NothingProc},
601 {N_("Load Game Ctrl+O"), "Load Game", LoadGameProc},
602 {N_("Load Position Ctrl+Shift+O"), "Load Position", LoadPositionProc},
603 // {N_("Load Next Game"), "Load Next Game", LoadNextGameProc},
604 // {N_("Load Previous Game"), "Load Previous Game", LoadPrevGameProc},
605 // {N_("Reload Same Game"), "Reload Same Game", ReloadGameProc},
606 {N_("Next Position Shift+PgDn"), "Load Next Position", LoadNextPositionProc},
607 {N_("Prev Position Shift+PgUp"), "Load Previous Position", LoadPrevPositionProc},
608 {"----", NULL, NothingProc},
609 // {N_("Reload Same Position"), "Reload Same Position", ReloadPositionProc},
610 {N_("Save Game Ctrl+S"), "Save Game", SaveGameProc},
611 {N_("Save Position Ctrl+Shift+S"), "Save Position", SavePositionProc},
612 {"----", NULL, NothingProc},
613 {N_("Mail Move"), "Mail Move", MailMoveProc},
614 {N_("Reload CMail Message"), "Reload CMail Message", ReloadCmailMsgProc},
615 {"----", NULL, NothingProc},
616 {N_("Quit Ctr+Q"), "Exit", QuitProc},
620 MenuItem editMenu[] = {
621 {N_("Copy Game Ctrl+C"), "Copy Game", CopyGameProc},
622 {N_("Copy Position Ctrl+Shift+C"), "Copy Position", CopyPositionProc},
623 {"----", NULL, NothingProc},
624 {N_("Paste Game Ctrl+V"), "Paste Game", PasteGameProc},
625 {N_("Paste Position Ctrl+Shift+V"), "Paste Position", PastePositionProc},
626 {"----", NULL, NothingProc},
627 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
628 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
629 {N_("Edit Tags"), "Edit Tags", EditTagsProc},
630 {N_("Edit Comment"), "Edit Comment", EditCommentProc},
631 {"----", NULL, NothingProc},
632 {N_("Revert Home"), "Revert", RevertProc},
633 {N_("Annotate"), "Annotate", AnnotateProc},
634 {N_("Truncate Game End"), "Truncate Game", TruncateGameProc},
635 {"----", NULL, NothingProc},
636 {N_("Backward Alt+Left"), "Backward", BackwardProc},
637 {N_("Forward Alt+Right"), "Forward", ForwardProc},
638 {N_("Back to Start Alt+Home"), "Back to Start", ToStartProc},
639 {N_("Forward to End Alt+End"), "Forward to End", ToEndProc},
643 MenuItem viewMenu[] = {
644 {N_("Flip View F2"), "Flip View", FlipViewProc},
645 {"----", NULL, NothingProc},
646 {N_("Engine Output Alt+Shift+O"), "Show Engine Output", EngineOutputProc},
647 {N_("Move History Alt+Shift+H"), "Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
648 {N_("Evaluation Graph Alt+Shift+E"), "Show Evaluation Graph", EvalGraphProc},
649 {N_("Game List Alt+Shift+G"), "Show Game List", ShowGameListProc},
650 {N_("ICS text menu"), "ICStex", IcsTextProc},
651 {"----", NULL, NothingProc},
652 {N_("Tags"), "Show Tags", EditTagsProc},
653 {N_("Comments"), "Show Comments", EditCommentProc},
654 {N_("ICS Input Box"), "ICS Input Box", IcsInputBoxProc},
655 {"----", NULL, NothingProc},
656 {N_("Board..."), "Board Options", BoardOptionsProc},
657 {N_("Game List Tags..."), "Game List", GameListOptionsPopUp},
661 MenuItem modeMenu[] = {
662 {N_("Machine White Ctrl+W"), "Machine White", MachineWhiteProc},
663 {N_("Machine Black Ctrl+B"), "Machine Black", MachineBlackProc},
664 {N_("Two Machines Ctrl+T"), "Two Machines", TwoMachinesProc},
665 {N_("Analysis Mode Ctrl+A"), "Analysis Mode", AnalyzeModeProc},
666 {N_("Analyze File Ctrl+F"), "Analyze File", AnalyzeFileProc },
667 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
668 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
669 {N_("Training"), "Training", TrainingProc},
670 {N_("ICS Client"), "ICS Client", IcsClientProc},
671 {"----", NULL, NothingProc},
672 {N_("Machine Match"), "Machine Match", MatchProc},
673 {N_("Pause Pause"), "Pause", PauseProc},
677 MenuItem actionMenu[] = {
678 {N_("Accept F3"), "Accept", AcceptProc},
679 {N_("Decline F4"), "Decline", DeclineProc},
680 {N_("Rematch F12"), "Rematch", RematchProc},
681 {"----", NULL, NothingProc},
682 {N_("Call Flag F5"), "Call Flag", CallFlagProc},
683 {N_("Draw F6"), "Draw", DrawProc},
684 {N_("Adjourn F7"), "Adjourn", AdjournProc},
685 {N_("Abort F8"),"Abort", AbortProc},
686 {N_("Resign F9"), "Resign", ResignProc},
687 {"----", NULL, NothingProc},
688 {N_("Stop Observing F10"), "Stop Observing", StopObservingProc},
689 {N_("Stop Examining F11"), "Stop Examining", StopExaminingProc},
690 {N_("Upload to Examine"), "Upload to Examine", UploadProc},
691 {"----", NULL, NothingProc},
692 {N_("Adjudicate to White"), "Adjudicate to White", AdjuWhiteProc},
693 {N_("Adjudicate to Black"), "Adjudicate to Black", AdjuBlackProc},
694 {N_("Adjudicate Draw"), "Adjudicate Draw", AdjuDrawProc},
698 MenuItem engineMenu[] = {
699 {N_("Engine #1 Settings ..."), "Engine #1 Settings", FirstSettingsProc},
700 {N_("Engine #2 Settings ..."), "Engine #2 Settings", SecondSettingsProc},
701 {"----", NULL, NothingProc},
702 {N_("Hint"), "Hint", HintProc},
703 {N_("Book"), "Book", BookProc},
704 {"----", NULL, NothingProc},
705 {N_("Move Now Ctrl+M"), "Move Now", MoveNowProc},
706 {N_("Retract Move Ctrl+X"), "Retract Move", RetractMoveProc},
710 MenuItem optionsMenu[] = {
711 #define OPTIONSDIALOG
713 {N_("General ..."), "General", OptionsProc},
715 {N_("Time Control ... Alt+Shift+T"), "Time Control", TimeControlProc},
716 {N_("Common Engine ... Alt+Shift+U"), "Common Engine", UciMenuProc},
717 {N_("Adjudications ... Alt+Shift+J"), "Adjudications", EngineMenuProc},
718 {N_("ICS ..."), "ICS", IcsOptionsProc},
719 {N_("Match ..."), "Match", MatchOptionsProc},
720 {N_("Load Game ..."), "Load Game", LoadOptionsProc},
721 {N_("Save Game ..."), "Save Game", SaveOptionsProc},
722 // {N_(" ..."), "", OptionsProc},
723 {N_("Game List ..."), "Game List", GameListOptionsPopUp},
724 {N_("Sounds ..."), "Sounds", SoundOptionsProc},
725 {"----", NULL, NothingProc},
726 #ifndef OPTIONSDIALOG
727 {N_("Always Queen Ctrl+Shift+Q"), "Always Queen", AlwaysQueenProc},
728 {N_("Animate Dragging"), "Animate Dragging", AnimateDraggingProc},
729 {N_("Animate Moving Ctrl+Shift+A"), "Animate Moving", AnimateMovingProc},
730 {N_("Auto Flag Ctrl+Shift+F"), "Auto Flag", AutoflagProc},
731 {N_("Auto Flip View"), "Auto Flip View", AutoflipProc},
732 {N_("Blindfold"), "Blindfold", BlindfoldProc},
733 {N_("Flash Moves"), "Flash Moves", FlashMovesProc},
735 {N_("Highlight Dragging"), "Highlight Dragging", HighlightDraggingProc},
737 {N_("Highlight Last Move"), "Highlight Last Move", HighlightLastMoveProc},
738 {N_("Highlight With Arrow"), "Arrow", HighlightArrowProc},
739 {N_("Move Sound"), "Move Sound", MoveSoundProc},
740 // {N_("ICS Alarm"), "ICS Alarm", IcsAlarmProc},
741 {N_("One-Click Moving"), "OneClick", OneClickProc},
742 {N_("Periodic Updates"), "Periodic Updates", PeriodicUpdatesProc},
743 {N_("Ponder Next Move Ctrl+Shift+P"), "Ponder Next Move", PonderNextMoveProc},
744 {N_("Popup Exit Message"), "Popup Exit Message", PopupExitMessageProc},
745 {N_("Popup Move Errors"), "Popup Move Errors", PopupMoveErrorsProc},
746 // {N_("Premove"), "Premove", PremoveProc},
747 {N_("Show Coords"), "Show Coords", ShowCoordsProc},
748 {N_("Hide Thinking Ctrl+Shift+H"), "Hide Thinking", HideThinkingProc},
749 {N_("Test Legality Ctrl+Shift+L"), "Test Legality", TestLegalityProc},
750 {"----", NULL, NothingProc},
752 {N_("Save Settings Now"), "Save Settings Now", SaveSettingsProc},
753 {N_("Save Settings on Exit"), "Save Settings on Exit", SaveOnExitProc},
757 MenuItem helpMenu[] = {
758 {N_("Info XBoard"), "Info XBoard", InfoProc},
759 {N_("Man XBoard F1"), "Man XBoard", ManProc},
760 {"----", NULL, NothingProc},
761 {N_("About XBoard"), "About XBoard", AboutProc},
766 {N_("File"), "File", fileMenu},
767 {N_("Edit"), "Edit", editMenu},
768 {N_("View"), "View", viewMenu},
769 {N_("Mode"), "Mode", modeMenu},
770 {N_("Action"), "Action", actionMenu},
771 {N_("Engine"), "Engine", engineMenu},
772 {N_("Options"), "Options", optionsMenu},
773 {N_("Help"), "Help", helpMenu},
777 #define PAUSE_BUTTON "P"
778 MenuItem buttonBar[] = {
779 {"<<", "<<", ToStartProc},
780 {"<", "<", BackwardProc},
781 {PAUSE_BUTTON, PAUSE_BUTTON, PauseProc},
782 {">", ">", ForwardProc},
783 {">>", ">>", ToEndProc},
787 #define PIECE_MENU_SIZE 18
788 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
789 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
790 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
791 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
792 N_("Empty square"), N_("Clear board") },
793 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
794 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
795 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
796 N_("Empty square"), N_("Clear board") }
798 /* must be in same order as PieceMenuStrings! */
799 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
800 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
801 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
802 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
803 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
804 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
805 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
806 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
807 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
810 #define DROP_MENU_SIZE 6
811 String dropMenuStrings[DROP_MENU_SIZE] = {
812 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
814 /* must be in same order as PieceMenuStrings! */
815 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
816 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
817 WhiteRook, WhiteQueen
825 DropMenuEnables dmEnables[] = {
843 { XtNborderWidth, 0 },
844 { XtNdefaultDistance, 0 },
848 { XtNborderWidth, 0 },
849 { XtNresizable, (XtArgVal) True },
853 { XtNborderWidth, 0 },
859 { XtNjustify, (XtArgVal) XtJustifyRight },
860 { XtNlabel, (XtArgVal) "..." },
861 { XtNresizable, (XtArgVal) True },
862 { XtNresize, (XtArgVal) False }
865 Arg messageArgs[] = {
866 { XtNjustify, (XtArgVal) XtJustifyLeft },
867 { XtNlabel, (XtArgVal) "..." },
868 { XtNresizable, (XtArgVal) True },
869 { XtNresize, (XtArgVal) False }
873 { XtNborderWidth, 0 },
874 { XtNjustify, (XtArgVal) XtJustifyLeft }
877 XtResource clientResources[] = {
878 { "flashCount", "flashCount", XtRInt, sizeof(int),
879 XtOffset(AppDataPtr, flashCount), XtRImmediate,
880 (XtPointer) FLASH_COUNT },
883 XrmOptionDescRec shellOptions[] = {
884 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
885 { "-flash", "flashCount", XrmoptionNoArg, "3" },
886 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
889 XtActionsRec boardActions[] = {
890 { "DrawPosition", DrawPositionProc },
891 { "HandleUserMove", HandleUserMove },
892 { "AnimateUserMove", AnimateUserMove },
893 { "HandlePV", HandlePV },
894 { "SelectPV", SelectPV },
895 { "StopPV", StopPV },
896 { "FileNameAction", FileNameAction },
897 { "AskQuestionProc", AskQuestionProc },
898 { "AskQuestionReplyAction", AskQuestionReplyAction },
899 { "PieceMenuPopup", PieceMenuPopup },
900 { "WhiteClock", WhiteClock },
901 { "BlackClock", BlackClock },
902 { "Iconify", Iconify },
903 { "ResetProc", ResetProc },
904 { "NewVariantProc", NewVariantProc },
905 { "LoadGameProc", LoadGameProc },
906 { "LoadNextGameProc", LoadNextGameProc },
907 { "LoadPrevGameProc", LoadPrevGameProc },
908 { "LoadSelectedProc", LoadSelectedProc },
909 { "SetFilterProc", SetFilterProc },
910 { "ReloadGameProc", ReloadGameProc },
911 { "LoadPositionProc", LoadPositionProc },
912 { "LoadNextPositionProc", LoadNextPositionProc },
913 { "LoadPrevPositionProc", LoadPrevPositionProc },
914 { "ReloadPositionProc", ReloadPositionProc },
915 { "CopyPositionProc", CopyPositionProc },
916 { "PastePositionProc", PastePositionProc },
917 { "CopyGameProc", CopyGameProc },
918 { "PasteGameProc", PasteGameProc },
919 { "SaveGameProc", SaveGameProc },
920 { "SavePositionProc", SavePositionProc },
921 { "MailMoveProc", MailMoveProc },
922 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
923 { "QuitProc", QuitProc },
924 { "MachineWhiteProc", MachineWhiteProc },
925 { "MachineBlackProc", MachineBlackProc },
926 { "AnalysisModeProc", AnalyzeModeProc },
927 { "AnalyzeFileProc", AnalyzeFileProc },
928 { "TwoMachinesProc", TwoMachinesProc },
929 { "IcsClientProc", IcsClientProc },
930 { "EditGameProc", EditGameProc },
931 { "EditPositionProc", EditPositionProc },
932 { "TrainingProc", EditPositionProc },
933 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
934 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
935 { "ShowGameListProc", ShowGameListProc },
936 { "ShowMoveListProc", HistoryShowProc},
937 { "EditTagsProc", EditCommentProc },
938 { "EditCommentProc", EditCommentProc },
939 { "IcsInputBoxProc", IcsInputBoxProc },
940 { "PauseProc", PauseProc },
941 { "AcceptProc", AcceptProc },
942 { "DeclineProc", DeclineProc },
943 { "RematchProc", RematchProc },
944 { "CallFlagProc", CallFlagProc },
945 { "DrawProc", DrawProc },
946 { "AdjournProc", AdjournProc },
947 { "AbortProc", AbortProc },
948 { "ResignProc", ResignProc },
949 { "AdjuWhiteProc", AdjuWhiteProc },
950 { "AdjuBlackProc", AdjuBlackProc },
951 { "AdjuDrawProc", AdjuDrawProc },
952 { "EnterKeyProc", EnterKeyProc },
953 { "UpKeyProc", UpKeyProc },
954 { "DownKeyProc", DownKeyProc },
955 { "StopObservingProc", StopObservingProc },
956 { "StopExaminingProc", StopExaminingProc },
957 { "UploadProc", UploadProc },
958 { "BackwardProc", BackwardProc },
959 { "ForwardProc", ForwardProc },
960 { "ToStartProc", ToStartProc },
961 { "ToEndProc", ToEndProc },
962 { "RevertProc", RevertProc },
963 { "AnnotateProc", AnnotateProc },
964 { "TruncateGameProc", TruncateGameProc },
965 { "MoveNowProc", MoveNowProc },
966 { "RetractMoveProc", RetractMoveProc },
967 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
968 { "UciMenuProc", (XtActionProc) UciMenuProc },
969 { "TimeControlProc", (XtActionProc) TimeControlProc },
970 { "FlipViewProc", FlipViewProc },
971 { "PonderNextMoveProc", PonderNextMoveProc },
972 #ifndef OPTIONSDIALOG
973 { "AlwaysQueenProc", AlwaysQueenProc },
974 { "AnimateDraggingProc", AnimateDraggingProc },
975 { "AnimateMovingProc", AnimateMovingProc },
976 { "AutoflagProc", AutoflagProc },
977 { "AutoflipProc", AutoflipProc },
978 { "BlindfoldProc", BlindfoldProc },
979 { "FlashMovesProc", FlashMovesProc },
981 { "HighlightDraggingProc", HighlightDraggingProc },
983 { "HighlightLastMoveProc", HighlightLastMoveProc },
984 // { "IcsAlarmProc", IcsAlarmProc },
985 { "MoveSoundProc", MoveSoundProc },
986 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
987 { "PopupExitMessageProc", PopupExitMessageProc },
988 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
989 // { "PremoveProc", PremoveProc },
990 { "ShowCoordsProc", ShowCoordsProc },
991 { "ShowThinkingProc", ShowThinkingProc },
992 { "HideThinkingProc", HideThinkingProc },
993 { "TestLegalityProc", TestLegalityProc },
995 { "SaveSettingsProc", SaveSettingsProc },
996 { "SaveOnExitProc", SaveOnExitProc },
997 { "InfoProc", InfoProc },
998 { "ManProc", ManProc },
999 { "HintProc", HintProc },
1000 { "BookProc", BookProc },
1001 { "AboutGameProc", AboutGameProc },
1002 { "AboutProc", AboutProc },
1003 { "DebugProc", DebugProc },
1004 { "NothingProc", NothingProc },
1005 { "CommentClick", (XtActionProc) CommentClick },
1006 { "CommentPopDown", (XtActionProc) CommentPopDown },
1007 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
1008 { "TagsPopDown", (XtActionProc) TagsPopDown },
1009 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
1010 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
1011 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
1012 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
1013 { "GameListPopDown", (XtActionProc) GameListPopDown },
1014 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
1015 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1016 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
1017 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1018 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1019 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
1020 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
1021 { "GenericPopDown", (XtActionProc) GenericPopDown },
1022 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1025 char globalTranslations[] =
1026 ":<Key>F9: ResignProc() \n \
1027 :Ctrl<Key>n: ResetProc() \n \
1028 :Meta<Key>V: NewVariantProc() \n \
1029 :Ctrl<Key>o: LoadGameProc() \n \
1030 :Meta<Key>Next: LoadNextGameProc() \n \
1031 :Meta<Key>Prior: LoadPrevGameProc() \n \
1032 :Ctrl<Key>s: SaveGameProc() \n \
1033 :Ctrl<Key>c: CopyGameProc() \n \
1034 :Ctrl<Key>v: PasteGameProc() \n \
1035 :Ctrl<Key>O: LoadPositionProc() \n \
1036 :Shift<Key>Next: LoadNextPositionProc() \n \
1037 :Shift<Key>Prior: LoadPrevPositionProc() \n \
1038 :Ctrl<Key>S: SavePositionProc() \n \
1039 :Ctrl<Key>C: CopyPositionProc() \n \
1040 :Ctrl<Key>V: PastePositionProc() \n \
1041 :Ctrl<Key>q: QuitProc() \n \
1042 :Ctrl<Key>w: MachineWhiteProc() \n \
1043 :Ctrl<Key>b: MachineBlackProc() \n \
1044 :Ctrl<Key>t: TwoMachinesProc() \n \
1045 :Ctrl<Key>a: AnalysisModeProc() \n \
1046 :Ctrl<Key>f: AnalyzeFileProc() \n \
1047 :Ctrl<Key>e: EditGameProc() \n \
1048 :Ctrl<Key>E: EditPositionProc() \n \
1049 :Meta<Key>O: EngineOutputProc() \n \
1050 :Meta<Key>E: EvalGraphProc() \n \
1051 :Meta<Key>G: ShowGameListProc() \n \
1052 :Meta<Key>H: ShowMoveListProc() \n \
1053 :<Key>Pause: PauseProc() \n \
1054 :<Key>F3: AcceptProc() \n \
1055 :<Key>F4: DeclineProc() \n \
1056 :<Key>F12: RematchProc() \n \
1057 :<Key>F5: CallFlagProc() \n \
1058 :<Key>F6: DrawProc() \n \
1059 :<Key>F7: AdjournProc() \n \
1060 :<Key>F8: AbortProc() \n \
1061 :<Key>F10: StopObservingProc() \n \
1062 :<Key>F11: StopExaminingProc() \n \
1063 :Meta Ctrl<Key>F12: DebugProc() \n \
1064 :Meta<Key>End: ToEndProc() \n \
1065 :Meta<Key>Right: ForwardProc() \n \
1066 :Meta<Key>Home: ToStartProc() \n \
1067 :Meta<Key>Left: BackwardProc() \n \
1068 :<Key>Home: RevertProc() \n \
1069 :<Key>End: TruncateGameProc() \n \
1070 :Ctrl<Key>m: MoveNowProc() \n \
1071 :Ctrl<Key>x: RetractMoveProc() \n \
1072 :Meta<Key>J: EngineMenuProc() \n \
1073 :Meta<Key>U: UciMenuProc() \n \
1074 :Meta<Key>T: TimeControlProc() \n \
1075 :Ctrl<Key>P: PonderNextMoveProc() \n "
1076 #ifndef OPTIONSDIALOG
1078 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1079 :Ctrl<Key>F: AutoflagProc() \n \
1080 :Ctrl<Key>A: AnimateMovingProc() \n \
1081 :Ctrl<Key>L: TestLegalityProc() \n \
1082 :Ctrl<Key>H: HideThinkingProc() \n "
1085 :<Key>-: Iconify() \n \
1086 :<Key>F1: ManProc() \n \
1087 :<Key>F2: FlipViewProc() \n \
1088 <KeyDown>.: BackwardProc() \n \
1089 <KeyUp>.: ForwardProc() \n \
1090 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1091 \"Send to chess program:\",,1) \n \
1092 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1093 \"Send to second chess program:\",,2) \n";
1095 char boardTranslations[] =
1096 "<Btn1Down>: HandleUserMove(0) \n \
1097 Shift<Btn1Up>: HandleUserMove(1) \n \
1098 <Btn1Up>: HandleUserMove(0) \n \
1099 <Btn1Motion>: AnimateUserMove() \n \
1100 <Btn3Motion>: HandlePV() \n \
1101 <Btn3Up>: PieceMenuPopup(menuB) \n \
1102 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1103 PieceMenuPopup(menuB) \n \
1104 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1105 PieceMenuPopup(menuW) \n \
1106 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1107 PieceMenuPopup(menuW) \n \
1108 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1109 PieceMenuPopup(menuB) \n";
1111 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1112 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1114 char ICSInputTranslations[] =
1115 "<Key>Up: UpKeyProc() \n "
1116 "<Key>Down: DownKeyProc() \n "
1117 "<Key>Return: EnterKeyProc() \n";
1119 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1120 // as the widget is destroyed before the up-click can call extend-end
1121 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1123 String xboardResources[] = {
1124 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1125 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1126 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1131 /* Max possible square size */
1132 #define MAXSQSIZE 256
1134 static int xpm_avail[MAXSQSIZE];
1136 #ifdef HAVE_DIR_STRUCT
1138 /* Extract piece size from filename */
1140 xpm_getsize(name, len, ext)
1151 if ((p=strchr(name, '.')) == NULL ||
1152 StrCaseCmp(p+1, ext) != 0)
1158 while (*p && isdigit(*p))
1165 /* Setup xpm_avail */
1167 xpm_getavail(dirname, ext)
1175 for (i=0; i<MAXSQSIZE; ++i)
1178 if (appData.debugMode)
1179 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1181 dir = opendir(dirname);
1184 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1185 programName, dirname);
1189 while ((ent=readdir(dir)) != NULL) {
1190 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1191 if (i > 0 && i < MAXSQSIZE)
1201 xpm_print_avail(fp, ext)
1207 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1208 for (i=1; i<MAXSQSIZE; ++i) {
1214 /* Return XPM piecesize closest to size */
1216 xpm_closest_to(dirname, size, ext)
1222 int sm_diff = MAXSQSIZE;
1226 xpm_getavail(dirname, ext);
1228 if (appData.debugMode)
1229 xpm_print_avail(stderr, ext);
1231 for (i=1; i<MAXSQSIZE; ++i) {
1234 diff = (diff<0) ? -diff : diff;
1235 if (diff < sm_diff) {
1243 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1249 #else /* !HAVE_DIR_STRUCT */
1250 /* If we are on a system without a DIR struct, we can't
1251 read the directory, so we can't collect a list of
1252 filenames, etc., so we can't do any size-fitting. */
1254 xpm_closest_to(dirname, size, ext)
1259 fprintf(stderr, _("\
1260 Warning: No DIR structure found on this system --\n\
1261 Unable to autosize for XPM/XIM pieces.\n\
1262 Please report this error to frankm@hiwaay.net.\n\
1263 Include system type & operating system in message.\n"));
1266 #endif /* HAVE_DIR_STRUCT */
1268 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1269 "magenta", "cyan", "white" };
1273 TextColors textColors[(int)NColorClasses];
1275 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1277 parse_color(str, which)
1281 char *p, buf[100], *d;
1284 if (strlen(str) > 99) /* watch bounds on buf */
1289 for (i=0; i<which; ++i) {
1296 /* Could be looking at something like:
1298 .. in which case we want to stop on a comma also */
1299 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1303 return -1; /* Use default for empty field */
1306 if (which == 2 || isdigit(*p))
1309 while (*p && isalpha(*p))
1314 for (i=0; i<8; ++i) {
1315 if (!StrCaseCmp(buf, cnames[i]))
1316 return which? (i+40) : (i+30);
1318 if (!StrCaseCmp(buf, "default")) return -1;
1320 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1325 parse_cpair(cc, str)
1329 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1330 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1335 /* bg and attr are optional */
1336 textColors[(int)cc].bg = parse_color(str, 1);
1337 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1338 textColors[(int)cc].attr = 0;
1344 /* Arrange to catch delete-window events */
1345 Atom wm_delete_window;
1347 CatchDeleteWindow(Widget w, String procname)
1350 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1351 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1352 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1359 XtSetArg(args[0], XtNiconic, False);
1360 XtSetValues(shellWidget, args, 1);
1362 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1365 //---------------------------------------------------------------------------------------------------------
1366 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1369 #define CW_USEDEFAULT (1<<31)
1370 #define ICS_TEXT_MENU_SIZE 90
1371 #define DEBUG_FILE "xboard.debug"
1372 #define SetCurrentDirectory chdir
1373 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1377 // these two must some day move to frontend.h, when they are implemented
1378 Boolean GameListIsUp();
1380 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1383 // front-end part of option handling
1385 // [HGM] This platform-dependent table provides the location for storing the color info
1386 extern char *crWhite, * crBlack;
1390 &appData.whitePieceColor,
1391 &appData.blackPieceColor,
1392 &appData.lightSquareColor,
1393 &appData.darkSquareColor,
1394 &appData.highlightSquareColor,
1395 &appData.premoveHighlightColor,
1396 &appData.lowTimeWarningColor,
1407 // [HGM] font: keep a font for each square size, even non-stndard ones
1408 #define NUM_SIZES 18
1409 #define MAX_SIZE 130
1410 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1411 char *fontTable[NUM_FONTS][MAX_SIZE];
1414 ParseFont(char *name, int number)
1415 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1417 if(sscanf(name, "size%d:", &size)) {
1418 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1419 // defer processing it until we know if it matches our board size
1420 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1421 fontTable[number][size] = strdup(strchr(name, ':')+1);
1422 fontValid[number][size] = True;
1427 case 0: // CLOCK_FONT
1428 appData.clockFont = strdup(name);
1430 case 1: // MESSAGE_FONT
1431 appData.font = strdup(name);
1433 case 2: // COORD_FONT
1434 appData.coordFont = strdup(name);
1439 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1444 { // only 2 fonts currently
1445 appData.clockFont = CLOCK_FONT_NAME;
1446 appData.coordFont = COORD_FONT_NAME;
1447 appData.font = DEFAULT_FONT_NAME;
1452 { // no-op, until we identify the code for this already in XBoard and move it here
1456 ParseColor(int n, char *name)
1457 { // in XBoard, just copy the color-name string
1458 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1462 ParseTextAttribs(ColorClass cc, char *s)
1464 (&appData.colorShout)[cc] = strdup(s);
1468 ParseBoardSize(void *addr, char *name)
1470 appData.boardSize = strdup(name);
1475 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1479 SetCommPortDefaults()
1480 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1483 // [HGM] args: these three cases taken out to stay in front-end
1485 SaveFontArg(FILE *f, ArgDescriptor *ad)
1488 int i, n = (int)(intptr_t)ad->argLoc;
1490 case 0: // CLOCK_FONT
1491 name = appData.clockFont;
1493 case 1: // MESSAGE_FONT
1494 name = appData.font;
1496 case 2: // COORD_FONT
1497 name = appData.coordFont;
1502 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1503 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1504 fontTable[n][squareSize] = strdup(name);
1505 fontValid[n][squareSize] = True;
1508 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1509 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1514 { // nothing to do, as the sounds are at all times represented by their text-string names already
1518 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1519 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1520 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
1524 SaveColor(FILE *f, ArgDescriptor *ad)
1525 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1526 if(colorVariable[(int)(intptr_t)ad->argLoc])
1527 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
1531 SaveBoardSize(FILE *f, char *name, void *addr)
1532 { // wrapper to shield back-end from BoardSize & sizeInfo
1533 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1537 ParseCommPortSettings(char *s)
1538 { // no such option in XBoard (yet)
1541 extern Widget engineOutputShell;
1542 extern Widget tagsShell, editTagsShell;
1544 GetActualPlacement(Widget wg, WindowPlacement *wp)
1554 XtSetArg(args[i], XtNx, &x); i++;
1555 XtSetArg(args[i], XtNy, &y); i++;
1556 XtSetArg(args[i], XtNwidth, &w); i++;
1557 XtSetArg(args[i], XtNheight, &h); i++;
1558 XtGetValues(wg, args, i);
1567 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1568 // In XBoard this will have to wait until awareness of window parameters is implemented
1569 GetActualPlacement(shellWidget, &wpMain);
1570 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1571 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1572 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1573 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1574 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1575 else GetActualPlacement(editShell, &wpComment);
1576 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1577 else GetActualPlacement(editTagsShell, &wpTags);
1581 PrintCommPortSettings(FILE *f, char *name)
1582 { // This option does not exist in XBoard
1586 MySearchPath(char *installDir, char *name, char *fullname)
1587 { // just append installDir and name. Perhaps ExpandPath should be used here?
1588 name = ExpandPathName(name);
1589 if(name && name[0] == '/')
1590 safeStrCpy(fullname, name, MSG_SIZ );
1592 sprintf(fullname, "%s%c%s", installDir, '/', name);
1598 MyGetFullPathName(char *name, char *fullname)
1599 { // should use ExpandPath?
1600 name = ExpandPathName(name);
1601 safeStrCpy(fullname, name, MSG_SIZ );
1606 EnsureOnScreen(int *x, int *y, int minX, int minY)
1613 { // [HGM] args: allows testing if main window is realized from back-end
1614 return xBoardWindow != 0;
1618 PopUpStartupDialog()
1619 { // start menu not implemented in XBoard
1623 ConvertToLine(int argc, char **argv)
1625 static char line[128*1024], buf[1024];
1629 for(i=1; i<argc; i++)
1631 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1632 && argv[i][0] != '{' )
1633 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1635 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1636 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1639 line[strlen(line)-1] = NULLCHAR;
1643 //--------------------------------------------------------------------------------------------
1645 extern Boolean twoBoards, partnerUp;
1648 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1650 #define BoardSize int
1651 void InitDrawingSizes(BoardSize boardSize, int flags)
1652 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1653 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1655 XtGeometryResult gres;
1658 if(!formWidget) return;
1661 * Enable shell resizing.
1663 shellArgs[0].value = (XtArgVal) &w;
1664 shellArgs[1].value = (XtArgVal) &h;
1665 XtGetValues(shellWidget, shellArgs, 2);
1667 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1668 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1669 XtSetValues(shellWidget, &shellArgs[2], 4);
1671 XtSetArg(args[0], XtNdefaultDistance, &sep);
1672 XtGetValues(formWidget, args, 1);
1674 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1675 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1676 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1678 hOffset = boardWidth + 10;
1679 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1680 secondSegments[i] = gridSegments[i];
1681 secondSegments[i].x1 += hOffset;
1682 secondSegments[i].x2 += hOffset;
1685 XtSetArg(args[0], XtNwidth, boardWidth);
1686 XtSetArg(args[1], XtNheight, boardHeight);
1687 XtSetValues(boardWidget, args, 2);
1689 timerWidth = (boardWidth - sep) / 2;
1690 XtSetArg(args[0], XtNwidth, timerWidth);
1691 XtSetValues(whiteTimerWidget, args, 1);
1692 XtSetValues(blackTimerWidget, args, 1);
1694 XawFormDoLayout(formWidget, False);
1696 if (appData.titleInWindow) {
1698 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1699 XtSetArg(args[i], XtNheight, &h); i++;
1700 XtGetValues(titleWidget, args, i);
1702 w = boardWidth - 2*bor;
1704 XtSetArg(args[0], XtNwidth, &w);
1705 XtGetValues(menuBarWidget, args, 1);
1706 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1709 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1710 if (gres != XtGeometryYes && appData.debugMode) {
1712 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1713 programName, gres, w, h, wr, hr);
1717 XawFormDoLayout(formWidget, True);
1720 * Inhibit shell resizing.
1722 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1723 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1724 shellArgs[4].value = shellArgs[2].value = w;
1725 shellArgs[5].value = shellArgs[3].value = h;
1726 XtSetValues(shellWidget, &shellArgs[0], 6);
1728 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1731 for(i=0; i<4; i++) {
1733 for(p=0; p<=(int)WhiteKing; p++)
1734 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1735 if(gameInfo.variant == VariantShogi) {
1736 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1737 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1738 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1739 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1740 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1743 if(gameInfo.variant == VariantGothic) {
1744 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1747 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1748 xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
1749 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1752 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1753 for(p=0; p<=(int)WhiteKing; p++)
1754 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1755 if(gameInfo.variant == VariantShogi) {
1756 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1757 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1758 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1759 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1760 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1763 if(gameInfo.variant == VariantGothic) {
1764 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1767 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1768 ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
1769 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1774 for(i=0; i<2; i++) {
1776 for(p=0; p<=(int)WhiteKing; p++)
1777 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1778 if(gameInfo.variant == VariantShogi) {
1779 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1780 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1781 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1782 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1783 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1786 if(gameInfo.variant == VariantGothic) {
1787 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1790 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1791 pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
1792 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1802 void ParseIcsTextColors()
1803 { // [HGM] tken out of main(), so it can be called from ICS-Options dialog
1804 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1805 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1806 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1807 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1808 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1809 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1810 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1811 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1812 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1813 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1815 if (appData.colorize) {
1817 _("%s: can't parse color names; disabling colorization\n"),
1820 appData.colorize = FALSE;
1825 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
1826 XrmValue vFrom, vTo;
1827 int forceMono = False;
1829 if (!appData.monoMode) {
1830 vFrom.addr = (caddr_t) appData.lightSquareColor;
1831 vFrom.size = strlen(appData.lightSquareColor);
1832 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1833 if (vTo.addr == NULL) {
1834 appData.monoMode = True;
1837 lightSquareColor = *(Pixel *) vTo.addr;
1840 if (!appData.monoMode) {
1841 vFrom.addr = (caddr_t) appData.darkSquareColor;
1842 vFrom.size = strlen(appData.darkSquareColor);
1843 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1844 if (vTo.addr == NULL) {
1845 appData.monoMode = True;
1848 darkSquareColor = *(Pixel *) vTo.addr;
1851 if (!appData.monoMode) {
1852 vFrom.addr = (caddr_t) appData.whitePieceColor;
1853 vFrom.size = strlen(appData.whitePieceColor);
1854 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1855 if (vTo.addr == NULL) {
1856 appData.monoMode = True;
1859 whitePieceColor = *(Pixel *) vTo.addr;
1862 if (!appData.monoMode) {
1863 vFrom.addr = (caddr_t) appData.blackPieceColor;
1864 vFrom.size = strlen(appData.blackPieceColor);
1865 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1866 if (vTo.addr == NULL) {
1867 appData.monoMode = True;
1870 blackPieceColor = *(Pixel *) vTo.addr;
1874 if (!appData.monoMode) {
1875 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1876 vFrom.size = strlen(appData.highlightSquareColor);
1877 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1878 if (vTo.addr == NULL) {
1879 appData.monoMode = True;
1882 highlightSquareColor = *(Pixel *) vTo.addr;
1886 if (!appData.monoMode) {
1887 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1888 vFrom.size = strlen(appData.premoveHighlightColor);
1889 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1890 if (vTo.addr == NULL) {
1891 appData.monoMode = True;
1894 premoveHighlightColor = *(Pixel *) vTo.addr;
1905 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1906 XSetWindowAttributes window_attributes;
1908 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1909 XrmValue vFrom, vTo;
1910 XtGeometryResult gres;
1913 int forceMono = False;
1915 srandom(time(0)); // [HGM] book: make random truly random
1917 setbuf(stdout, NULL);
1918 setbuf(stderr, NULL);
1921 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1922 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1926 programName = strrchr(argv[0], '/');
1927 if (programName == NULL)
1928 programName = argv[0];
1933 XtSetLanguageProc(NULL, NULL, NULL);
1934 bindtextdomain(PACKAGE, LOCALEDIR);
1935 textdomain(PACKAGE);
1939 XtAppInitialize(&appContext, "XBoard", shellOptions,
1940 XtNumber(shellOptions),
1941 &argc, argv, xboardResources, NULL, 0);
1942 appData.boardSize = "";
1943 InitAppData(ConvertToLine(argc, argv));
1945 if (p == NULL) p = "/tmp";
1946 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1947 gameCopyFilename = (char*) malloc(i);
1948 gamePasteFilename = (char*) malloc(i);
1949 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1950 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1952 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1953 clientResources, XtNumber(clientResources),
1956 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1957 static char buf[MSG_SIZ];
1958 EscapeExpand(buf, appData.initString);
1959 appData.initString = strdup(buf);
1960 EscapeExpand(buf, appData.secondInitString);
1961 appData.secondInitString = strdup(buf);
1962 EscapeExpand(buf, appData.firstComputerString);
1963 appData.firstComputerString = strdup(buf);
1964 EscapeExpand(buf, appData.secondComputerString);
1965 appData.secondComputerString = strdup(buf);
1968 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1971 if (chdir(chessDir) != 0) {
1972 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1978 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1979 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1980 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1981 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1984 setbuf(debugFP, NULL);
1987 /* [HGM,HR] make sure board size is acceptable */
1988 if(appData.NrFiles > BOARD_FILES ||
1989 appData.NrRanks > BOARD_RANKS )
1990 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1993 /* This feature does not work; animation needs a rewrite */
1994 appData.highlightDragging = FALSE;
1998 xDisplay = XtDisplay(shellWidget);
1999 xScreen = DefaultScreen(xDisplay);
2000 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
2002 gameInfo.variant = StringToVariant(appData.variant);
2003 InitPosition(FALSE);
2006 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
2008 if (isdigit(appData.boardSize[0])) {
2009 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
2010 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
2011 &fontPxlSize, &smallLayout, &tinyLayout);
2013 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
2014 programName, appData.boardSize);
2018 /* Find some defaults; use the nearest known size */
2019 SizeDefaults *szd, *nearest;
2020 int distance = 99999;
2021 nearest = szd = sizeDefaults;
2022 while (szd->name != NULL) {
2023 if (abs(szd->squareSize - squareSize) < distance) {
2025 distance = abs(szd->squareSize - squareSize);
2026 if (distance == 0) break;
2030 if (i < 2) lineGap = nearest->lineGap;
2031 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
2032 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
2033 if (i < 5) fontPxlSize = nearest->fontPxlSize;
2034 if (i < 6) smallLayout = nearest->smallLayout;
2035 if (i < 7) tinyLayout = nearest->tinyLayout;
2038 SizeDefaults *szd = sizeDefaults;
2039 if (*appData.boardSize == NULLCHAR) {
2040 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
2041 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
2044 if (szd->name == NULL) szd--;
2045 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
2047 while (szd->name != NULL &&
2048 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
2049 if (szd->name == NULL) {
2050 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
2051 programName, appData.boardSize);
2055 squareSize = szd->squareSize;
2056 lineGap = szd->lineGap;
2057 clockFontPxlSize = szd->clockFontPxlSize;
2058 coordFontPxlSize = szd->coordFontPxlSize;
2059 fontPxlSize = szd->fontPxlSize;
2060 smallLayout = szd->smallLayout;
2061 tinyLayout = szd->tinyLayout;
2062 // [HGM] font: use defaults from settings file if available and not overruled
2064 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
2065 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
2066 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
2067 appData.font = fontTable[MESSAGE_FONT][squareSize];
2068 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
2069 appData.coordFont = fontTable[COORD_FONT][squareSize];
2071 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
2072 if (strlen(appData.pixmapDirectory) > 0) {
2073 p = ExpandPathName(appData.pixmapDirectory);
2075 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
2076 appData.pixmapDirectory);
2079 if (appData.debugMode) {
2080 fprintf(stderr, _("\
2081 XBoard square size (hint): %d\n\
2082 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
2084 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
2085 if (appData.debugMode) {
2086 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
2089 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
2091 /* [HR] height treated separately (hacked) */
2092 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
2093 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
2094 if (appData.showJail == 1) {
2095 /* Jail on top and bottom */
2096 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2097 XtSetArg(boardArgs[2], XtNheight,
2098 boardHeight + 2*(lineGap + squareSize));
2099 } else if (appData.showJail == 2) {
2101 XtSetArg(boardArgs[1], XtNwidth,
2102 boardWidth + 2*(lineGap + squareSize));
2103 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2106 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2107 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2111 * Determine what fonts to use.
2113 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2114 clockFontID = XLoadFont(xDisplay, appData.clockFont);
2115 clockFontStruct = XQueryFont(xDisplay, clockFontID);
2116 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2117 coordFontID = XLoadFont(xDisplay, appData.coordFont);
2118 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2119 appData.font = FindFont(appData.font, fontPxlSize);
2120 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
2121 countFontStruct = XQueryFont(xDisplay, countFontID);
2122 // appData.font = FindFont(appData.font, fontPxlSize);
2124 xdb = XtDatabase(xDisplay);
2125 XrmPutStringResource(&xdb, "*font", appData.font);
2128 * Detect if there are not enough colors available and adapt.
2130 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2131 appData.monoMode = True;
2134 forceMono = MakeColors();
2137 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2140 if (appData.bitmapDirectory == NULL ||
2141 appData.bitmapDirectory[0] == NULLCHAR)
2142 appData.bitmapDirectory = DEF_BITMAP_DIR;
2145 if (appData.lowTimeWarning && !appData.monoMode) {
2146 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2147 vFrom.size = strlen(appData.lowTimeWarningColor);
2148 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2149 if (vTo.addr == NULL)
2150 appData.monoMode = True;
2152 lowTimeWarningColor = *(Pixel *) vTo.addr;
2155 if (appData.monoMode && appData.debugMode) {
2156 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2157 (unsigned long) XWhitePixel(xDisplay, xScreen),
2158 (unsigned long) XBlackPixel(xDisplay, xScreen));
2161 ParseIcsTextColors();
2162 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2163 textColors[ColorNone].attr = 0;
2165 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2171 layoutName = "tinyLayout";
2172 } else if (smallLayout) {
2173 layoutName = "smallLayout";
2175 layoutName = "normalLayout";
2177 /* Outer layoutWidget is there only to provide a name for use in
2178 resources that depend on the layout style */
2180 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2181 layoutArgs, XtNumber(layoutArgs));
2183 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2184 formArgs, XtNumber(formArgs));
2185 XtSetArg(args[0], XtNdefaultDistance, &sep);
2186 XtGetValues(formWidget, args, 1);
2189 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2190 XtSetArg(args[0], XtNtop, XtChainTop);
2191 XtSetArg(args[1], XtNbottom, XtChainTop);
2192 XtSetArg(args[2], XtNright, XtChainLeft);
2193 XtSetValues(menuBarWidget, args, 3);
2195 widgetList[j++] = whiteTimerWidget =
2196 XtCreateWidget("whiteTime", labelWidgetClass,
2197 formWidget, timerArgs, XtNumber(timerArgs));
2198 XtSetArg(args[0], XtNfont, clockFontStruct);
2199 XtSetArg(args[1], XtNtop, XtChainTop);
2200 XtSetArg(args[2], XtNbottom, XtChainTop);
2201 XtSetValues(whiteTimerWidget, args, 3);
2203 widgetList[j++] = blackTimerWidget =
2204 XtCreateWidget("blackTime", labelWidgetClass,
2205 formWidget, timerArgs, XtNumber(timerArgs));
2206 XtSetArg(args[0], XtNfont, clockFontStruct);
2207 XtSetArg(args[1], XtNtop, XtChainTop);
2208 XtSetArg(args[2], XtNbottom, XtChainTop);
2209 XtSetValues(blackTimerWidget, args, 3);
2211 if (appData.titleInWindow) {
2212 widgetList[j++] = titleWidget =
2213 XtCreateWidget("title", labelWidgetClass, formWidget,
2214 titleArgs, XtNumber(titleArgs));
2215 XtSetArg(args[0], XtNtop, XtChainTop);
2216 XtSetArg(args[1], XtNbottom, XtChainTop);
2217 XtSetValues(titleWidget, args, 2);
2220 if (appData.showButtonBar) {
2221 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2222 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2223 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2224 XtSetArg(args[2], XtNtop, XtChainTop);
2225 XtSetArg(args[3], XtNbottom, XtChainTop);
2226 XtSetValues(buttonBarWidget, args, 4);
2229 widgetList[j++] = messageWidget =
2230 XtCreateWidget("message", labelWidgetClass, formWidget,
2231 messageArgs, XtNumber(messageArgs));
2232 XtSetArg(args[0], XtNtop, XtChainTop);
2233 XtSetArg(args[1], XtNbottom, XtChainTop);
2234 XtSetValues(messageWidget, args, 2);
2236 widgetList[j++] = boardWidget =
2237 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2238 XtNumber(boardArgs));
2240 XtManageChildren(widgetList, j);
2242 timerWidth = (boardWidth - sep) / 2;
2243 XtSetArg(args[0], XtNwidth, timerWidth);
2244 XtSetValues(whiteTimerWidget, args, 1);
2245 XtSetValues(blackTimerWidget, args, 1);
2247 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2248 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2249 XtGetValues(whiteTimerWidget, args, 2);
2251 if (appData.showButtonBar) {
2252 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2253 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2254 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2258 * formWidget uses these constraints but they are stored
2262 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2263 XtSetValues(menuBarWidget, args, i);
2264 if (appData.titleInWindow) {
2267 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2268 XtSetValues(whiteTimerWidget, args, i);
2270 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2271 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2272 XtSetValues(blackTimerWidget, args, i);
2274 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2275 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2276 XtSetValues(titleWidget, args, i);
2278 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2279 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2280 XtSetValues(messageWidget, args, i);
2281 if (appData.showButtonBar) {
2283 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2284 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2285 XtSetValues(buttonBarWidget, args, i);
2289 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2290 XtSetValues(whiteTimerWidget, args, i);
2292 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2293 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2294 XtSetValues(blackTimerWidget, args, i);
2296 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2297 XtSetValues(titleWidget, args, i);
2299 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2300 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2301 XtSetValues(messageWidget, args, i);
2302 if (appData.showButtonBar) {
2304 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2305 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2306 XtSetValues(buttonBarWidget, args, i);
2311 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2312 XtSetValues(whiteTimerWidget, args, i);
2314 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2315 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2316 XtSetValues(blackTimerWidget, args, i);
2318 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2319 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2320 XtSetValues(messageWidget, args, i);
2321 if (appData.showButtonBar) {
2323 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2324 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2325 XtSetValues(buttonBarWidget, args, i);
2329 XtSetArg(args[0], XtNfromVert, messageWidget);
2330 XtSetArg(args[1], XtNtop, XtChainTop);
2331 XtSetArg(args[2], XtNbottom, XtChainBottom);
2332 XtSetArg(args[3], XtNleft, XtChainLeft);
2333 XtSetArg(args[4], XtNright, XtChainRight);
2334 XtSetValues(boardWidget, args, 5);
2336 XtRealizeWidget(shellWidget);
2339 XtSetArg(args[0], XtNx, wpMain.x);
2340 XtSetArg(args[1], XtNy, wpMain.y);
2341 XtSetValues(shellWidget, args, 2);
2345 * Correct the width of the message and title widgets.
2346 * It is not known why some systems need the extra fudge term.
2347 * The value "2" is probably larger than needed.
2349 XawFormDoLayout(formWidget, False);
2351 #define WIDTH_FUDGE 2
2353 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2354 XtSetArg(args[i], XtNheight, &h); i++;
2355 XtGetValues(messageWidget, args, i);
2356 if (appData.showButtonBar) {
2358 XtSetArg(args[i], XtNwidth, &w); i++;
2359 XtGetValues(buttonBarWidget, args, i);
2360 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2362 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2365 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2366 if (gres != XtGeometryYes && appData.debugMode) {
2367 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2368 programName, gres, w, h, wr, hr);
2371 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2372 /* The size used for the child widget in layout lags one resize behind
2373 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2375 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2376 if (gres != XtGeometryYes && appData.debugMode) {
2377 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2378 programName, gres, w, h, wr, hr);
2381 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2382 XtSetArg(args[1], XtNright, XtChainRight);
2383 XtSetValues(messageWidget, args, 2);
2385 if (appData.titleInWindow) {
2387 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2388 XtSetArg(args[i], XtNheight, &h); i++;
2389 XtGetValues(titleWidget, args, i);
2391 w = boardWidth - 2*bor;
2393 XtSetArg(args[0], XtNwidth, &w);
2394 XtGetValues(menuBarWidget, args, 1);
2395 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2398 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2399 if (gres != XtGeometryYes && appData.debugMode) {
2401 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2402 programName, gres, w, h, wr, hr);
2405 XawFormDoLayout(formWidget, True);
2407 xBoardWindow = XtWindow(boardWidget);
2409 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2410 // not need to go into InitDrawingSizes().
2414 * Create X checkmark bitmap and initialize option menu checks.
2416 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2417 checkmark_bits, checkmark_width, checkmark_height);
2418 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2419 #ifndef OPTIONSDIALOG
2420 if (appData.alwaysPromoteToQueen) {
2421 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2424 if (appData.animateDragging) {
2425 XtSetValues(XtNameToWidget(menuBarWidget,
2426 "menuOptions.Animate Dragging"),
2429 if (appData.animate) {
2430 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2433 if (appData.autoCallFlag) {
2434 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2437 if (appData.autoFlipView) {
2438 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2441 if (appData.blindfold) {
2442 XtSetValues(XtNameToWidget(menuBarWidget,
2443 "menuOptions.Blindfold"), args, 1);
2445 if (appData.flashCount > 0) {
2446 XtSetValues(XtNameToWidget(menuBarWidget,
2447 "menuOptions.Flash Moves"),
2451 if (appData.highlightDragging) {
2452 XtSetValues(XtNameToWidget(menuBarWidget,
2453 "menuOptions.Highlight Dragging"),
2457 if (appData.highlightLastMove) {
2458 XtSetValues(XtNameToWidget(menuBarWidget,
2459 "menuOptions.Highlight Last Move"),
2462 if (appData.highlightMoveWithArrow) {
2463 XtSetValues(XtNameToWidget(menuBarWidget,
2464 "menuOptions.Arrow"),
2467 // if (appData.icsAlarm) {
2468 // XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2471 if (appData.ringBellAfterMoves) {
2472 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2475 if (appData.oneClick) {
2476 XtSetValues(XtNameToWidget(menuBarWidget,
2477 "menuOptions.OneClick"), args, 1);
2479 if (appData.periodicUpdates) {
2480 XtSetValues(XtNameToWidget(menuBarWidget,
2481 "menuOptions.Periodic Updates"), args, 1);
2483 if (appData.ponderNextMove) {
2484 XtSetValues(XtNameToWidget(menuBarWidget,
2485 "menuOptions.Ponder Next Move"), args, 1);
2487 if (appData.popupExitMessage) {
2488 XtSetValues(XtNameToWidget(menuBarWidget,
2489 "menuOptions.Popup Exit Message"), args, 1);
2491 if (appData.popupMoveErrors) {
2492 XtSetValues(XtNameToWidget(menuBarWidget,
2493 "menuOptions.Popup Move Errors"), args, 1);
2495 // if (appData.premove) {
2496 // XtSetValues(XtNameToWidget(menuBarWidget,
2497 // "menuOptions.Premove"), args, 1);
2499 if (appData.showCoords) {
2500 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2503 if (appData.hideThinkingFromHuman) {
2504 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2507 if (appData.testLegality) {
2508 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2512 if (saveSettingsOnExit) {
2513 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2520 ReadBitmap(&wIconPixmap, "icon_white.bm",
2521 icon_white_bits, icon_white_width, icon_white_height);
2522 ReadBitmap(&bIconPixmap, "icon_black.bm",
2523 icon_black_bits, icon_black_width, icon_black_height);
2524 iconPixmap = wIconPixmap;
2526 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2527 XtSetValues(shellWidget, args, i);
2530 * Create a cursor for the board widget.
2532 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2533 XChangeWindowAttributes(xDisplay, xBoardWindow,
2534 CWCursor, &window_attributes);
2537 * Inhibit shell resizing.
2539 shellArgs[0].value = (XtArgVal) &w;
2540 shellArgs[1].value = (XtArgVal) &h;
2541 XtGetValues(shellWidget, shellArgs, 2);
2542 shellArgs[4].value = shellArgs[2].value = w;
2543 shellArgs[5].value = shellArgs[3].value = h;
2544 XtSetValues(shellWidget, &shellArgs[2], 4);
2545 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2546 marginH = h - boardHeight;
2548 CatchDeleteWindow(shellWidget, "QuitProc");
2553 if (appData.bitmapDirectory[0] != NULLCHAR) {
2557 CreateXPMBoard(appData.liteBackTextureFile, 1);
2558 CreateXPMBoard(appData.darkBackTextureFile, 0);
2562 /* Create regular pieces */
2563 if (!useImages) CreatePieces();
2568 if (appData.animate || appData.animateDragging)
2571 XtAugmentTranslations(formWidget,
2572 XtParseTranslationTable(globalTranslations));
2573 XtAugmentTranslations(boardWidget,
2574 XtParseTranslationTable(boardTranslations));
2575 XtAugmentTranslations(whiteTimerWidget,
2576 XtParseTranslationTable(whiteTranslations));
2577 XtAugmentTranslations(blackTimerWidget,
2578 XtParseTranslationTable(blackTranslations));
2580 /* Why is the following needed on some versions of X instead
2581 * of a translation? */
2582 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2583 (XtEventHandler) EventProc, NULL);
2586 /* [AS] Restore layout */
2587 if( wpMoveHistory.visible ) {
2591 if( wpEvalGraph.visible )
2596 if( wpEngineOutput.visible ) {
2597 EngineOutputPopUp();
2602 if (errorExitStatus == -1) {
2603 if (appData.icsActive) {
2604 /* We now wait until we see "login:" from the ICS before
2605 sending the logon script (problems with timestamp otherwise) */
2606 /*ICSInitScript();*/
2607 if (appData.icsInputBox) ICSInputBoxPopUp();
2611 signal(SIGWINCH, TermSizeSigHandler);
2613 signal(SIGINT, IntSigHandler);
2614 signal(SIGTERM, IntSigHandler);
2615 if (*appData.cmailGameName != NULLCHAR) {
2616 signal(SIGUSR1, CmailSigHandler);
2619 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2621 XtSetKeyboardFocus(shellWidget, formWidget);
2623 XtAppMainLoop(appContext);
2624 if (appData.debugMode) fclose(debugFP); // [DM] debug
2631 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2632 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2634 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2635 unlink(gameCopyFilename);
2636 unlink(gamePasteFilename);
2639 RETSIGTYPE TermSizeSigHandler(int sig)
2652 CmailSigHandler(sig)
2658 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2660 /* Activate call-back function CmailSigHandlerCallBack() */
2661 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2663 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2667 CmailSigHandlerCallBack(isr, closure, message, count, error)
2675 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2677 /**** end signal code ****/
2683 /* try to open the icsLogon script, either in the location given
2684 * or in the users HOME directory
2691 f = fopen(appData.icsLogon, "r");
2694 homedir = getenv("HOME");
2695 if (homedir != NULL)
2697 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2698 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2699 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2700 f = fopen(buf, "r");
2705 ProcessICSInitScript(f);
2707 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2716 EditCommentPopDown();
2731 if (!menuBarWidget) return;
2732 w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2734 DisplayError("menuEdit.Revert", 0);
2736 XtSetSensitive(w, !grey);
2738 w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2740 DisplayError("menuEdit.Annotate", 0);
2742 XtSetSensitive(w, !grey);
2747 SetMenuEnables(enab)
2751 if (!menuBarWidget) return;
2752 while (enab->name != NULL) {
2753 w = XtNameToWidget(menuBarWidget, enab->name);
2755 DisplayError(enab->name, 0);
2757 XtSetSensitive(w, enab->value);
2763 Enables icsEnables[] = {
2764 { "menuFile.Mail Move", False },
2765 { "menuFile.Reload CMail Message", False },
2766 { "menuMode.Machine Black", False },
2767 { "menuMode.Machine White", False },
2768 { "menuMode.Analysis Mode", False },
2769 { "menuMode.Analyze File", False },
2770 { "menuMode.Two Machines", False },
2771 { "menuMode.Machine Match", False },
2773 { "menuEngine.Hint", False },
2774 { "menuEngine.Book", False },
2775 { "menuEngine.Move Now", False },
2776 #ifndef OPTIONSDIALOG
2777 { "menuOptions.Periodic Updates", False },
2778 { "menuOptions.Hide Thinking", False },
2779 { "menuOptions.Ponder Next Move", False },
2781 { "menuEngine.Engine #1 Settings", False },
2783 { "menuEngine.Engine #2 Settings", False },
2784 { "menuEdit.Annotate", False },
2788 Enables ncpEnables[] = {
2789 { "menuFile.Mail Move", False },
2790 { "menuFile.Reload CMail Message", False },
2791 { "menuMode.Machine White", False },
2792 { "menuMode.Machine Black", False },
2793 { "menuMode.Analysis Mode", False },
2794 { "menuMode.Analyze File", False },
2795 { "menuMode.Two Machines", False },
2796 { "menuMode.Machine Match", False },
2797 { "menuMode.ICS Client", False },
2798 { "menuView.ICStex", False },
2799 { "menuView.ICS Input Box", False },
2800 { "Action", False },
2801 { "menuEdit.Revert", False },
2802 { "menuEdit.Annotate", False },
2803 { "menuEngine.Engine #1 Settings", False },
2804 { "menuEngine.Engine #2 Settings", False },
2805 { "menuEngine.Move Now", False },
2806 { "menuEngine.Retract Move", False },
2807 { "menuOptions.ICS", False },
2808 #ifndef OPTIONSDIALOG
2809 { "menuOptions.Auto Flag", False },
2810 { "menuOptions.Auto Flip View", False },
2811 // { "menuOptions.ICS Alarm", False },
2812 { "menuOptions.Move Sound", False },
2813 { "menuOptions.Hide Thinking", False },
2814 { "menuOptions.Periodic Updates", False },
2815 { "menuOptions.Ponder Next Move", False },
2817 { "menuEngine.Hint", False },
2818 { "menuEngine.Book", False },
2822 Enables gnuEnables[] = {
2823 { "menuMode.ICS Client", False },
2824 { "menuView.ICStex", False },
2825 { "menuView.ICS Input Box", False },
2826 { "menuAction.Accept", False },
2827 { "menuAction.Decline", False },
2828 { "menuAction.Rematch", False },
2829 { "menuAction.Adjourn", False },
2830 { "menuAction.Stop Examining", False },
2831 { "menuAction.Stop Observing", False },
2832 { "menuAction.Upload to Examine", False },
2833 { "menuEdit.Revert", False },
2834 { "menuEdit.Annotate", False },
2835 { "menuOptions.ICS", False },
2837 /* The next two options rely on SetCmailMode being called *after* */
2838 /* SetGNUMode so that when GNU is being used to give hints these */
2839 /* menu options are still available */
2841 { "menuFile.Mail Move", False },
2842 { "menuFile.Reload CMail Message", False },
2846 Enables cmailEnables[] = {
2848 { "menuAction.Call Flag", False },
2849 { "menuAction.Draw", True },
2850 { "menuAction.Adjourn", False },
2851 { "menuAction.Abort", False },
2852 { "menuAction.Stop Observing", False },
2853 { "menuAction.Stop Examining", False },
2854 { "menuFile.Mail Move", True },
2855 { "menuFile.Reload CMail Message", True },
2859 Enables trainingOnEnables[] = {
2860 { "menuMode.Edit Comment", False },
2861 { "menuMode.Pause", False },
2862 { "menuEdit.Forward", False },
2863 { "menuEdit.Backward", False },
2864 { "menuEdit.Forward to End", False },
2865 { "menuEdit.Back to Start", False },
2866 { "menuEngine.Move Now", False },
2867 { "menuEdit.Truncate Game", False },
2871 Enables trainingOffEnables[] = {
2872 { "menuMode.Edit Comment", True },
2873 { "menuMode.Pause", True },
2874 { "menuEdit.Forward", True },
2875 { "menuEdit.Backward", True },
2876 { "menuEdit.Forward to End", True },
2877 { "menuEdit.Back to Start", True },
2878 { "menuEngine.Move Now", True },
2879 { "menuEdit.Truncate Game", True },
2883 Enables machineThinkingEnables[] = {
2884 { "menuFile.Load Game", False },
2885 // { "menuFile.Load Next Game", False },
2886 // { "menuFile.Load Previous Game", False },
2887 // { "menuFile.Reload Same Game", False },
2888 { "menuEdit.Paste Game", False },
2889 { "menuFile.Load Position", False },
2890 // { "menuFile.Load Next Position", False },
2891 // { "menuFile.Load Previous Position", False },
2892 // { "menuFile.Reload Same Position", False },
2893 { "menuEdit.Paste Position", False },
2894 { "menuMode.Machine White", False },
2895 { "menuMode.Machine Black", False },
2896 { "menuMode.Two Machines", False },
2897 { "menuMode.Machine Match", False },
2898 { "menuEngine.Retract Move", False },
2902 Enables userThinkingEnables[] = {
2903 { "menuFile.Load Game", True },
2904 // { "menuFile.Load Next Game", True },
2905 // { "menuFile.Load Previous Game", True },
2906 // { "menuFile.Reload Same Game", True },
2907 { "menuEdit.Paste Game", True },
2908 { "menuFile.Load Position", True },
2909 // { "menuFile.Load Next Position", True },
2910 // { "menuFile.Load Previous Position", True },
2911 // { "menuFile.Reload Same Position", True },
2912 { "menuEdit.Paste Position", True },
2913 { "menuMode.Machine White", True },
2914 { "menuMode.Machine Black", True },
2915 { "menuMode.Two Machines", True },
2916 { "menuMode.Machine Match", True },
2917 { "menuEngine.Retract Move", True },
2923 SetMenuEnables(icsEnables);
2926 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2927 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2934 SetMenuEnables(ncpEnables);
2940 SetMenuEnables(gnuEnables);
2946 SetMenuEnables(cmailEnables);
2952 SetMenuEnables(trainingOnEnables);
2953 if (appData.showButtonBar) {
2954 XtSetSensitive(buttonBarWidget, False);
2960 SetTrainingModeOff()
2962 SetMenuEnables(trainingOffEnables);
2963 if (appData.showButtonBar) {
2964 XtSetSensitive(buttonBarWidget, True);
2969 SetUserThinkingEnables()
2971 if (appData.noChessProgram) return;
2972 SetMenuEnables(userThinkingEnables);
2976 SetMachineThinkingEnables()
2978 if (appData.noChessProgram) return;
2979 SetMenuEnables(machineThinkingEnables);
2981 case MachinePlaysBlack:
2982 case MachinePlaysWhite:
2983 case TwoMachinesPlay:
2984 XtSetSensitive(XtNameToWidget(menuBarWidget,
2985 ModeToWidgetName(gameMode)), True);
2992 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2993 #define HISTORY_SIZE 64
2994 static char *history[HISTORY_SIZE];
2995 int histIn = 0, histP = 0;
2998 SaveInHistory(char *cmd)
3000 if (history[histIn] != NULL) {
3001 free(history[histIn]);
3002 history[histIn] = NULL;
3004 if (*cmd == NULLCHAR) return;
3005 history[histIn] = StrSave(cmd);
3006 histIn = (histIn + 1) % HISTORY_SIZE;
3007 if (history[histIn] != NULL) {
3008 free(history[histIn]);
3009 history[histIn] = NULL;
3015 PrevInHistory(char *cmd)
3018 if (histP == histIn) {
3019 if (history[histIn] != NULL) free(history[histIn]);
3020 history[histIn] = StrSave(cmd);
3022 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
3023 if (newhp == histIn || history[newhp] == NULL) return NULL;
3025 return history[histP];
3031 if (histP == histIn) return NULL;
3032 histP = (histP + 1) % HISTORY_SIZE;
3033 return history[histP];
3035 // end of borrowed code
3037 #define Abs(n) ((n)<0 ? -(n) : (n))
3040 * Find a font that matches "pattern" that is as close as
3041 * possible to the targetPxlSize. Prefer fonts that are k
3042 * pixels smaller to fonts that are k pixels larger. The
3043 * pattern must be in the X Consortium standard format,
3044 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3045 * The return value should be freed with XtFree when no
3049 FindFont(pattern, targetPxlSize)
3053 char **fonts, *p, *best, *scalable, *scalableTail;
3054 int i, j, nfonts, minerr, err, pxlSize;
3057 char **missing_list;
3059 char *def_string, *base_fnt_lst, strInt[3];
3061 XFontStruct **fnt_list;
3063 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3064 snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
3065 p = strstr(pattern, "--");
3066 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3067 strcat(base_fnt_lst, strInt);
3068 strcat(base_fnt_lst, strchr(p + 2, '-'));
3070 if ((fntSet = XCreateFontSet(xDisplay,
3074 &def_string)) == NULL) {
3076 fprintf(stderr, _("Unable to create font set.\n"));
3080 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3082 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3084 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3085 programName, pattern);
3093 for (i=0; i<nfonts; i++) {
3096 if (*p != '-') continue;
3098 if (*p == NULLCHAR) break;
3099 if (*p++ == '-') j++;
3101 if (j < 7) continue;
3104 scalable = fonts[i];
3107 err = pxlSize - targetPxlSize;
3108 if (Abs(err) < Abs(minerr) ||
3109 (minerr > 0 && err < 0 && -err == minerr)) {
3115 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3116 /* If the error is too big and there is a scalable font,
3117 use the scalable font. */
3118 int headlen = scalableTail - scalable;
3119 p = (char *) XtMalloc(strlen(scalable) + 10);
3120 while (isdigit(*scalableTail)) scalableTail++;
3121 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3123 p = (char *) XtMalloc(strlen(best) + 2);
3124 safeStrCpy(p, best, strlen(best)+1 );
3126 if (appData.debugMode) {
3127 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3128 pattern, targetPxlSize, p);
3131 if (missing_count > 0)
3132 XFreeStringList(missing_list);
3133 XFreeFontSet(xDisplay, fntSet);
3135 XFreeFontNames(fonts);
3141 { // [HGM] deletes GCs that are to be remade, to prevent resource leak;
3142 // must be called before all non-first callse to CreateGCs()
3143 XtReleaseGC(shellWidget, highlineGC);
3144 XtReleaseGC(shellWidget, lightSquareGC);
3145 XtReleaseGC(shellWidget, darkSquareGC);
3146 if (appData.monoMode) {
3147 if (DefaultDepth(xDisplay, xScreen) == 1) {
3148 XtReleaseGC(shellWidget, wbPieceGC);
3150 XtReleaseGC(shellWidget, bwPieceGC);
3153 XtReleaseGC(shellWidget, prelineGC);
3154 XtReleaseGC(shellWidget, jailSquareGC);
3155 XtReleaseGC(shellWidget, wdPieceGC);
3156 XtReleaseGC(shellWidget, wlPieceGC);
3157 XtReleaseGC(shellWidget, wjPieceGC);
3158 XtReleaseGC(shellWidget, bdPieceGC);
3159 XtReleaseGC(shellWidget, blPieceGC);
3160 XtReleaseGC(shellWidget, bjPieceGC);
3164 void CreateGCs(int redo)
3166 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3167 | GCBackground | GCFunction | GCPlaneMask;
3168 XGCValues gc_values;
3171 gc_values.plane_mask = AllPlanes;
3172 gc_values.line_width = lineGap;
3173 gc_values.line_style = LineSolid;
3174 gc_values.function = GXcopy;
3177 DeleteGCs(); // called a second time; clean up old GCs first
3178 } else { // [HGM] grid and font GCs created on first call only
3179 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3180 gc_values.background = XBlackPixel(xDisplay, xScreen);
3181 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3183 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3184 gc_values.background = XWhitePixel(xDisplay, xScreen);
3185 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3186 XSetFont(xDisplay, coordGC, coordFontID);
3188 // [HGM] make font for holdings counts (white on black)
3189 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3190 gc_values.background = XBlackPixel(xDisplay, xScreen);
3191 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3192 XSetFont(xDisplay, countGC, countFontID);
3194 if (appData.monoMode) {
3195 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3196 gc_values.background = XWhitePixel(xDisplay, xScreen);
3197 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3199 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3200 gc_values.background = XBlackPixel(xDisplay, xScreen);
3201 lightSquareGC = wbPieceGC
3202 = XtGetGC(shellWidget, value_mask, &gc_values);
3204 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3205 gc_values.background = XWhitePixel(xDisplay, xScreen);
3206 darkSquareGC = bwPieceGC
3207 = XtGetGC(shellWidget, value_mask, &gc_values);
3209 if (DefaultDepth(xDisplay, xScreen) == 1) {
3210 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3211 gc_values.function = GXcopyInverted;
3212 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3213 gc_values.function = GXcopy;
3214 if (XBlackPixel(xDisplay, xScreen) == 1) {
3215 bwPieceGC = darkSquareGC;
3216 wbPieceGC = copyInvertedGC;
3218 bwPieceGC = copyInvertedGC;
3219 wbPieceGC = lightSquareGC;
3223 gc_values.foreground = highlightSquareColor;
3224 gc_values.background = highlightSquareColor;
3225 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3227 gc_values.foreground = premoveHighlightColor;
3228 gc_values.background = premoveHighlightColor;
3229 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3231 gc_values.foreground = lightSquareColor;
3232 gc_values.background = darkSquareColor;
3233 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3235 gc_values.foreground = darkSquareColor;
3236 gc_values.background = lightSquareColor;
3237 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3239 gc_values.foreground = jailSquareColor;
3240 gc_values.background = jailSquareColor;
3241 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3243 gc_values.foreground = whitePieceColor;
3244 gc_values.background = darkSquareColor;
3245 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3247 gc_values.foreground = whitePieceColor;
3248 gc_values.background = lightSquareColor;
3249 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3251 gc_values.foreground = whitePieceColor;
3252 gc_values.background = jailSquareColor;
3253 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3255 gc_values.foreground = blackPieceColor;
3256 gc_values.background = darkSquareColor;
3257 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3259 gc_values.foreground = blackPieceColor;
3260 gc_values.background = lightSquareColor;
3261 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3263 gc_values.foreground = blackPieceColor;
3264 gc_values.background = jailSquareColor;
3265 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3269 void loadXIM(xim, xmask, filename, dest, mask)
3282 fp = fopen(filename, "rb");
3284 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3291 for (y=0; y<h; ++y) {
3292 for (x=0; x<h; ++x) {
3297 XPutPixel(xim, x, y, blackPieceColor);
3299 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3302 XPutPixel(xim, x, y, darkSquareColor);
3304 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3307 XPutPixel(xim, x, y, whitePieceColor);
3309 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3312 XPutPixel(xim, x, y, lightSquareColor);
3314 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3322 /* create Pixmap of piece */
3323 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3325 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3328 /* create Pixmap of clipmask
3329 Note: We assume the white/black pieces have the same
3330 outline, so we make only 6 masks. This is okay
3331 since the XPM clipmask routines do the same. */
3333 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3335 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3338 /* now create the 1-bit version */
3339 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3342 values.foreground = 1;
3343 values.background = 0;
3345 /* Don't use XtGetGC, not read only */
3346 maskGC = XCreateGC(xDisplay, *mask,
3347 GCForeground | GCBackground, &values);
3348 XCopyPlane(xDisplay, temp, *mask, maskGC,
3349 0, 0, squareSize, squareSize, 0, 0, 1);
3350 XFreePixmap(xDisplay, temp);
3355 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3357 void CreateXIMPieces()
3362 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3367 /* The XSynchronize calls were copied from CreatePieces.
3368 Not sure if needed, but can't hurt */
3369 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3372 /* temp needed by loadXIM() */
3373 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3374 0, 0, ss, ss, AllPlanes, XYPixmap);
3376 if (strlen(appData.pixmapDirectory) == 0) {
3380 if (appData.monoMode) {
3381 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3385 fprintf(stderr, _("\nLoading XIMs...\n"));
3387 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3388 fprintf(stderr, "%d", piece+1);
3389 for (kind=0; kind<4; kind++) {
3390 fprintf(stderr, ".");
3391 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3392 ExpandPathName(appData.pixmapDirectory),
3393 piece <= (int) WhiteKing ? "" : "w",
3394 pieceBitmapNames[piece],
3396 ximPieceBitmap[kind][piece] =
3397 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3398 0, 0, ss, ss, AllPlanes, XYPixmap);
3399 if (appData.debugMode)
3400 fprintf(stderr, _("(File:%s:) "), buf);
3401 loadXIM(ximPieceBitmap[kind][piece],
3403 &(xpmPieceBitmap2[kind][piece]),
3404 &(ximMaskPm2[piece]));
3405 if(piece <= (int)WhiteKing)
3406 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3408 fprintf(stderr," ");
3410 /* Load light and dark squares */
3411 /* If the LSQ and DSQ pieces don't exist, we will
3412 draw them with solid squares. */
3413 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3414 if (access(buf, 0) != 0) {
3418 fprintf(stderr, _("light square "));
3420 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3421 0, 0, ss, ss, AllPlanes, XYPixmap);
3422 if (appData.debugMode)
3423 fprintf(stderr, _("(File:%s:) "), buf);
3425 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3426 fprintf(stderr, _("dark square "));
3427 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3428 ExpandPathName(appData.pixmapDirectory), ss);
3429 if (appData.debugMode)
3430 fprintf(stderr, _("(File:%s:) "), buf);
3432 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3433 0, 0, ss, ss, AllPlanes, XYPixmap);
3434 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3435 xpmJailSquare = xpmLightSquare;
3437 fprintf(stderr, _("Done.\n"));
3439 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3443 void CreateXPMBoard(char *s, int kind)
3447 if(s == NULL || *s == 0 || *s == '*') { useTexture &= ~(kind+1); return; }
3448 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3449 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3453 void FreeXPMPieces()
3454 { // [HGM] to prevent resoucre leak on calling CreaeXPMPieces() a second time,
3455 // thisroutine has to be called t free the old piece pixmaps
3457 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++)
3458 for (kind=0; kind<4; kind++) XFreePixmap(xDisplay, xpmPieceBitmap2[kind][piece]);
3460 XFreePixmap(xDisplay, xpmLightSquare);
3461 XFreePixmap(xDisplay, xpmDarkSquare);
3465 void CreateXPMPieces()
3469 u_int ss = squareSize;
3471 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3472 XpmColorSymbol symbols[4];
3473 static int redo = False;
3475 if(redo) FreeXPMPieces(); else redo = 1;
3477 /* The XSynchronize calls were copied from CreatePieces.
3478 Not sure if needed, but can't hurt */
3479 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3481 /* Setup translations so piece colors match square colors */
3482 symbols[0].name = "light_piece";
3483 symbols[0].value = appData.whitePieceColor;
3484 symbols[1].name = "dark_piece";
3485 symbols[1].value = appData.blackPieceColor;
3486 symbols[2].name = "light_square";
3487 symbols[2].value = appData.lightSquareColor;
3488 symbols[3].name = "dark_square";
3489 symbols[3].value = appData.darkSquareColor;
3491 attr.valuemask = XpmColorSymbols;
3492 attr.colorsymbols = symbols;
3493 attr.numsymbols = 4;
3495 if (appData.monoMode) {
3496 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3500 if (strlen(appData.pixmapDirectory) == 0) {
3501 XpmPieces* pieces = builtInXpms;
3504 while (pieces->size != squareSize && pieces->size) pieces++;
3505 if (!pieces->size) {
3506 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3509 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3510 for (kind=0; kind<4; kind++) {
3512 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3513 pieces->xpm[piece][kind],
3514 &(xpmPieceBitmap2[kind][piece]),
3515 NULL, &attr)) != 0) {
3516 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3520 if(piece <= (int) WhiteKing)
3521 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3525 xpmJailSquare = xpmLightSquare;
3529 fprintf(stderr, _("\nLoading XPMs...\n"));
3532 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3533 fprintf(stderr, "%d ", piece+1);
3534 for (kind=0; kind<4; kind++) {
3535 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3536 ExpandPathName(appData.pixmapDirectory),
3537 piece > (int) WhiteKing ? "w" : "",
3538 pieceBitmapNames[piece],
3540 if (appData.debugMode) {
3541 fprintf(stderr, _("(File:%s:) "), buf);
3543 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3544 &(xpmPieceBitmap2[kind][piece]),
3545 NULL, &attr)) != 0) {
3546 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3547 // [HGM] missing: read of unorthodox piece failed; substitute King.
3548 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3549 ExpandPathName(appData.pixmapDirectory),
3551 if (appData.debugMode) {
3552 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3554 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3555 &(xpmPieceBitmap2[kind][piece]),
3559 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3564 if(piece <= (int) WhiteKing)
3565 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3568 /* Load light and dark squares */
3569 /* If the LSQ and DSQ pieces don't exist, we will
3570 draw them with solid squares. */
3571 fprintf(stderr, _("light square "));
3572 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3573 if (access(buf, 0) != 0) {
3577 if (appData.debugMode)
3578 fprintf(stderr, _("(File:%s:) "), buf);
3580 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3581 &xpmLightSquare, NULL, &attr)) != 0) {
3582 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3585 fprintf(stderr, _("dark square "));
3586 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3587 ExpandPathName(appData.pixmapDirectory), ss);
3588 if (appData.debugMode) {
3589 fprintf(stderr, _("(File:%s:) "), buf);
3591 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3592 &xpmDarkSquare, NULL, &attr)) != 0) {
3593 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3597 xpmJailSquare = xpmLightSquare;
3598 fprintf(stderr, _("Done.\n"));
3600 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3603 #endif /* HAVE_LIBXPM */
3606 /* No built-in bitmaps */
3611 u_int ss = squareSize;
3613 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3616 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3617 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3618 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3619 pieceBitmapNames[piece],
3620 ss, kind == SOLID ? 's' : 'o');
3621 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3622 if(piece <= (int)WhiteKing)
3623 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3627 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3631 /* With built-in bitmaps */
3634 BuiltInBits* bib = builtInBits;
3637 u_int ss = squareSize;
3639 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3642 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3644 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3645 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3646 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3647 pieceBitmapNames[piece],
3648 ss, kind == SOLID ? 's' : 'o');
3649 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3650 bib->bits[kind][piece], ss, ss);
3651 if(piece <= (int)WhiteKing)
3652 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3656 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3661 void ReadBitmap(pm, name, bits, wreq, hreq)
3664 unsigned char bits[];
3670 char msg[MSG_SIZ], fullname[MSG_SIZ];
3672 if (*appData.bitmapDirectory != NULLCHAR) {
3673 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3674 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3675 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3676 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3677 &w, &h, pm, &x_hot, &y_hot);
3678 fprintf(stderr, "load %s\n", name);
3679 if (errcode != BitmapSuccess) {
3681 case BitmapOpenFailed:
3682 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3684 case BitmapFileInvalid:
3685 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3687 case BitmapNoMemory:
3688 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3692 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3696 fprintf(stderr, _("%s: %s...using built-in\n"),
3698 } else if (w != wreq || h != hreq) {
3700 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3701 programName, fullname, w, h, wreq, hreq);
3707 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3716 if (lineGap == 0) return;
3718 /* [HR] Split this into 2 loops for non-square boards. */
3720 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3721 gridSegments[i].x1 = 0;
3722 gridSegments[i].x2 =
3723 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3724 gridSegments[i].y1 = gridSegments[i].y2
3725 = lineGap / 2 + (i * (squareSize + lineGap));
3728 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3729 gridSegments[j + i].y1 = 0;
3730 gridSegments[j + i].y2 =
3731 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3732 gridSegments[j + i].x1 = gridSegments[j + i].x2
3733 = lineGap / 2 + (j * (squareSize + lineGap));
3737 static void MenuBarSelect(w, addr, index)
3742 XtActionProc proc = (XtActionProc) addr;
3744 (proc)(NULL, NULL, NULL, NULL);
3747 void CreateMenuBarPopup(parent, name, mb)
3757 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3760 XtSetArg(args[j], XtNleftMargin, 20); j++;
3761 XtSetArg(args[j], XtNrightMargin, 20); j++;
3763 while (mi->string != NULL) {
3764 if (strcmp(mi->string, "----") == 0) {
3765 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3768 XtSetArg(args[j], XtNlabel, XtNewString(mi->string));
3769 entry = XtCreateManagedWidget(mi->ref, smeBSBObjectClass,
3771 XtAddCallback(entry, XtNcallback,
3772 (XtCallbackProc) MenuBarSelect,
3773 (caddr_t) mi->proc);
3779 Widget CreateMenuBar(mb)
3783 Widget anchor, menuBar;
3785 char menuName[MSG_SIZ];
3788 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3789 XtSetArg(args[j], XtNvSpace, 0); j++;
3790 XtSetArg(args[j], XtNborderWidth, 0); j++;
3791 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3792 formWidget, args, j);
3794 while (mb->name != NULL) {
3795 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3796 strncat(menuName, mb->ref, MSG_SIZ - strlen(menuName) - 1);
3798 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3801 shortName[0] = mb->name[0];
3802 shortName[1] = NULLCHAR;
3803 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3806 XtSetArg(args[j], XtNlabel, XtNewString(mb->name)); j++;
3809 XtSetArg(args[j], XtNborderWidth, 0); j++;
3810 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3812 CreateMenuBarPopup(menuBar, menuName, mb);
3818 Widget CreateButtonBar(mi)
3822 Widget button, buttonBar;
3826 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3828 XtSetArg(args[j], XtNhSpace, 0); j++;
3830 XtSetArg(args[j], XtNborderWidth, 0); j++;
3831 XtSetArg(args[j], XtNvSpace, 0); j++;
3832 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3833 formWidget, args, j);
3835 while (mi->string != NULL) {
3838 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3839 XtSetArg(args[j], XtNborderWidth, 0); j++;
3841 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3842 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3843 buttonBar, args, j);
3844 XtAddCallback(button, XtNcallback,
3845 (XtCallbackProc) MenuBarSelect,
3846 (caddr_t) mi->proc);
3853 CreatePieceMenu(name, color)
3860 ChessSquare selection;
3862 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3863 boardWidget, args, 0);
3865 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3866 String item = pieceMenuStrings[color][i];
3868 if (strcmp(item, "----") == 0) {
3869 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3872 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3873 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3875 selection = pieceMenuTranslation[color][i];
3876 XtAddCallback(entry, XtNcallback,
3877 (XtCallbackProc) PieceMenuSelect,
3878 (caddr_t) selection);
3879 if (selection == WhitePawn || selection == BlackPawn) {
3880 XtSetArg(args[0], XtNpopupOnEntry, entry);
3881 XtSetValues(menu, args, 1);
3894 ChessSquare selection;
3896 whitePieceMenu = CreatePieceMenu("menuW", 0);
3897 blackPieceMenu = CreatePieceMenu("menuB", 1);
3899 XtRegisterGrabAction(PieceMenuPopup, True,
3900 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3901 GrabModeAsync, GrabModeAsync);
3903 XtSetArg(args[0], XtNlabel, _("Drop"));
3904 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3905 boardWidget, args, 1);
3906 for (i = 0; i < DROP_MENU_SIZE; i++) {
3907 String item = dropMenuStrings[i];
3909 if (strcmp(item, "----") == 0) {
3910 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3913 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3914 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3916 selection = dropMenuTranslation[i];
3917 XtAddCallback(entry, XtNcallback,
3918 (XtCallbackProc) DropMenuSelect,
3919 (caddr_t) selection);
3924 void SetupDropMenu()
3932 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3933 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3934 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3935 dmEnables[i].piece);
3936 XtSetSensitive(entry, p != NULL || !appData.testLegality
3937 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3938 && !appData.icsActive));
3940 while (p && *p++ == dmEnables[i].piece) count++;
3941 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3943 XtSetArg(args[j], XtNlabel, label); j++;
3944 XtSetValues(entry, args, j);
3948 void PieceMenuPopup(w, event, params, num_params)
3952 Cardinal *num_params;
3954 String whichMenu; int menuNr;
3955 if (event->type == ButtonRelease)
3956 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3957 else if (event->type == ButtonPress)
3958 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3960 case 0: whichMenu = params[0]; break;
3961 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3963 case -1: if (errorUp) ErrorPopDown();
3966 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3969 static void PieceMenuSelect(w, piece, junk)
3974 if (pmFromX < 0 || pmFromY < 0) return;
3975 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3978 static void DropMenuSelect(w, piece, junk)
3983 if (pmFromX < 0 || pmFromY < 0) return;
3984 DropMenuEvent(piece, pmFromX, pmFromY);
3987 void WhiteClock(w, event, prms, nprms)
3996 void BlackClock(w, event, prms, nprms)
4007 * If the user selects on a border boundary, return -1; if off the board,
4008 * return -2. Otherwise map the event coordinate to the square.
4010 int EventToSquare(x, limit)
4018 if ((x % (squareSize + lineGap)) >= squareSize)
4020 x /= (squareSize + lineGap);
4026 static void do_flash_delay(msec)
4032 static void drawHighlight(file, rank, gc)
4038 if (lineGap == 0) return;
4041 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
4042 (squareSize + lineGap);
4043 y = lineGap/2 + rank * (squareSize + lineGap);
4045 x = lineGap/2 + file * (squareSize + lineGap);
4046 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
4047 (squareSize + lineGap);
4050 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
4051 squareSize+lineGap, squareSize+lineGap);
4054 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
4055 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4058 SetHighlights(fromX, fromY, toX, toY)
4059 int fromX, fromY, toX, toY;
4061 if (hi1X != fromX || hi1Y != fromY) {
4062 if (hi1X >= 0 && hi1Y >= 0) {
4063 drawHighlight(hi1X, hi1Y, lineGC);
4065 } // [HGM] first erase both, then draw new!
4066 if (hi2X != toX || hi2Y != toY) {
4067 if (hi2X >= 0 && hi2Y >= 0) {
4068 drawHighlight(hi2X, hi2Y, lineGC);
4071 if (hi1X != fromX || hi1Y != fromY) {
4072 if (fromX >= 0 && fromY >= 0) {
4073 drawHighlight(fromX, fromY, highlineGC);
4076 if (hi2X != toX || hi2Y != toY) {
4077 if (toX >= 0 && toY >= 0) {
4078 drawHighlight(toX, toY, highlineGC);
4090 SetHighlights(-1, -1, -1, -1);
4095 SetPremoveHighlights(fromX, fromY, toX, toY)
4096 int fromX, fromY, toX, toY;
4098 if (pm1X != fromX || pm1Y != fromY) {
4099 if (pm1X >= 0 && pm1Y >= 0) {
4100 drawHighlight(pm1X, pm1Y, lineGC);
4102 if (fromX >= 0 && fromY >= 0) {
4103 drawHighlight(fromX, fromY, prelineGC);
4106 if (pm2X != toX || pm2Y != toY) {
4107 if (pm2X >= 0 && pm2Y >= 0) {
4108 drawHighlight(pm2X, pm2Y, lineGC);
4110 if (toX >= 0 && toY >= 0) {
4111 drawHighlight(toX, toY, prelineGC);
4121 ClearPremoveHighlights()
4123 SetPremoveHighlights(-1, -1, -1, -1);
4126 static int CutOutSquare(x, y, x0, y0, kind)
4127 int x, y, *x0, *y0, kind;
4129 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
4130 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
4132 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
4133 if(textureW[kind] < W*squareSize)
4134 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
4136 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
4137 if(textureH[kind] < H*squareSize)
4138 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
4140 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
4144 static void BlankSquare(x, y, color, piece, dest, fac)
4145 int x, y, color, fac;
4148 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
4150 if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
4151 XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
4152 squareSize, squareSize, x*fac, y*fac);
4154 if (useImages && useImageSqs) {
4158 pm = xpmLightSquare;
4163 case 2: /* neutral */
4168 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4169 squareSize, squareSize, x*fac, y*fac);
4179 case 2: /* neutral */
4184 XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
4189 I split out the routines to draw a piece so that I could
4190 make a generic flash routine.
4192 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4194 int square_color, x, y;
4197 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4198 switch (square_color) {
4200 case 2: /* neutral */
4202 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4203 ? *pieceToOutline(piece)
4204 : *pieceToSolid(piece),
4205 dest, bwPieceGC, 0, 0,
4206 squareSize, squareSize, x, y);
4209 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4210 ? *pieceToSolid(piece)
4211 : *pieceToOutline(piece),
4212 dest, wbPieceGC, 0, 0,
4213 squareSize, squareSize, x, y);
4218 static void monoDrawPiece(piece, square_color, x, y, dest)
4220 int square_color, x, y;
4223 switch (square_color) {
4225 case 2: /* neutral */
4227 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4228 ? *pieceToOutline(piece)
4229 : *pieceToSolid(piece),
4230 dest, bwPieceGC, 0, 0,
4231 squareSize, squareSize, x, y, 1);
4234 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4235 ? *pieceToSolid(piece)
4236 : *pieceToOutline(piece),
4237 dest, wbPieceGC, 0, 0,
4238 squareSize, squareSize, x, y, 1);
4243 static void colorDrawPiece(piece, square_color, x, y, dest)
4245 int square_color, x, y;
4248 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4249 switch (square_color) {
4251 XCopyPlane(xDisplay, *pieceToSolid(piece),
4252 dest, (int) piece < (int) BlackPawn
4253 ? wlPieceGC : blPieceGC, 0, 0,
4254 squareSize, squareSize, x, y, 1);
4257 XCopyPlane(xDisplay, *pieceToSolid(piece),
4258 dest, (int) piece < (int) BlackPawn
4259 ? wdPieceGC : bdPieceGC, 0, 0,
4260 squareSize, squareSize, x, y, 1);
4262 case 2: /* neutral */
4264 XCopyPlane(xDisplay, *pieceToSolid(piece),
4265 dest, (int) piece < (int) BlackPawn
4266 ? wjPieceGC : bjPieceGC, 0, 0,
4267 squareSize, squareSize, x, y, 1);
4272 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4274 int square_color, x, y;
4277 int kind, p = piece;
4279 switch (square_color) {
4281 case 2: /* neutral */
4283 if ((int)piece < (int) BlackPawn) {
4291 if ((int)piece < (int) BlackPawn) {
4299 if(appData.upsideDown && flipView) { kind ^= 2; p += p < BlackPawn ? BlackPawn : -BlackPawn; }// swap white and black pieces
4300 if(useTexture & square_color+1) {
4301 BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
4302 XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
4303 XSetClipOrigin(xDisplay, wlPieceGC, x, y);
4304 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);
4305 XSetClipMask(xDisplay, wlPieceGC, None);
4306 XSetClipOrigin(xDisplay, wlPieceGC, 0, 0);
4308 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4309 dest, wlPieceGC, 0, 0,
4310 squareSize, squareSize, x, y);
4313 typedef void (*DrawFunc)();
4315 DrawFunc ChooseDrawFunc()
4317 if (appData.monoMode) {
4318 if (DefaultDepth(xDisplay, xScreen) == 1) {
4319 return monoDrawPiece_1bit;
4321 return monoDrawPiece;
4325 return colorDrawPieceImage;
4327 return colorDrawPiece;
4331 /* [HR] determine square color depending on chess variant. */
4332 static int SquareColor(row, column)
4337 if (gameInfo.variant == VariantXiangqi) {
4338 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4340 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4342 } else if (row <= 4) {
4348 square_color = ((column + row) % 2) == 1;
4351 /* [hgm] holdings: next line makes all holdings squares light */
4352 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4354 return square_color;
4357 void DrawSquare(row, column, piece, do_flash)
4358 int row, column, do_flash;
4361 int square_color, x, y, direction, font_ascent, font_descent;
4364 XCharStruct overall;
4368 /* Calculate delay in milliseconds (2-delays per complete flash) */
4369 flash_delay = 500 / appData.flashRate;
4372 x = lineGap + ((BOARD_WIDTH-1)-column) *
4373 (squareSize + lineGap);
4374 y = lineGap + row * (squareSize + lineGap);
4376 x = lineGap + column * (squareSize + lineGap);
4377 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4378 (squareSize + lineGap);
4381 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4383 square_color = SquareColor(row, column);
4385 if ( // [HGM] holdings: blank out area between board and holdings
4386 column == BOARD_LEFT-1 || column == BOARD_RGHT
4387 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4388 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4389 BlankSquare(x, y, 2, EmptySquare, xBoardWindow, 1);
4391 // [HGM] print piece counts next to holdings
4392 string[1] = NULLCHAR;
4393 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4394 string[0] = '0' + piece;
4395 XTextExtents(countFontStruct, string, 1, &direction,
4396 &font_ascent, &font_descent, &overall);
4397 if (appData.monoMode) {
4398 XDrawImageString(xDisplay, xBoardWindow, countGC,
4399 x + squareSize - overall.width - 2,
4400 y + font_ascent + 1, string, 1);
4402 XDrawString(xDisplay, xBoardWindow, countGC,
4403 x + squareSize - overall.width - 2,
4404 y + font_ascent + 1, string, 1);
4407 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4408 string[0] = '0' + piece;
4409 XTextExtents(countFontStruct, string, 1, &direction,
4410 &font_ascent, &font_descent, &overall);
4411 if (appData.monoMode) {
4412 XDrawImageString(xDisplay, xBoardWindow, countGC,
4413 x + 2, y + font_ascent + 1, string, 1);
4415 XDrawString(xDisplay, xBoardWindow, countGC,
4416 x + 2, y + font_ascent + 1, string, 1);
4420 if (piece == EmptySquare || appData.blindfold) {
4421 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4423 drawfunc = ChooseDrawFunc();
4425 if (do_flash && appData.flashCount > 0) {
4426 for (i=0; i<appData.flashCount; ++i) {
4427 drawfunc(piece, square_color, x, y, xBoardWindow);
4428 XSync(xDisplay, False);
4429 do_flash_delay(flash_delay);
4431 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4432 XSync(xDisplay, False);
4433 do_flash_delay(flash_delay);
4436 drawfunc(piece, square_color, x, y, xBoardWindow);
4440 string[1] = NULLCHAR;
4441 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4442 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4443 string[0] = 'a' + column - BOARD_LEFT;
4444 XTextExtents(coordFontStruct, string, 1, &direction,
4445 &font_ascent, &font_descent, &overall);
4446 if (appData.monoMode) {
4447 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4448 x + squareSize - overall.width - 2,
4449 y + squareSize - font_descent - 1, string, 1);
4451 XDrawString(xDisplay, xBoardWindow, coordGC,
4452 x + squareSize - overall.width - 2,
4453 y + squareSize - font_descent - 1, string, 1);
4456 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4457 string[0] = ONE + row;
4458 XTextExtents(coordFontStruct, string, 1, &direction,
4459 &font_ascent, &font_descent, &overall);
4460 if (appData.monoMode) {
4461 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4462 x + 2, y + font_ascent + 1, string, 1);
4464 XDrawString(xDisplay, xBoardWindow, coordGC,
4465 x + 2, y + font_ascent + 1, string, 1);
4468 if(!partnerUp && marker[row][column]) {
4469 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4470 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4475 /* Why is this needed on some versions of X? */
4476 void EventProc(widget, unused, event)
4481 if (!XtIsRealized(widget))
4484 switch (event->type) {
4486 if (event->xexpose.count > 0) return; /* no clipping is done */
4487 XDrawPosition(widget, True, NULL);
4488 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4489 flipView = !flipView; partnerUp = !partnerUp;
4490 XDrawPosition(widget, True, NULL);
4491 flipView = !flipView; partnerUp = !partnerUp;
4495 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
4502 void DrawPosition(fullRedraw, board)
4503 /*Boolean*/int fullRedraw;
4506 XDrawPosition(boardWidget, fullRedraw, board);
4509 /* Returns 1 if there are "too many" differences between b1 and b2
4510 (i.e. more than 1 move was made) */
4511 static int too_many_diffs(b1, b2)
4517 for (i=0; i<BOARD_HEIGHT; ++i) {
4518 for (j=0; j<BOARD_WIDTH; ++j) {
4519 if (b1[i][j] != b2[i][j]) {
4520 if (++c > 4) /* Castling causes 4 diffs */
4528 /* Matrix describing castling maneuvers */
4529 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4530 static int castling_matrix[4][5] = {
4531 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4532 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4533 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4534 { 7, 7, 4, 5, 6 } /* 0-0, black */
4537 /* Checks whether castling occurred. If it did, *rrow and *rcol
4538 are set to the destination (row,col) of the rook that moved.
4540 Returns 1 if castling occurred, 0 if not.
4542 Note: Only handles a max of 1 castling move, so be sure
4543 to call too_many_diffs() first.
4545 static int check_castle_draw(newb, oldb, rrow, rcol)
4552 /* For each type of castling... */
4553 for (i=0; i<4; ++i) {
4554 r = castling_matrix[i];
4556 /* Check the 4 squares involved in the castling move */
4558 for (j=1; j<=4; ++j) {
4559 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4566 /* All 4 changed, so it must be a castling move */
4575 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4576 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4578 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4581 void DrawSeekBackground( int left, int top, int right, int bottom )
4583 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4586 void DrawSeekText(char *buf, int x, int y)
4588 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4591 void DrawSeekDot(int x, int y, int colorNr)
4593 int square = colorNr & 0x80;
4596 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4598 XFillRectangle(xDisplay, xBoardWindow, color,
4599 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4601 XFillArc(xDisplay, xBoardWindow, color,
4602 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4605 static int damage[2][BOARD_RANKS][BOARD_FILES];
4608 * event handler for redrawing the board
4610 void XDrawPosition(w, repaint, board)
4612 /*Boolean*/int repaint;
4616 static int lastFlipView = 0;
4617 static int lastBoardValid[2] = {0, 0};
4618 static Board lastBoard[2];
4621 int nr = twoBoards*partnerUp;
4623 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4625 if (board == NULL) {
4626 if (!lastBoardValid[nr]) return;
4627 board = lastBoard[nr];
4629 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4630 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4631 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Flip View"),
4636 * It would be simpler to clear the window with XClearWindow()
4637 * but this causes a very distracting flicker.
4640 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4642 if ( lineGap && IsDrawArrowEnabled())
4643 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4644 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4646 /* If too much changes (begin observing new game, etc.), don't
4648 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4650 /* Special check for castling so we don't flash both the king
4651 and the rook (just flash the king). */
4653 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4654 /* Draw rook with NO flashing. King will be drawn flashing later */
4655 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4656 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4660 /* First pass -- Draw (newly) empty squares and repair damage.
4661 This prevents you from having a piece show up twice while it
4662 is flashing on its new square */
4663 for (i = 0; i < BOARD_HEIGHT; i++)
4664 for (j = 0; j < BOARD_WIDTH; j++)
4665 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4666 || damage[nr][i][j]) {
4667 DrawSquare(i, j, board[i][j], 0);
4668 damage[nr][i][j] = False;
4671 /* Second pass -- Draw piece(s) in new position and flash them */
4672 for (i = 0; i < BOARD_HEIGHT; i++)
4673 for (j = 0; j < BOARD_WIDTH; j++)
4674 if (board[i][j] != lastBoard[nr][i][j]) {
4675 DrawSquare(i, j, board[i][j], do_flash);
4679 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4680 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4681 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4683 for (i = 0; i < BOARD_HEIGHT; i++)
4684 for (j = 0; j < BOARD_WIDTH; j++) {
4685 DrawSquare(i, j, board[i][j], 0);
4686 damage[nr][i][j] = False;
4690 CopyBoard(lastBoard[nr], board);
4691 lastBoardValid[nr] = 1;
4692 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4693 lastFlipView = flipView;
4695 /* Draw highlights */
4696 if (pm1X >= 0 && pm1Y >= 0) {
4697 drawHighlight(pm1X, pm1Y, prelineGC);
4699 if (pm2X >= 0 && pm2Y >= 0) {
4700 drawHighlight(pm2X, pm2Y, prelineGC);
4702 if (hi1X >= 0 && hi1Y >= 0) {
4703 drawHighlight(hi1X, hi1Y, highlineGC);
4705 if (hi2X >= 0 && hi2Y >= 0) {
4706 drawHighlight(hi2X, hi2Y, highlineGC);
4708 DrawArrowHighlight(hi1X, hi1Y, hi2X, hi2Y);
4710 /* If piece being dragged around board, must redraw that too */
4713 XSync(xDisplay, False);
4718 * event handler for redrawing the board
4720 void DrawPositionProc(w, event, prms, nprms)
4726 XDrawPosition(w, True, NULL);
4731 * event handler for parsing user moves
4733 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4734 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4735 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4736 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4737 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4738 // and at the end FinishMove() to perform the move after optional promotion popups.
4739 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4740 void HandleUserMove(w, event, prms, nprms)
4746 if (w != boardWidget || errorExitStatus != -1) return;
4747 if(nprms) shiftKey = !strcmp(prms[0], "1");
4750 if (event->type == ButtonPress) {
4751 XtPopdown(promotionShell);
4752 XtDestroyWidget(promotionShell);
4753 promotionUp = False;
4761 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4762 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4763 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4766 void AnimateUserMove (Widget w, XEvent * event,
4767 String * params, Cardinal * nParams)
4769 DragPieceMove(event->xmotion.x, event->xmotion.y);
4772 void HandlePV (Widget w, XEvent * event,
4773 String * params, Cardinal * nParams)
4774 { // [HGM] pv: walk PV
4775 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4778 Widget CommentCreate(name, text, mutable, callback, lines)
4780 int /*Boolean*/ mutable;
4781 XtCallbackProc callback;
4785 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4790 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4791 XtGetValues(boardWidget, args, j);
4794 XtSetArg(args[j], XtNresizable, True); j++;
4797 XtCreatePopupShell(name, topLevelShellWidgetClass,
4798 shellWidget, args, j);
4801 XtCreatePopupShell(name, transientShellWidgetClass,
4802 shellWidget, args, j);
4805 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4806 layoutArgs, XtNumber(layoutArgs));
4808 XtCreateManagedWidget("form", formWidgetClass, layout,
4809 formArgs, XtNumber(formArgs));
4813 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4814 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4816 XtSetArg(args[j], XtNstring, text); j++;
4817 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4818 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4819 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4820 XtSetArg(args[j], XtNright, XtChainRight); j++;
4821 XtSetArg(args[j], XtNresizable, True); j++;
4822 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4823 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4824 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4825 XtSetArg(args[j], XtNautoFill, True); j++;
4826 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4828 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4829 XtOverrideTranslations(edit, XtParseTranslationTable(commentTranslations));
4833 XtSetArg(args[j], XtNfromVert, edit); j++;
4834 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4835 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4836 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4837 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4839 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4840 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4843 XtSetArg(args[j], XtNfromVert, edit); j++;
4844 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4845 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4846 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4847 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4848 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4850 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4851 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4854 XtSetArg(args[j], XtNfromVert, edit); j++;
4855 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4856 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4857 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4858 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4859 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4861 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4862 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4865 XtSetArg(args[j], XtNfromVert, edit); j++;
4866 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4867 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4868 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4869 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4871 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4872 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4875 XtSetArg(args[j], XtNfromVert, edit); j++;
4876 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4877 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4878 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4879 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4880 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4882 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4883 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4886 XtRealizeWidget(shell);
4888 if (commentX == -1) {
4891 Dimension pw_height;
4892 Dimension ew_height;
4895 XtSetArg(args[j], XtNheight, &ew_height); j++;
4896 XtGetValues(edit, args, j);
4899 XtSetArg(args[j], XtNheight, &pw_height); j++;
4900 XtGetValues(shell, args, j);
4901 commentH = pw_height + (lines - 1) * ew_height;
4902 commentW = bw_width - 16;
4904 XSync(xDisplay, False);
4906 /* This code seems to tickle an X bug if it is executed too soon
4907 after xboard starts up. The coordinates get transformed as if
4908 the main window was positioned at (0, 0).
4910 XtTranslateCoords(shellWidget,
4911 (bw_width - commentW) / 2, 0 - commentH / 2,
4912 &commentX, &commentY);
4914 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4915 RootWindowOfScreen(XtScreen(shellWidget)),
4916 (bw_width - commentW) / 2, 0 - commentH / 2,
4921 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4924 if(wpComment.width > 0) {
4925 commentX = wpComment.x;
4926 commentY = wpComment.y;
4927 commentW = wpComment.width;
4928 commentH = wpComment.height;
4932 XtSetArg(args[j], XtNheight, commentH); j++;
4933 XtSetArg(args[j], XtNwidth, commentW); j++;
4934 XtSetArg(args[j], XtNx, commentX); j++;
4935 XtSetArg(args[j], XtNy, commentY); j++;
4936 XtSetValues(shell, args, j);
4937 XtSetKeyboardFocus(shell, edit);
4942 static int savedIndex; /* gross that this is global */
4944 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
4947 XawTextPosition index, dummy;
4950 XawTextGetSelectionPos(w, &index, &dummy);
4951 XtSetArg(arg, XtNstring, &val);
4952 XtGetValues(w, &arg, 1);
4953 ReplaceComment(savedIndex, val);
4954 if(savedIndex != currentMove) ToNrEvent(savedIndex);
4955 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
4958 void EditCommentPopUp(index, title, text)
4967 if (text == NULL) text = "";
4969 if (editShell == NULL) {
4971 CommentCreate(title, text, True, EditCommentCallback, 4);
4972 XtRealizeWidget(editShell);
4973 CatchDeleteWindow(editShell, "EditCommentPopDown");
4975 edit = XtNameToWidget(editShell, "*form.text");
4977 XtSetArg(args[j], XtNstring, text); j++;
4978 XtSetValues(edit, args, j);
4980 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4981 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4982 XtSetValues(editShell, args, j);
4985 XtPopup(editShell, XtGrabNone);
4989 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4990 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"),
4992 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"),
4996 void EditCommentCallback(w, client_data, call_data)
4998 XtPointer client_data, call_data;
5006 XtSetArg(args[j], XtNlabel, &name); j++;
5007 XtGetValues(w, args, j);
5009 if (strcmp(name, _("ok")) == 0) {
5010 edit = XtNameToWidget(editShell, "*form.text");
5012 XtSetArg(args[j], XtNstring, &val); j++;
5013 XtGetValues(edit, args, j);
5014 ReplaceComment(savedIndex, val);
5015 EditCommentPopDown();
5016 } else if (strcmp(name, _("cancel")) == 0) {
5017 EditCommentPopDown();
5018 } else if (strcmp(name, _("clear")) == 0) {
5019 edit = XtNameToWidget(editShell, "*form.text");
5020 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5021 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5025 void EditCommentPopDown()
5030 if (!editUp) return;
5032 XtSetArg(args[j], XtNx, &commentX); j++;
5033 XtSetArg(args[j], XtNy, &commentY); j++;
5034 XtSetArg(args[j], XtNheight, &commentH); j++;
5035 XtSetArg(args[j], XtNwidth, &commentW); j++;
5036 XtGetValues(editShell, args, j);
5037 XtPopdown(editShell);
5040 XtSetArg(args[j], XtNleftBitmap, None); j++;
5041 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"),
5043 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"),
5047 void ICSInputBoxPopUp()
5052 extern Option boxOptions[];
5054 void ICSInputSendText()
5061 edit = boxOptions[0].handle;
5063 XtSetArg(args[j], XtNstring, &val); j++;
5064 XtGetValues(edit, args, j);
5066 SendMultiLineToICS(val);
5067 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5068 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5071 void ICSInputBoxPopDown()
5076 void CommentPopUp(title, text)
5083 savedIndex = currentMove; // [HGM] vari
5084 if (commentShell == NULL) {
5086 CommentCreate(title, text, False, CommentCallback, 4);
5087 XtRealizeWidget(commentShell);
5088 CatchDeleteWindow(commentShell, "CommentPopDown");
5090 edit = XtNameToWidget(commentShell, "*form.text");
5092 XtSetArg(args[j], XtNstring, text); j++;
5093 XtSetValues(edit, args, j);
5095 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5096 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5097 XtSetValues(commentShell, args, j);
5100 XtPopup(commentShell, XtGrabNone);
5101 XSync(xDisplay, False);
5106 void CommentCallback(w, client_data, call_data)
5108 XtPointer client_data, call_data;
5115 XtSetArg(args[j], XtNlabel, &name); j++;
5116 XtGetValues(w, args, j);
5118 if (strcmp(name, _("close")) == 0) {
5120 } else if (strcmp(name, _("edit")) == 0) {
5127 void CommentPopDown()
5132 if (!commentUp) return;
5134 XtSetArg(args[j], XtNx, &commentX); j++;
5135 XtSetArg(args[j], XtNy, &commentY); j++;
5136 XtSetArg(args[j], XtNwidth, &commentW); j++;
5137 XtSetArg(args[j], XtNheight, &commentH); j++;
5138 XtGetValues(commentShell, args, j);
5139 XtPopdown(commentShell);
5140 XSync(xDisplay, False);
5144 void FileNamePopUp(label, def, proc, openMode)
5150 fileProc = proc; /* I can't see a way not */
5151 fileOpenMode = openMode; /* to use globals here */
5152 { // [HGM] use file-selector dialog stolen from Ghostview
5154 int index; // this is not supported yet
5156 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5157 def, openMode, NULL, &name))
5158 (void) (*fileProc)(f, index=0, name);
5162 void FileNamePopDown()
5164 if (!filenameUp) return;
5165 XtPopdown(fileNameShell);
5166 XtDestroyWidget(fileNameShell);
5171 void FileNameCallback(w, client_data, call_data)
5173 XtPointer client_data, call_data;
5178 XtSetArg(args[0], XtNlabel, &name);
5179 XtGetValues(w, args, 1);
5181 if (strcmp(name, _("cancel")) == 0) {
5186 FileNameAction(w, NULL, NULL, NULL);
5189 void FileNameAction(w, event, prms, nprms)
5201 name = XawDialogGetValueString(w = XtParent(w));
5203 if ((name != NULL) && (*name != NULLCHAR)) {
5204 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
5205 XtPopdown(w = XtParent(XtParent(w)));
5209 p = strrchr(buf, ' ');
5216 fullname = ExpandPathName(buf);
5218 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5221 f = fopen(fullname, fileOpenMode);
5223 DisplayError(_("Failed to open file"), errno);
5225 (void) (*fileProc)(f, index, buf);
5232 XtPopdown(w = XtParent(XtParent(w)));
5238 void PromotionPopUp()
5241 Widget dialog, layout;
5243 Dimension bw_width, pw_width;
5247 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5248 XtGetValues(boardWidget, args, j);
5251 XtSetArg(args[j], XtNresizable, True); j++;
5252 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5254 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5255 shellWidget, args, j);
5257 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5258 layoutArgs, XtNumber(layoutArgs));
5261 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5262 XtSetArg(args[j], XtNborderWidth, 0); j++;
5263 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5266 if(gameInfo.variant != VariantShogi) {
5267 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) {
5268 XawDialogAddButton(dialog, _("Warlord"), PromotionCallback,
5269 (XtPointer) dialog);
5270 XawDialogAddButton(dialog, _("General"), PromotionCallback,
5271 (XtPointer) dialog);
5272 XawDialogAddButton(dialog, _("Lieutenant"), PromotionCallback,
5273 (XtPointer) dialog);
5274 XawDialogAddButton(dialog, _("Captain"), PromotionCallback,
5275 (XtPointer) dialog);
5277 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5278 (XtPointer) dialog);
5279 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5280 (XtPointer) dialog);
5281 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5282 (XtPointer) dialog);
5283 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5284 (XtPointer) dialog);
5286 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5287 gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
\r
5288 gameInfo.variant == VariantGiveaway) {
5289 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5290 (XtPointer) dialog);
5292 if(gameInfo.variant == VariantCapablanca ||
5293 gameInfo.variant == VariantGothic ||
5294 gameInfo.variant == VariantCapaRandom) {
5295 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5296 (XtPointer) dialog);
5297 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5298 (XtPointer) dialog);
5300 } else // [HGM] shogi
5302 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5303 (XtPointer) dialog);
5304 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5305 (XtPointer) dialog);
5307 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5308 (XtPointer) dialog);
5310 XtRealizeWidget(promotionShell);
5311 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5314 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5315 XtGetValues(promotionShell, args, j);
5317 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5318 lineGap + squareSize/3 +
5319 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5320 0 : 6*(squareSize + lineGap)), &x, &y);
5323 XtSetArg(args[j], XtNx, x); j++;
5324 XtSetArg(args[j], XtNy, y); j++;
5325 XtSetValues(promotionShell, args, j);
5327 XtPopup(promotionShell, XtGrabNone);
5332 void PromotionPopDown()
5334 if (!promotionUp) return;
5335 XtPopdown(promotionShell);
5336 XtDestroyWidget(promotionShell);
5337 promotionUp = False;
5340 void PromotionCallback(w, client_data, call_data)
5342 XtPointer client_data, call_data;
5348 XtSetArg(args[0], XtNlabel, &name);
5349 XtGetValues(w, args, 1);
5353 if (fromX == -1) return;
5355 if (strcmp(name, _("cancel")) == 0) {
5359 } else if (strcmp(name, _("Knight")) == 0) {
5361 } else if (strcmp(name, _("Promote")) == 0) {
5363 } else if (strcmp(name, _("Defer")) == 0) {
5366 promoChar = ToLower(name[0]);
5369 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5371 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5372 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5377 void ErrorCallback(w, client_data, call_data)
5379 XtPointer client_data, call_data;
5382 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5384 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5390 if (!errorUp) return;
5392 XtPopdown(errorShell);
5393 XtDestroyWidget(errorShell);
5394 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5397 void ErrorPopUp(title, label, modal)
5398 char *title, *label;
5402 Widget dialog, layout;
5406 Dimension bw_width, pw_width;
5407 Dimension pw_height;
5411 XtSetArg(args[i], XtNresizable, True); i++;
5412 XtSetArg(args[i], XtNtitle, title); i++;
5414 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5415 shellWidget, args, i);
5417 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5418 layoutArgs, XtNumber(layoutArgs));
5421 XtSetArg(args[i], XtNlabel, label); i++;
5422 XtSetArg(args[i], XtNborderWidth, 0); i++;
5423 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5426 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5428 XtRealizeWidget(errorShell);
5429 CatchDeleteWindow(errorShell, "ErrorPopDown");
5432 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5433 XtGetValues(boardWidget, args, i);
5435 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5436 XtSetArg(args[i], XtNheight, &pw_height); i++;
5437 XtGetValues(errorShell, args, i);
5440 /* This code seems to tickle an X bug if it is executed too soon
5441 after xboard starts up. The coordinates get transformed as if
5442 the main window was positioned at (0, 0).
5444 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5445 0 - pw_height + squareSize / 3, &x, &y);
5447 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5448 RootWindowOfScreen(XtScreen(boardWidget)),
5449 (bw_width - pw_width) / 2,
5450 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5454 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5457 XtSetArg(args[i], XtNx, x); i++;
5458 XtSetArg(args[i], XtNy, y); i++;
5459 XtSetValues(errorShell, args, i);
5462 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5465 /* Disable all user input other than deleting the window */
5466 static int frozen = 0;
5470 /* Grab by a widget that doesn't accept input */
5471 XtAddGrab(messageWidget, TRUE, FALSE);
5475 /* Undo a FreezeUI */
5478 if (!frozen) return;
5479 XtRemoveGrab(messageWidget);
5483 char *ModeToWidgetName(mode)
5487 case BeginningOfGame:
5488 if (appData.icsActive)
5489 return "menuMode.ICS Client";
5490 else if (appData.noChessProgram ||
5491 *appData.cmailGameName != NULLCHAR)
5492 return "menuMode.Edit Game";
5494 return "menuMode.Machine Black";
5495 case MachinePlaysBlack:
5496 return "menuMode.Machine Black";
5497 case MachinePlaysWhite:
5498 return "menuMode.Machine White";
5500 return "menuMode.Analysis Mode";
5502 return "menuMode.Analyze File";
5503 case TwoMachinesPlay:
5504 return "menuMode.Two Machines";
5506 return "menuMode.Edit Game";
5507 case PlayFromGameFile:
5508 return "menuFile.Load Game";
5510 return "menuMode.Edit Position";
5512 return "menuMode.Training";
5513 case IcsPlayingWhite:
5514 case IcsPlayingBlack:
5518 return "menuMode.ICS Client";
5525 void ModeHighlight()
5528 static int oldPausing = FALSE;
5529 static GameMode oldmode = (GameMode) -1;
5532 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5534 if (pausing != oldPausing) {
5535 oldPausing = pausing;
5537 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5539 XtSetArg(args[0], XtNleftBitmap, None);
5541 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5544 if (appData.showButtonBar) {
5545 /* Always toggle, don't set. Previous code messes up when
5546 invoked while the button is pressed, as releasing it
5547 toggles the state again. */
5550 XtSetArg(args[0], XtNbackground, &oldbg);
5551 XtSetArg(args[1], XtNforeground, &oldfg);
5552 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5554 XtSetArg(args[0], XtNbackground, oldfg);
5555 XtSetArg(args[1], XtNforeground, oldbg);
5557 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5561 wname = ModeToWidgetName(oldmode);
5562 if (wname != NULL) {
5563 XtSetArg(args[0], XtNleftBitmap, None);
5564 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5566 wname = ModeToWidgetName(gameMode);
5567 if (wname != NULL) {
5568 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5569 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5573 /* Maybe all the enables should be handled here, not just this one */
5574 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5575 gameMode == Training || gameMode == PlayFromGameFile);
5580 * Button/menu procedures
5582 void ResetProc(w, event, prms, nprms)
5591 int LoadGamePopUp(f, gameNumber, title)
5596 cmailMsgLoaded = FALSE;
5597 if (gameNumber == 0) {
5598 int error = GameListBuild(f);
5600 DisplayError(_("Cannot build game list"), error);
5601 } else if (!ListEmpty(&gameList) &&
5602 ((ListGame *) gameList.tailPred)->number > 1) {
5603 GameListPopUp(f, title);
5609 return LoadGame(f, gameNumber, title, FALSE);
5612 void LoadGameProc(w, event, prms, nprms)
5618 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5621 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5624 void LoadNextGameProc(w, event, prms, nprms)
5633 void LoadPrevGameProc(w, event, prms, nprms)
5642 void ReloadGameProc(w, event, prms, nprms)
5651 void LoadNextPositionProc(w, event, prms, nprms)
5660 void LoadPrevPositionProc(w, event, prms, nprms)
5669 void ReloadPositionProc(w, event, prms, nprms)
5678 void LoadPositionProc(w, event, prms, nprms)
5684 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5687 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5690 void SaveGameProc(w, event, prms, nprms)
5696 FileNamePopUp(_("Save game file name?"),
5697 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5701 void SavePositionProc(w, event, prms, nprms)
5707 FileNamePopUp(_("Save position file name?"),
5708 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5712 void ReloadCmailMsgProc(w, event, prms, nprms)
5718 ReloadCmailMsgEvent(FALSE);
5721 void MailMoveProc(w, event, prms, nprms)
5730 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5731 char *selected_fen_position=NULL;
5734 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5735 Atom *type_return, XtPointer *value_return,
5736 unsigned long *length_return, int *format_return)
5738 char *selection_tmp;
5740 if (!selected_fen_position) return False; /* should never happen */
5741 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5742 /* note: since no XtSelectionDoneProc was registered, Xt will
5743 * automatically call XtFree on the value returned. So have to
5744 * make a copy of it allocated with XtMalloc */
5745 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5746 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
5748 *value_return=selection_tmp;
5749 *length_return=strlen(selection_tmp);
5750 *type_return=*target;
5751 *format_return = 8; /* bits per byte */
5753 } else if (*target == XA_TARGETS(xDisplay)) {
5754 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5755 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5756 targets_tmp[1] = XA_STRING;
5757 *value_return = targets_tmp;
5758 *type_return = XA_ATOM;
5760 *format_return = 8 * sizeof(Atom);
5761 if (*format_return > 32) {
5762 *length_return *= *format_return / 32;
5763 *format_return = 32;
5771 /* note: when called from menu all parameters are NULL, so no clue what the
5772 * Widget which was clicked on was, or what the click event was
5774 void CopyPositionProc(w, event, prms, nprms)
5781 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5782 * have a notion of a position that is selected but not copied.
5783 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5785 if(gameMode == EditPosition) EditPositionDone(TRUE);
5786 if (selected_fen_position) free(selected_fen_position);
5787 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5788 if (!selected_fen_position) return;
5789 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5791 SendPositionSelection,
5792 NULL/* lose_ownership_proc */ ,
5793 NULL/* transfer_done_proc */);
5794 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5796 SendPositionSelection,
5797 NULL/* lose_ownership_proc */ ,
5798 NULL/* transfer_done_proc */);
5801 /* function called when the data to Paste is ready */
5803 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5804 Atom *type, XtPointer value, unsigned long *len, int *format)
5807 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5808 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5809 EditPositionPasteFEN(fenstr);
5813 /* called when Paste Position button is pressed,
5814 * all parameters will be NULL */
5815 void PastePositionProc(w, event, prms, nprms)
5821 XtGetSelectionValue(menuBarWidget,
5822 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5823 /* (XtSelectionCallbackProc) */ PastePositionCB,
5824 NULL, /* client_data passed to PastePositionCB */
5826 /* better to use the time field from the event that triggered the
5827 * call to this function, but that isn't trivial to get
5835 SendGameSelection(Widget w, Atom *selection, Atom *target,
5836 Atom *type_return, XtPointer *value_return,
5837 unsigned long *length_return, int *format_return)
5839 char *selection_tmp;
5841 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5842 FILE* f = fopen(gameCopyFilename, "r");
5845 if (f == NULL) return False;
5849 selection_tmp = XtMalloc(len + 1);
5850 count = fread(selection_tmp, 1, len, f);
5853 XtFree(selection_tmp);
5856 selection_tmp[len] = NULLCHAR;
5857 *value_return = selection_tmp;
5858 *length_return = len;
5859 *type_return = *target;
5860 *format_return = 8; /* bits per byte */
5862 } else if (*target == XA_TARGETS(xDisplay)) {
5863 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5864 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5865 targets_tmp[1] = XA_STRING;
5866 *value_return = targets_tmp;
5867 *type_return = XA_ATOM;
5869 *format_return = 8 * sizeof(Atom);
5870 if (*format_return > 32) {
5871 *length_return *= *format_return / 32;
5872 *format_return = 32;
5880 /* note: when called from menu all parameters are NULL, so no clue what the
5881 * Widget which was clicked on was, or what the click event was
5883 void CopyGameProc(w, event, prms, nprms)
5891 ret = SaveGameToFile(gameCopyFilename, FALSE);
5895 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5896 * have a notion of a game that is selected but not copied.
5897 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5899 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5902 NULL/* lose_ownership_proc */ ,
5903 NULL/* transfer_done_proc */);
5904 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5907 NULL/* lose_ownership_proc */ ,
5908 NULL/* transfer_done_proc */);
5911 /* function called when the data to Paste is ready */
5913 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5914 Atom *type, XtPointer value, unsigned long *len, int *format)
5917 if (value == NULL || *len == 0) {
5918 return; /* nothing had been selected to copy */
5920 f = fopen(gamePasteFilename, "w");
5922 DisplayError(_("Can't open temp file"), errno);
5925 fwrite(value, 1, *len, f);
5928 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5931 /* called when Paste Game button is pressed,
5932 * all parameters will be NULL */
5933 void PasteGameProc(w, event, prms, nprms)
5939 XtGetSelectionValue(menuBarWidget,
5940 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5941 /* (XtSelectionCallbackProc) */ PasteGameCB,
5942 NULL, /* client_data passed to PasteGameCB */
5944 /* better to use the time field from the event that triggered the
5945 * call to this function, but that isn't trivial to get
5955 SaveGameProc(NULL, NULL, NULL, NULL);
5959 void QuitProc(w, event, prms, nprms)
5968 void PauseProc(w, event, prms, nprms)
5978 void MachineBlackProc(w, event, prms, nprms)
5984 MachineBlackEvent();
5987 void MachineWhiteProc(w, event, prms, nprms)
5993 MachineWhiteEvent();
5996 void AnalyzeModeProc(w, event, prms, nprms)
6004 if (!first.analysisSupport) {
6005 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6006 DisplayError(buf, 0);
6009 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
6010 if (appData.icsActive) {
6011 if (gameMode != IcsObserving) {
6012 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
6013 DisplayError(buf, 0);
6015 if (appData.icsEngineAnalyze) {
6016 if (appData.debugMode)
6017 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
6023 /* if enable, use want disable icsEngineAnalyze */
6024 if (appData.icsEngineAnalyze) {
6029 appData.icsEngineAnalyze = TRUE;
6030 if (appData.debugMode)
6031 fprintf(debugFP, _("ICS engine analyze starting... \n"));
6033 #ifndef OPTIONSDIALOG
6034 if (!appData.showThinking)
6035 ShowThinkingProc(w,event,prms,nprms);
6041 void AnalyzeFileProc(w, event, prms, nprms)
6047 if (!first.analysisSupport) {
6049 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6050 DisplayError(buf, 0);
6054 #ifndef OPTIONSDIALOG
6055 if (!appData.showThinking)
6056 ShowThinkingProc(w,event,prms,nprms);
6059 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
6060 AnalysisPeriodicEvent(1);
6063 void TwoMachinesProc(w, event, prms, nprms)
6072 void MatchProc(w, event, prms, nprms)
6078 if(gameMode != BeginningOfGame) { DisplayError(_("You can only start a match from the initial position."), 0); return; }
6079 matchMode = 2; // This is back-end, really
\r
6080 appData.matchGames = appData.defaultMatchGames;
\r
6082 first.matchWins = second.matchWins = 0;
\r
6086 void IcsClientProc(w, event, prms, nprms)
6095 void EditGameProc(w, event, prms, nprms)
6104 void EditPositionProc(w, event, prms, nprms)
6110 EditPositionEvent();
6113 void TrainingProc(w, event, prms, nprms)
6122 void EditCommentProc(w, event, prms, nprms)
6129 EditCommentPopDown();
6135 void IcsInputBoxProc(w, event, prms, nprms)
6141 if (!PopDown(4)) ICSInputBoxPopUp();
6144 void AcceptProc(w, event, prms, nprms)
6153 void DeclineProc(w, event, prms, nprms)
6162 void RematchProc(w, event, prms, nprms)
6171 void CallFlagProc(w, event, prms, nprms)
6180 void DrawProc(w, event, prms, nprms)
6189 void AbortProc(w, event, prms, nprms)
6198 void AdjournProc(w, event, prms, nprms)
6207 void ResignProc(w, event, prms, nprms)
6216 void AdjuWhiteProc(w, event, prms, nprms)
6222 UserAdjudicationEvent(+1);
6225 void AdjuBlackProc(w, event, prms, nprms)
6231 UserAdjudicationEvent(-1);
6234 void AdjuDrawProc(w, event, prms, nprms)
6240 UserAdjudicationEvent(0);
6243 void EnterKeyProc(w, event, prms, nprms)
6249 if (shellUp[4] == True)
6253 void UpKeyProc(w, event, prms, nprms)
6258 { // [HGM] input: let up-arrow recall previous line from history
6265 if (!shellUp[4]) return;
6266 edit = boxOptions[0].handle;
6268 XtSetArg(args[j], XtNstring, &val); j++;
6269 XtGetValues(edit, args, j);
6270 val = PrevInHistory(val);
6271 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6272 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6274 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6275 XawTextReplace(edit, 0, 0, &t);
6276 XawTextSetInsertionPoint(edit, 9999);
6280 void DownKeyProc(w, event, prms, nprms)
6285 { // [HGM] input: let down-arrow recall next line from history
6290 if (!shellUp[4]) return;
6291 edit = boxOptions[0].handle;
6292 val = NextInHistory();
6293 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6294 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6296 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6297 XawTextReplace(edit, 0, 0, &t);
6298 XawTextSetInsertionPoint(edit, 9999);
6302 void StopObservingProc(w, event, prms, nprms)
6308 StopObservingEvent();
6311 void StopExaminingProc(w, event, prms, nprms)
6317 StopExaminingEvent();
6320 void UploadProc(w, event, prms, nprms)
6330 void ForwardProc(w, event, prms, nprms)
6340 void BackwardProc(w, event, prms, nprms)
6349 void ToStartProc(w, event, prms, nprms)
6358 void ToEndProc(w, event, prms, nprms)
6367 void RevertProc(w, event, prms, nprms)
6376 void AnnotateProc(w, event, prms, nprms)
6385 void TruncateGameProc(w, event, prms, nprms)
6391 TruncateGameEvent();
6393 void RetractMoveProc(w, event, prms, nprms)
6402 void MoveNowProc(w, event, prms, nprms)
6411 void FlipViewProc(w, event, prms, nprms)
6417 flipView = !flipView;
6418 DrawPosition(True, NULL);
6421 void PonderNextMoveProc(w, event, prms, nprms)
6429 PonderNextMoveEvent(!appData.ponderNextMove);
6430 #ifndef OPTIONSDIALOG
6431 if (appData.ponderNextMove) {
6432 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6434 XtSetArg(args[0], XtNleftBitmap, None);
6436 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6441 #ifndef OPTIONSDIALOG
6442 void AlwaysQueenProc(w, event, prms, nprms)
6450 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6452 if (appData.alwaysPromoteToQueen) {
6453 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6455 XtSetArg(args[0], XtNleftBitmap, None);
6457 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6461 void AnimateDraggingProc(w, event, prms, nprms)
6469 appData.animateDragging = !appData.animateDragging;
6471 if (appData.animateDragging) {
6472 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6475 XtSetArg(args[0], XtNleftBitmap, None);
6477 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6481 void AnimateMovingProc(w, event, prms, nprms)
6489 appData.animate = !appData.animate;
6491 if (appData.animate) {
6492 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6495 XtSetArg(args[0], XtNleftBitmap, None);
6497 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6501 void AutoflagProc(w, event, prms, nprms)
6509 appData.autoCallFlag = !appData.autoCallFlag;
6511 if (appData.autoCallFlag) {
6512 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6514 XtSetArg(args[0], XtNleftBitmap, None);
6516 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6520 void AutoflipProc(w, event, prms, nprms)
6528 appData.autoFlipView = !appData.autoFlipView;
6530 if (appData.autoFlipView) {
6531 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6533 XtSetArg(args[0], XtNleftBitmap, None);
6535 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6539 void BlindfoldProc(w, event, prms, nprms)
6547 appData.blindfold = !appData.blindfold;
6549 if (appData.blindfold) {
6550 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6552 XtSetArg(args[0], XtNleftBitmap, None);
6554 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6557 DrawPosition(True, NULL);
6560 void TestLegalityProc(w, event, prms, nprms)
6568 appData.testLegality = !appData.testLegality;
6570 if (appData.testLegality) {
6571 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6573 XtSetArg(args[0], XtNleftBitmap, None);
6575 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6580 void FlashMovesProc(w, event, prms, nprms)
6588 if (appData.flashCount == 0) {
6589 appData.flashCount = 3;
6591 appData.flashCount = -appData.flashCount;
6594 if (appData.flashCount > 0) {
6595 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6597 XtSetArg(args[0], XtNleftBitmap, None);
6599 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6604 void HighlightDraggingProc(w, event, prms, nprms)
6612 appData.highlightDragging = !appData.highlightDragging;
6614 if (appData.highlightDragging) {
6615 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6617 XtSetArg(args[0], XtNleftBitmap, None);
6619 XtSetValues(XtNameToWidget(menuBarWidget,
6620 "menuOptions.Highlight Dragging"), args, 1);
6624 void HighlightLastMoveProc(w, event, prms, nprms)
6632 appData.highlightLastMove = !appData.highlightLastMove;
6634 if (appData.highlightLastMove) {
6635 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6637 XtSetArg(args[0], XtNleftBitmap, None);
6639 XtSetValues(XtNameToWidget(menuBarWidget,
6640 "menuOptions.Highlight Last Move"), args, 1);
6643 void HighlightArrowProc(w, event, prms, nprms)
6651 appData.highlightMoveWithArrow = !appData.highlightMoveWithArrow;
6653 if (appData.highlightMoveWithArrow) {
6654 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6656 XtSetArg(args[0], XtNleftBitmap, None);
6658 XtSetValues(XtNameToWidget(menuBarWidget,
6659 "menuOptions.Arrow"), args, 1);
6663 void IcsAlarmProc(w, event, prms, nprms)
6671 appData.icsAlarm = !appData.icsAlarm;
6673 if (appData.icsAlarm) {
6674 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6676 XtSetArg(args[0], XtNleftBitmap, None);
6678 XtSetValues(XtNameToWidget(menuBarWidget,
6679 "menuOptions.ICS Alarm"), args, 1);
6683 void MoveSoundProc(w, event, prms, nprms)
6691 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6693 if (appData.ringBellAfterMoves) {
6694 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6696 XtSetArg(args[0], XtNleftBitmap, None);
6698 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6702 void OneClickProc(w, event, prms, nprms)
6710 appData.oneClick = !appData.oneClick;
6712 if (appData.oneClick) {
6713 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6715 XtSetArg(args[0], XtNleftBitmap, None);
6717 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.OneClick"),
6721 void PeriodicUpdatesProc(w, event, prms, nprms)
6729 PeriodicUpdatesEvent(!appData.periodicUpdates);
6731 if (appData.periodicUpdates) {
6732 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6734 XtSetArg(args[0], XtNleftBitmap, None);
6736 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6740 void PopupExitMessageProc(w, event, prms, nprms)
6748 appData.popupExitMessage = !appData.popupExitMessage;
6750 if (appData.popupExitMessage) {
6751 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6753 XtSetArg(args[0], XtNleftBitmap, None);
6755 XtSetValues(XtNameToWidget(menuBarWidget,
6756 "menuOptions.Popup Exit Message"), args, 1);
6759 void PopupMoveErrorsProc(w, event, prms, nprms)
6767 appData.popupMoveErrors = !appData.popupMoveErrors;
6769 if (appData.popupMoveErrors) {
6770 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6772 XtSetArg(args[0], XtNleftBitmap, None);
6774 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6779 void PremoveProc(w, event, prms, nprms)
6787 appData.premove = !appData.premove;
6789 if (appData.premove) {
6790 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6792 XtSetArg(args[0], XtNleftBitmap, None);
6794 XtSetValues(XtNameToWidget(menuBarWidget,
6795 "menuOptions.Premove"), args, 1);
6799 void ShowCoordsProc(w, event, prms, nprms)
6807 appData.showCoords = !appData.showCoords;
6809 if (appData.showCoords) {
6810 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6812 XtSetArg(args[0], XtNleftBitmap, None);
6814 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6817 DrawPosition(True, NULL);
6820 void ShowThinkingProc(w, event, prms, nprms)
6826 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6827 ShowThinkingEvent();
6830 void HideThinkingProc(w, event, prms, nprms)
6838 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6839 ShowThinkingEvent();
6841 if (appData.hideThinkingFromHuman) {
6842 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6844 XtSetArg(args[0], XtNleftBitmap, None);
6846 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6851 void SaveOnExitProc(w, event, prms, nprms)
6859 saveSettingsOnExit = !saveSettingsOnExit;
6861 if (saveSettingsOnExit) {
6862 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6864 XtSetArg(args[0], XtNleftBitmap, None);
6866 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6870 void SaveSettingsProc(w, event, prms, nprms)
6876 SaveSettings(settingsFileName);
6879 void InfoProc(w, event, prms, nprms)
6886 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6891 void ManProc(w, event, prms, nprms)
6899 if (nprms && *nprms > 0)
6903 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6907 void HintProc(w, event, prms, nprms)
6916 void BookProc(w, event, prms, nprms)
6925 void AboutProc(w, event, prms, nprms)
6933 char *zippy = " (with Zippy code)";
6937 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6938 programVersion, zippy,
6939 "Copyright 1991 Digital Equipment Corporation",
6940 "Enhancements Copyright 1992-2009 Free Software Foundation",
6941 "Enhancements Copyright 2005 Alessandro Scotti",
6942 PACKAGE, " is free software and carries NO WARRANTY;",
6943 "see the file COPYING for more information.");
6944 ErrorPopUp(_("About XBoard"), buf, FALSE);
6947 void DebugProc(w, event, prms, nprms)
6953 appData.debugMode = !appData.debugMode;
6956 void AboutGameProc(w, event, prms, nprms)
6965 void NothingProc(w, event, prms, nprms)
6974 void Iconify(w, event, prms, nprms)
6983 XtSetArg(args[0], XtNiconic, True);
6984 XtSetValues(shellWidget, args, 1);
6987 void DisplayMessage(message, extMessage)
6988 char *message, *extMessage;
6990 /* display a message in the message widget */
6999 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
7004 message = extMessage;
7008 /* need to test if messageWidget already exists, since this function
7009 can also be called during the startup, if for example a Xresource
7010 is not set up correctly */
7013 XtSetArg(arg, XtNlabel, message);
7014 XtSetValues(messageWidget, &arg, 1);
7020 void DisplayTitle(text)
7025 char title[MSG_SIZ];
7028 if (text == NULL) text = "";
7030 if (appData.titleInWindow) {
7032 XtSetArg(args[i], XtNlabel, text); i++;
7033 XtSetValues(titleWidget, args, i);
7036 if (*text != NULLCHAR) {
7037 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
7038 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
7039 } else if (appData.icsActive) {
7040 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7041 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7042 } else if (appData.cmailGameName[0] != NULLCHAR) {
7043 snprintf(icon, sizeof(icon), "%s", "CMail");
7044 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7046 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7047 } else if (gameInfo.variant == VariantGothic) {
7048 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7049 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
7052 } else if (gameInfo.variant == VariantFalcon) {
7053 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7054 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
7056 } else if (appData.noChessProgram) {
7057 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7058 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
7060 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
7061 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7064 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7065 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7066 XtSetValues(shellWidget, args, i);
7071 DisplayError(message, error)
7078 if (appData.debugMode || appData.matchMode) {
7079 fprintf(stderr, "%s: %s\n", programName, message);
7082 if (appData.debugMode || appData.matchMode) {
7083 fprintf(stderr, "%s: %s: %s\n",
7084 programName, message, strerror(error));
7086 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7089 ErrorPopUp(_("Error"), message, FALSE);
7093 void DisplayMoveError(message)
7098 DrawPosition(FALSE, NULL);
7099 if (appData.debugMode || appData.matchMode) {
7100 fprintf(stderr, "%s: %s\n", programName, message);
7102 if (appData.popupMoveErrors) {
7103 ErrorPopUp(_("Error"), message, FALSE);
7105 DisplayMessage(message, "");
7110 void DisplayFatalError(message, error, status)
7116 errorExitStatus = status;
7118 fprintf(stderr, "%s: %s\n", programName, message);
7120 fprintf(stderr, "%s: %s: %s\n",
7121 programName, message, strerror(error));
7122 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7125 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7126 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7132 void DisplayInformation(message)
7136 ErrorPopUp(_("Information"), message, TRUE);
7139 void DisplayNote(message)
7143 ErrorPopUp(_("Note"), message, FALSE);
7147 NullXErrorCheck(dpy, error_event)
7149 XErrorEvent *error_event;
7154 void DisplayIcsInteractionTitle(message)
7157 if (oldICSInteractionTitle == NULL) {
7158 /* Magic to find the old window title, adapted from vim */
7159 char *wina = getenv("WINDOWID");
7161 Window win = (Window) atoi(wina);
7162 Window root, parent, *children;
7163 unsigned int nchildren;
7164 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7166 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7167 if (!XQueryTree(xDisplay, win, &root, &parent,
7168 &children, &nchildren)) break;
7169 if (children) XFree((void *)children);
7170 if (parent == root || parent == 0) break;
7173 XSetErrorHandler(oldHandler);
7175 if (oldICSInteractionTitle == NULL) {
7176 oldICSInteractionTitle = "xterm";
7179 printf("\033]0;%s\007", message);
7183 char pendingReplyPrefix[MSG_SIZ];
7184 ProcRef pendingReplyPR;
7186 void AskQuestionProc(w, event, prms, nprms)
7193 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7197 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7200 void AskQuestionPopDown()
7202 if (!askQuestionUp) return;
7203 XtPopdown(askQuestionShell);
7204 XtDestroyWidget(askQuestionShell);
7205 askQuestionUp = False;
7208 void AskQuestionReplyAction(w, event, prms, nprms)
7218 reply = XawDialogGetValueString(w = XtParent(w));
7219 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
7220 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
7221 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
7222 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
7223 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7224 AskQuestionPopDown();
7226 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7229 void AskQuestionCallback(w, client_data, call_data)
7231 XtPointer client_data, call_data;
7236 XtSetArg(args[0], XtNlabel, &name);
7237 XtGetValues(w, args, 1);
7239 if (strcmp(name, _("cancel")) == 0) {
7240 AskQuestionPopDown();
7242 AskQuestionReplyAction(w, NULL, NULL, NULL);
7246 void AskQuestion(title, question, replyPrefix, pr)
7247 char *title, *question, *replyPrefix;
7251 Widget popup, layout, dialog, edit;
7257 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
7258 pendingReplyPR = pr;
7261 XtSetArg(args[i], XtNresizable, True); i++;
7262 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7263 askQuestionShell = popup =
7264 XtCreatePopupShell(title, transientShellWidgetClass,
7265 shellWidget, args, i);
7268 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7269 layoutArgs, XtNumber(layoutArgs));
7272 XtSetArg(args[i], XtNlabel, question); i++;
7273 XtSetArg(args[i], XtNvalue, ""); i++;
7274 XtSetArg(args[i], XtNborderWidth, 0); i++;
7275 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7278 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7279 (XtPointer) dialog);
7280 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7281 (XtPointer) dialog);
7283 XtRealizeWidget(popup);
7284 CatchDeleteWindow(popup, "AskQuestionPopDown");
7286 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7287 &x, &y, &win_x, &win_y, &mask);
7289 XtSetArg(args[0], XtNx, x - 10);
7290 XtSetArg(args[1], XtNy, y - 30);
7291 XtSetValues(popup, args, 2);
7293 XtPopup(popup, XtGrabExclusive);
7294 askQuestionUp = True;
7296 edit = XtNameToWidget(dialog, "*value");
7297 XtSetKeyboardFocus(popup, edit);
7305 if (*name == NULLCHAR) {
7307 } else if (strcmp(name, "$") == 0) {
7308 putc(BELLCHAR, stderr);
7311 char *prefix = "", *sep = "";
7312 if(!strchr(name, '/')) { prefix = appData.soundDirectory; sep = "/"; }
7313 snprintf(buf, sizeof(buf), "%s '%s%s%s' &", appData.soundProgram, prefix, sep, name);
7321 PlaySound(appData.soundMove);
7327 PlaySound(appData.soundIcsWin);
7333 PlaySound(appData.soundIcsLoss);
7339 PlaySound(appData.soundIcsDraw);
7343 PlayIcsUnfinishedSound()
7345 PlaySound(appData.soundIcsUnfinished);
7351 PlaySound(appData.soundIcsAlarm);
7357 system("stty echo");
7363 system("stty -echo");
7367 Colorize(cc, continuation)
7372 int count, outCount, error;
7374 if (textColors[(int)cc].bg > 0) {
7375 if (textColors[(int)cc].fg > 0) {
7376 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7377 textColors[(int)cc].fg, textColors[(int)cc].bg);
7379 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7380 textColors[(int)cc].bg);
7383 if (textColors[(int)cc].fg > 0) {
7384 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7385 textColors[(int)cc].fg);
7387 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7390 count = strlen(buf);
7391 outCount = OutputToProcess(NoProc, buf, count, &error);
7392 if (outCount < count) {
7393 DisplayFatalError(_("Error writing to display"), error, 1);
7396 if (continuation) return;
7399 PlaySound(appData.soundShout);
7402 PlaySound(appData.soundSShout);
7405 PlaySound(appData.soundChannel1);
7408 PlaySound(appData.soundChannel);
7411 PlaySound(appData.soundKibitz);
7414 PlaySound(appData.soundTell);
7416 case ColorChallenge:
7417 PlaySound(appData.soundChallenge);
7420 PlaySound(appData.soundRequest);
7423 PlaySound(appData.soundSeek);
7434 return getpwuid(getuid())->pw_name;
7438 ExpandPathName(path)
7441 static char static_buf[4*MSG_SIZ];
7442 char *d, *s, buf[4*MSG_SIZ];
7448 while (*s && isspace(*s))
7457 if (*(s+1) == '/') {
7458 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7462 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7463 { char *p; if(p = strchr(buf, '/')) *p = 0; }
7464 pwd = getpwnam(buf);
7467 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7471 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7472 strcat(d, strchr(s+1, '/'));
7476 safeStrCpy(d, s, 4*MSG_SIZ );
7483 static char host_name[MSG_SIZ];
7485 #if HAVE_GETHOSTNAME
7486 gethostname(host_name, MSG_SIZ);
7488 #else /* not HAVE_GETHOSTNAME */
7489 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7490 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7492 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7494 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7495 #endif /* not HAVE_GETHOSTNAME */
7498 XtIntervalId delayedEventTimerXID = 0;
7499 DelayedEventCallback delayedEventCallback = 0;
7504 delayedEventTimerXID = 0;
7505 delayedEventCallback();
7509 ScheduleDelayedEvent(cb, millisec)
7510 DelayedEventCallback cb; long millisec;
7512 if(delayedEventTimerXID && delayedEventCallback == cb)
7513 // [HGM] alive: replace, rather than add or flush identical event
7514 XtRemoveTimeOut(delayedEventTimerXID);
7515 delayedEventCallback = cb;
7516 delayedEventTimerXID =
7517 XtAppAddTimeOut(appContext, millisec,
7518 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7521 DelayedEventCallback
7524 if (delayedEventTimerXID) {
7525 return delayedEventCallback;
7532 CancelDelayedEvent()
7534 if (delayedEventTimerXID) {
7535 XtRemoveTimeOut(delayedEventTimerXID);
7536 delayedEventTimerXID = 0;
7540 XtIntervalId loadGameTimerXID = 0;
7542 int LoadGameTimerRunning()
7544 return loadGameTimerXID != 0;
7547 int StopLoadGameTimer()
7549 if (loadGameTimerXID != 0) {
7550 XtRemoveTimeOut(loadGameTimerXID);
7551 loadGameTimerXID = 0;
7559 LoadGameTimerCallback(arg, id)
7563 loadGameTimerXID = 0;
7568 StartLoadGameTimer(millisec)
7572 XtAppAddTimeOut(appContext, millisec,
7573 (XtTimerCallbackProc) LoadGameTimerCallback,
7577 XtIntervalId analysisClockXID = 0;
7580 AnalysisClockCallback(arg, id)
7584 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7585 || appData.icsEngineAnalyze) { // [DM]
7586 AnalysisPeriodicEvent(0);
7587 StartAnalysisClock();
7592 StartAnalysisClock()
7595 XtAppAddTimeOut(appContext, 2000,
7596 (XtTimerCallbackProc) AnalysisClockCallback,
7600 XtIntervalId clockTimerXID = 0;
7602 int ClockTimerRunning()
7604 return clockTimerXID != 0;
7607 int StopClockTimer()
7609 if (clockTimerXID != 0) {
7610 XtRemoveTimeOut(clockTimerXID);
7619 ClockTimerCallback(arg, id)
7628 StartClockTimer(millisec)
7632 XtAppAddTimeOut(appContext, millisec,
7633 (XtTimerCallbackProc) ClockTimerCallback,
7638 DisplayTimerLabel(w, color, timer, highlight)
7647 /* check for low time warning */
7648 Pixel foregroundOrWarningColor = timerForegroundPixel;
7651 appData.lowTimeWarning &&
7652 (timer / 1000) < appData.icsAlarmTime)
7653 foregroundOrWarningColor = lowTimeWarningColor;
7655 if (appData.clockMode) {
7656 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7657 XtSetArg(args[0], XtNlabel, buf);
7659 snprintf(buf, MSG_SIZ, "%s ", color);
7660 XtSetArg(args[0], XtNlabel, buf);
7665 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7666 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7668 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7669 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7672 XtSetValues(w, args, 3);
7676 DisplayWhiteClock(timeRemaining, highlight)
7682 if(appData.noGUI) return;
7683 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7684 if (highlight && iconPixmap == bIconPixmap) {
7685 iconPixmap = wIconPixmap;
7686 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7687 XtSetValues(shellWidget, args, 1);
7692 DisplayBlackClock(timeRemaining, highlight)
7698 if(appData.noGUI) return;
7699 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7700 if (highlight && iconPixmap == wIconPixmap) {
7701 iconPixmap = bIconPixmap;
7702 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7703 XtSetValues(shellWidget, args, 1);
7721 int StartChildProcess(cmdLine, dir, pr)
7728 int to_prog[2], from_prog[2];
7732 if (appData.debugMode) {
7733 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7736 /* We do NOT feed the cmdLine to the shell; we just
7737 parse it into blank-separated arguments in the
7738 most simple-minded way possible.
7741 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7744 while(*p == ' ') p++;
7746 if(*p == '"' || *p == '\'')
7747 p = strchr(++argv[i-1], *p);
7748 else p = strchr(p, ' ');
7749 if (p == NULL) break;
7754 SetUpChildIO(to_prog, from_prog);
7756 if ((pid = fork()) == 0) {
7758 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7759 close(to_prog[1]); // first close the unused pipe ends
7760 close(from_prog[0]);
7761 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7762 dup2(from_prog[1], 1);
7763 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7764 close(from_prog[1]); // and closing again loses one of the pipes!
7765 if(fileno(stderr) >= 2) // better safe than sorry...
7766 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7768 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7773 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7775 execvp(argv[0], argv);
7777 /* If we get here, exec failed */
7782 /* Parent process */
7784 close(from_prog[1]);
7786 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7789 cp->fdFrom = from_prog[0];
7790 cp->fdTo = to_prog[1];
7795 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7796 static RETSIGTYPE AlarmCallBack(int n)
7802 DestroyChildProcess(pr, signalType)
7806 ChildProc *cp = (ChildProc *) pr;
7808 if (cp->kind != CPReal) return;
7810 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7811 signal(SIGALRM, AlarmCallBack);
7813 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7814 kill(cp->pid, SIGKILL); // kill it forcefully
7815 wait((int *) 0); // and wait again
7819 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7821 /* Process is exiting either because of the kill or because of
7822 a quit command sent by the backend; either way, wait for it to die.
7831 InterruptChildProcess(pr)
7834 ChildProc *cp = (ChildProc *) pr;
7836 if (cp->kind != CPReal) return;
7837 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7840 int OpenTelnet(host, port, pr)
7845 char cmdLine[MSG_SIZ];
7847 if (port[0] == NULLCHAR) {
7848 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7850 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7852 return StartChildProcess(cmdLine, "", pr);
7855 int OpenTCP(host, port, pr)
7861 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7862 #else /* !OMIT_SOCKETS */
7864 struct sockaddr_in sa;
7866 unsigned short uport;
7869 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7873 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7874 sa.sin_family = AF_INET;
7875 sa.sin_addr.s_addr = INADDR_ANY;
7876 uport = (unsigned short) 0;
7877 sa.sin_port = htons(uport);
7878 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7882 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7883 if (!(hp = gethostbyname(host))) {
7885 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7886 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7887 hp->h_addrtype = AF_INET;
7889 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7890 hp->h_addr_list[0] = (char *) malloc(4);
7891 hp->h_addr_list[0][0] = b0;
7892 hp->h_addr_list[0][1] = b1;
7893 hp->h_addr_list[0][2] = b2;
7894 hp->h_addr_list[0][3] = b3;
7899 sa.sin_family = hp->h_addrtype;
7900 uport = (unsigned short) atoi(port);
7901 sa.sin_port = htons(uport);
7902 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7904 if (connect(s, (struct sockaddr *) &sa,
7905 sizeof(struct sockaddr_in)) < 0) {
7909 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7916 #endif /* !OMIT_SOCKETS */
7921 int OpenCommPort(name, pr)
7928 fd = open(name, 2, 0);
7929 if (fd < 0) return errno;
7931 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7941 int OpenLoopback(pr)
7947 SetUpChildIO(to, from);
7949 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7952 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7959 int OpenRcmd(host, user, cmd, pr)
7960 char *host, *user, *cmd;
7963 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7967 #define INPUT_SOURCE_BUF_SIZE 8192
7976 char buf[INPUT_SOURCE_BUF_SIZE];
7981 DoInputCallback(closure, source, xid)
7986 InputSource *is = (InputSource *) closure;
7991 if (is->lineByLine) {
7992 count = read(is->fd, is->unused,
7993 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7995 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7998 is->unused += count;
8000 while (p < is->unused) {
8001 q = memchr(p, '\n', is->unused - p);
8002 if (q == NULL) break;
8004 (is->func)(is, is->closure, p, q - p, 0);
8008 while (p < is->unused) {
8013 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8018 (is->func)(is, is->closure, is->buf, count, error);
8022 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8029 ChildProc *cp = (ChildProc *) pr;
8031 is = (InputSource *) calloc(1, sizeof(InputSource));
8032 is->lineByLine = lineByLine;
8036 is->fd = fileno(stdin);
8038 is->kind = cp->kind;
8039 is->fd = cp->fdFrom;
8042 is->unused = is->buf;
8045 is->xid = XtAppAddInput(appContext, is->fd,
8046 (XtPointer) (XtInputReadMask),
8047 (XtInputCallbackProc) DoInputCallback,
8049 is->closure = closure;
8050 return (InputSourceRef) is;
8054 RemoveInputSource(isr)
8057 InputSource *is = (InputSource *) isr;
8059 if (is->xid == 0) return;
8060 XtRemoveInput(is->xid);
8064 int OutputToProcess(pr, message, count, outError)
8070 static int line = 0;
8071 ChildProc *cp = (ChildProc *) pr;
8076 if (appData.noJoin || !appData.useInternalWrap)
8077 outCount = fwrite(message, 1, count, stdout);
8080 int width = get_term_width();
8081 int len = wrap(NULL, message, count, width, &line);
8082 char *msg = malloc(len);
8086 outCount = fwrite(message, 1, count, stdout);
8089 dbgchk = wrap(msg, message, count, width, &line);
8090 if (dbgchk != len && appData.debugMode)
8091 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8092 outCount = fwrite(msg, 1, dbgchk, stdout);
8098 outCount = write(cp->fdTo, message, count);
8108 /* Output message to process, with "ms" milliseconds of delay
8109 between each character. This is needed when sending the logon
8110 script to ICC, which for some reason doesn't like the
8111 instantaneous send. */
8112 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8119 ChildProc *cp = (ChildProc *) pr;
8124 r = write(cp->fdTo, message++, 1);
8137 /**** Animation code by Hugh Fisher, DCS, ANU.
8139 Known problem: if a window overlapping the board is
8140 moved away while a piece is being animated underneath,
8141 the newly exposed area won't be updated properly.
8142 I can live with this.
8144 Known problem: if you look carefully at the animation
8145 of pieces in mono mode, they are being drawn as solid
8146 shapes without interior detail while moving. Fixing
8147 this would be a major complication for minimal return.
8150 /* Masks for XPM pieces. Black and white pieces can have
8151 different shapes, but in the interest of retaining my
8152 sanity pieces must have the same outline on both light
8153 and dark squares, and all pieces must use the same
8154 background square colors/images. */
8156 static int xpmDone = 0;
8159 CreateAnimMasks (pieceDepth)
8166 unsigned long plane;
8169 /* Need a bitmap just to get a GC with right depth */
8170 buf = XCreatePixmap(xDisplay, xBoardWindow,
8172 values.foreground = 1;
8173 values.background = 0;
8174 /* Don't use XtGetGC, not read only */
8175 maskGC = XCreateGC(xDisplay, buf,
8176 GCForeground | GCBackground, &values);
8177 XFreePixmap(xDisplay, buf);
8179 buf = XCreatePixmap(xDisplay, xBoardWindow,
8180 squareSize, squareSize, pieceDepth);
8181 values.foreground = XBlackPixel(xDisplay, xScreen);
8182 values.background = XWhitePixel(xDisplay, xScreen);
8183 bufGC = XCreateGC(xDisplay, buf,
8184 GCForeground | GCBackground, &values);
8186 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8187 /* Begin with empty mask */
8188 if(!xpmDone) // [HGM] pieces: keep using existing
8189 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8190 squareSize, squareSize, 1);
8191 XSetFunction(xDisplay, maskGC, GXclear);
8192 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8193 0, 0, squareSize, squareSize);
8195 /* Take a copy of the piece */
8200 XSetFunction(xDisplay, bufGC, GXcopy);
8201 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8203 0, 0, squareSize, squareSize, 0, 0);
8205 /* XOR the background (light) over the piece */
8206 XSetFunction(xDisplay, bufGC, GXxor);
8208 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8209 0, 0, squareSize, squareSize, 0, 0);
8211 XSetForeground(xDisplay, bufGC, lightSquareColor);
8212 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8215 /* We now have an inverted piece image with the background
8216 erased. Construct mask by just selecting all the non-zero
8217 pixels - no need to reconstruct the original image. */
8218 XSetFunction(xDisplay, maskGC, GXor);
8220 /* Might be quicker to download an XImage and create bitmap
8221 data from it rather than this N copies per piece, but it
8222 only takes a fraction of a second and there is a much
8223 longer delay for loading the pieces. */
8224 for (n = 0; n < pieceDepth; n ++) {
8225 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8226 0, 0, squareSize, squareSize,
8232 XFreePixmap(xDisplay, buf);
8233 XFreeGC(xDisplay, bufGC);
8234 XFreeGC(xDisplay, maskGC);
8238 InitAnimState (anim, info)
8240 XWindowAttributes * info;
8245 /* Each buffer is square size, same depth as window */
8246 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8247 squareSize, squareSize, info->depth);
8248 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8249 squareSize, squareSize, info->depth);
8251 /* Create a plain GC for blitting */
8252 mask = GCForeground | GCBackground | GCFunction |
8253 GCPlaneMask | GCGraphicsExposures;
8254 values.foreground = XBlackPixel(xDisplay, xScreen);
8255 values.background = XWhitePixel(xDisplay, xScreen);
8256 values.function = GXcopy;
8257 values.plane_mask = AllPlanes;
8258 values.graphics_exposures = False;
8259 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8261 /* Piece will be copied from an existing context at
8262 the start of each new animation/drag. */
8263 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8265 /* Outline will be a read-only copy of an existing */
8266 anim->outlineGC = None;
8272 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8273 XWindowAttributes info;
8275 if (xpmDone && gameInfo.variant == old) return;
8276 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8277 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8279 InitAnimState(&game, &info);
8280 InitAnimState(&player, &info);
8282 /* For XPM pieces, we need bitmaps to use as masks. */
8284 CreateAnimMasks(info.depth);
8290 static Boolean frameWaiting;
8292 static RETSIGTYPE FrameAlarm (sig)
8295 frameWaiting = False;
8296 /* In case System-V style signals. Needed?? */
8297 signal(SIGALRM, FrameAlarm);
8304 struct itimerval delay;
8306 XSync(xDisplay, False);
8309 frameWaiting = True;
8310 signal(SIGALRM, FrameAlarm);
8311 delay.it_interval.tv_sec =
8312 delay.it_value.tv_sec = time / 1000;
8313 delay.it_interval.tv_usec =
8314 delay.it_value.tv_usec = (time % 1000) * 1000;
8315 setitimer(ITIMER_REAL, &delay, NULL);
8316 while (frameWaiting) pause();
8317 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8318 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8319 setitimer(ITIMER_REAL, &delay, NULL);
8329 XSync(xDisplay, False);
8331 usleep(time * 1000);
8336 /* Convert board position to corner of screen rect and color */
8339 ScreenSquare(column, row, pt, color)
8340 int column; int row; XPoint * pt; int * color;
8343 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8344 pt->y = lineGap + row * (squareSize + lineGap);
8346 pt->x = lineGap + column * (squareSize + lineGap);
8347 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8349 *color = SquareColor(row, column);
8352 /* Convert window coords to square */
8355 BoardSquare(x, y, column, row)
8356 int x; int y; int * column; int * row;
8358 *column = EventToSquare(x, BOARD_WIDTH);
8359 if (flipView && *column >= 0)
8360 *column = BOARD_WIDTH - 1 - *column;
8361 *row = EventToSquare(y, BOARD_HEIGHT);
8362 if (!flipView && *row >= 0)
8363 *row = BOARD_HEIGHT - 1 - *row;
8368 #undef Max /* just in case */
8370 #define Max(a, b) ((a) > (b) ? (a) : (b))
8371 #define Min(a, b) ((a) < (b) ? (a) : (b))
8374 SetRect(rect, x, y, width, height)
8375 XRectangle * rect; int x; int y; int width; int height;
8379 rect->width = width;
8380 rect->height = height;
8383 /* Test if two frames overlap. If they do, return
8384 intersection rect within old and location of
8385 that rect within new. */
8388 Intersect(old, new, size, area, pt)
8389 XPoint * old; XPoint * new;
8390 int size; XRectangle * area; XPoint * pt;
8392 if (old->x > new->x + size || new->x > old->x + size ||
8393 old->y > new->y + size || new->y > old->y + size) {
8396 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8397 size - abs(old->x - new->x), size - abs(old->y - new->y));
8398 pt->x = Max(old->x - new->x, 0);
8399 pt->y = Max(old->y - new->y, 0);
8404 /* For two overlapping frames, return the rect(s)
8405 in the old that do not intersect with the new. */
8408 CalcUpdateRects(old, new, size, update, nUpdates)
8409 XPoint * old; XPoint * new; int size;
8410 XRectangle update[]; int * nUpdates;
8414 /* If old = new (shouldn't happen) then nothing to draw */
8415 if (old->x == new->x && old->y == new->y) {
8419 /* Work out what bits overlap. Since we know the rects
8420 are the same size we don't need a full intersect calc. */
8422 /* Top or bottom edge? */
8423 if (new->y > old->y) {
8424 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8426 } else if (old->y > new->y) {
8427 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8428 size, old->y - new->y);
8431 /* Left or right edge - don't overlap any update calculated above. */
8432 if (new->x > old->x) {
8433 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8434 new->x - old->x, size - abs(new->y - old->y));
8436 } else if (old->x > new->x) {
8437 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8438 old->x - new->x, size - abs(new->y - old->y));
8445 /* Generate a series of frame coords from start->mid->finish.
8446 The movement rate doubles until the half way point is
8447 reached, then halves back down to the final destination,
8448 which gives a nice slow in/out effect. The algorithmn
8449 may seem to generate too many intermediates for short
8450 moves, but remember that the purpose is to attract the
8451 viewers attention to the piece about to be moved and
8452 then to where it ends up. Too few frames would be less
8456 Tween(start, mid, finish, factor, frames, nFrames)
8457 XPoint * start; XPoint * mid;
8458 XPoint * finish; int factor;
8459 XPoint frames[]; int * nFrames;
8461 int fraction, n, count;
8465 /* Slow in, stepping 1/16th, then 1/8th, ... */
8467 for (n = 0; n < factor; n++)
8469 for (n = 0; n < factor; n++) {
8470 frames[count].x = start->x + (mid->x - start->x) / fraction;
8471 frames[count].y = start->y + (mid->y - start->y) / fraction;
8473 fraction = fraction / 2;
8477 frames[count] = *mid;
8480 /* Slow out, stepping 1/2, then 1/4, ... */
8482 for (n = 0; n < factor; n++) {
8483 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8484 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8486 fraction = fraction * 2;
8491 /* Draw a piece on the screen without disturbing what's there */
8494 SelectGCMask(piece, clip, outline, mask)
8495 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8499 /* Bitmap for piece being moved. */
8500 if (appData.monoMode) {
8501 *mask = *pieceToSolid(piece);
8502 } else if (useImages) {
8504 *mask = xpmMask[piece];
8506 *mask = ximMaskPm[piece];
8509 *mask = *pieceToSolid(piece);
8512 /* GC for piece being moved. Square color doesn't matter, but
8513 since it gets modified we make a copy of the original. */
8515 if (appData.monoMode)
8520 if (appData.monoMode)
8525 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8527 /* Outline only used in mono mode and is not modified */
8529 *outline = bwPieceGC;
8531 *outline = wbPieceGC;
8535 OverlayPiece(piece, clip, outline, dest)
8536 ChessSquare piece; GC clip; GC outline; Drawable dest;
8541 /* Draw solid rectangle which will be clipped to shape of piece */
8542 XFillRectangle(xDisplay, dest, clip,
8543 0, 0, squareSize, squareSize);
8544 if (appData.monoMode)
8545 /* Also draw outline in contrasting color for black
8546 on black / white on white cases */
8547 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8548 0, 0, squareSize, squareSize, 0, 0, 1);
8550 /* Copy the piece */
8555 if(appData.upsideDown && flipView) kind ^= 2;
8556 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8558 0, 0, squareSize, squareSize,
8563 /* Animate the movement of a single piece */
8566 BeginAnimation(anim, piece, startColor, start)
8574 if(appData.upsideDown && flipView) piece += piece < BlackPawn ? BlackPawn : -BlackPawn;
8575 /* The old buffer is initialised with the start square (empty) */
8576 BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0);
8577 anim->prevFrame = *start;
8579 /* The piece will be drawn using its own bitmap as a matte */
8580 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8581 XSetClipMask(xDisplay, anim->pieceGC, mask);
8585 AnimationFrame(anim, frame, piece)
8590 XRectangle updates[4];
8595 /* Save what we are about to draw into the new buffer */
8596 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8597 frame->x, frame->y, squareSize, squareSize,
8600 /* Erase bits of the previous frame */
8601 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8602 /* Where the new frame overlapped the previous,
8603 the contents in newBuf are wrong. */
8604 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8605 overlap.x, overlap.y,
8606 overlap.width, overlap.height,
8608 /* Repaint the areas in the old that don't overlap new */
8609 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8610 for (i = 0; i < count; i++)
8611 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8612 updates[i].x - anim->prevFrame.x,
8613 updates[i].y - anim->prevFrame.y,
8614 updates[i].width, updates[i].height,
8615 updates[i].x, updates[i].y);
8617 /* Easy when no overlap */
8618 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8619 0, 0, squareSize, squareSize,
8620 anim->prevFrame.x, anim->prevFrame.y);
8623 /* Save this frame for next time round */
8624 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8625 0, 0, squareSize, squareSize,
8627 anim->prevFrame = *frame;
8629 /* Draw piece over original screen contents, not current,
8630 and copy entire rect. Wipes out overlapping piece images. */
8631 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8632 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8633 0, 0, squareSize, squareSize,
8634 frame->x, frame->y);
8638 EndAnimation (anim, finish)
8642 XRectangle updates[4];
8647 /* The main code will redraw the final square, so we
8648 only need to erase the bits that don't overlap. */
8649 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8650 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8651 for (i = 0; i < count; i++)
8652 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8653 updates[i].x - anim->prevFrame.x,
8654 updates[i].y - anim->prevFrame.y,
8655 updates[i].width, updates[i].height,
8656 updates[i].x, updates[i].y);
8658 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8659 0, 0, squareSize, squareSize,
8660 anim->prevFrame.x, anim->prevFrame.y);
8665 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8667 ChessSquare piece; int startColor;
8668 XPoint * start; XPoint * finish;
8669 XPoint frames[]; int nFrames;
8673 BeginAnimation(anim, piece, startColor, start);
8674 for (n = 0; n < nFrames; n++) {
8675 AnimationFrame(anim, &(frames[n]), piece);
8676 FrameDelay(appData.animSpeed);
8678 EndAnimation(anim, finish);
8682 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
8685 ChessSquare piece = board[fromY][toY];
8686 board[fromY][toY] = EmptySquare;
8687 DrawPosition(FALSE, board);
8689 x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap);
8690 y = lineGap + toY * (squareSize + lineGap);
8692 x = lineGap + toX * (squareSize + lineGap);
8693 y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap);
8695 for(i=1; i<4*kFactor; i++) {
8696 int r = squareSize * 9 * i/(20*kFactor - 5);
8697 XFillArc(xDisplay, xBoardWindow, highlineGC,
8698 x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360);
8699 FrameDelay(appData.animSpeed);
8701 board[fromY][toY] = piece;
8704 /* Main control logic for deciding what to animate and how */
8707 AnimateMove(board, fromX, fromY, toX, toY)
8716 XPoint start, finish, mid;
8717 XPoint frames[kFactor * 2 + 1];
8718 int nFrames, startColor, endColor;
8720 /* Are we animating? */
8721 if (!appData.animate || appData.blindfold)
8724 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8725 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8726 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8728 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8729 piece = board[fromY][fromX];
8730 if (piece >= EmptySquare) return;
8735 hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1;
8738 if (appData.debugMode) {
8739 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8740 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8741 piece, fromX, fromY, toX, toY); }
8743 ScreenSquare(fromX, fromY, &start, &startColor);
8744 ScreenSquare(toX, toY, &finish, &endColor);
8747 /* Knight: make straight movement then diagonal */
8748 if (abs(toY - fromY) < abs(toX - fromX)) {
8749 mid.x = start.x + (finish.x - start.x) / 2;
8753 mid.y = start.y + (finish.y - start.y) / 2;
8756 mid.x = start.x + (finish.x - start.x) / 2;
8757 mid.y = start.y + (finish.y - start.y) / 2;
8760 /* Don't use as many frames for very short moves */
8761 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8762 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8764 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8765 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8766 if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
8768 for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
8769 if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
8772 /* Be sure end square is redrawn */
8773 damage[0][toY][toX] = True;
8777 DragPieceBegin(x, y)
8780 int boardX, boardY, color;
8783 /* Are we animating? */
8784 if (!appData.animateDragging || appData.blindfold)
8787 /* Figure out which square we start in and the
8788 mouse position relative to top left corner. */
8789 BoardSquare(x, y, &boardX, &boardY);
8790 player.startBoardX = boardX;
8791 player.startBoardY = boardY;
8792 ScreenSquare(boardX, boardY, &corner, &color);
8793 player.startSquare = corner;
8794 player.startColor = color;
8795 /* As soon as we start dragging, the piece will jump slightly to
8796 be centered over the mouse pointer. */
8797 player.mouseDelta.x = squareSize/2;
8798 player.mouseDelta.y = squareSize/2;
8799 /* Initialise animation */
8800 player.dragPiece = PieceForSquare(boardX, boardY);
8802 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8803 player.dragActive = True;
8804 BeginAnimation(&player, player.dragPiece, color, &corner);
8805 /* Mark this square as needing to be redrawn. Note that
8806 we don't remove the piece though, since logically (ie
8807 as seen by opponent) the move hasn't been made yet. */
8808 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8809 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8810 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8811 corner.x, corner.y, squareSize, squareSize,
8812 0, 0); // [HGM] zh: unstack in stead of grab
8813 if(gatingPiece != EmptySquare) {
8814 /* Kludge alert: When gating we want the introduced
8815 piece to appear on the from square. To generate an
8816 image of it, we draw it on the board, copy the image,
8817 and draw the original piece again. */
8818 ChessSquare piece = boards[currentMove][boardY][boardX];
8819 DrawSquare(boardY, boardX, gatingPiece, 0);
8820 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8821 corner.x, corner.y, squareSize, squareSize, 0, 0);
8822 DrawSquare(boardY, boardX, piece, 0);
8824 damage[0][boardY][boardX] = True;
8826 player.dragActive = False;
8836 /* Are we animating? */
8837 if (!appData.animateDragging || appData.blindfold)
8841 if (! player.dragActive)
8843 /* Move piece, maintaining same relative position
8844 of mouse within square */
8845 corner.x = x - player.mouseDelta.x;
8846 corner.y = y - player.mouseDelta.y;
8847 AnimationFrame(&player, &corner, player.dragPiece);
8849 if (appData.highlightDragging) {
8851 BoardSquare(x, y, &boardX, &boardY);
8852 SetHighlights(fromX, fromY, boardX, boardY);
8861 int boardX, boardY, color;
8864 /* Are we animating? */
8865 if (!appData.animateDragging || appData.blindfold)
8869 if (! player.dragActive)
8871 /* Last frame in sequence is square piece is
8872 placed on, which may not match mouse exactly. */
8873 BoardSquare(x, y, &boardX, &boardY);
8874 ScreenSquare(boardX, boardY, &corner, &color);
8875 EndAnimation(&player, &corner);
8877 /* Be sure end square is redrawn */
8878 damage[0][boardY][boardX] = True;
8880 /* This prevents weird things happening with fast successive
8881 clicks which on my Sun at least can cause motion events
8882 without corresponding press/release. */
8883 player.dragActive = False;
8886 /* Handle expose event while piece being dragged */
8891 if (!player.dragActive || appData.blindfold)
8894 /* What we're doing: logically, the move hasn't been made yet,
8895 so the piece is still in it's original square. But visually
8896 it's being dragged around the board. So we erase the square
8897 that the piece is on and draw it at the last known drag point. */
8898 BlankSquare(player.startSquare.x, player.startSquare.y,
8899 player.startColor, EmptySquare, xBoardWindow, 1);
8900 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8901 damage[0][player.startBoardY][player.startBoardX] = TRUE;
8904 #include <sys/ioctl.h>
8905 int get_term_width()
8907 int fd, default_width;
8910 default_width = 79; // this is FICS default anyway...
8912 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8914 if (!ioctl(fd, TIOCGSIZE, &win))
8915 default_width = win.ts_cols;
8916 #elif defined(TIOCGWINSZ)
8918 if (!ioctl(fd, TIOCGWINSZ, &win))
8919 default_width = win.ws_col;
8921 return default_width;
8927 static int old_width = 0;
8928 int new_width = get_term_width();
8930 if (old_width != new_width)
8931 ics_printf("set width %d\n", new_width);
8932 old_width = new_width;
8935 void NotifyFrontendLogin()
8940 /* [AS] Arrow highlighting support */
8942 static double A_WIDTH = 5; /* Width of arrow body */
8944 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
8945 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
8947 static double Sqr( double x )
8952 static int Round( double x )
8954 return (int) (x + 0.5);
8957 void SquareToPos(int rank, int file, int *x, int *y)
8960 *x = lineGap + ((BOARD_WIDTH-1)-file) * (squareSize + lineGap);
8961 *y = lineGap + rank * (squareSize + lineGap);
8963 *x = lineGap + file * (squareSize + lineGap);
8964 *y = lineGap + ((BOARD_HEIGHT-1)-rank) * (squareSize + lineGap);
8968 /* Draw an arrow between two points using current settings */
8969 void DrawArrowBetweenPoints( int s_x, int s_y, int d_x, int d_y )
8972 double dx, dy, j, k, x, y;
8975 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
8977 arrow[0].x = s_x + A_WIDTH + 0.5;
8980 arrow[1].x = s_x + A_WIDTH + 0.5;
8981 arrow[1].y = d_y - h;
8983 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8984 arrow[2].y = d_y - h;
8989 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
8990 arrow[5].y = d_y - h;
8992 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8993 arrow[4].y = d_y - h;
8995 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
8998 else if( d_y == s_y ) {
8999 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
9002 arrow[0].y = s_y + A_WIDTH + 0.5;
9004 arrow[1].x = d_x - w;
9005 arrow[1].y = s_y + A_WIDTH + 0.5;
9007 arrow[2].x = d_x - w;
9008 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9013 arrow[5].x = d_x - w;
9014 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
9016 arrow[4].x = d_x - w;
9017 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9020 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
9023 /* [AS] Needed a lot of paper for this! :-) */
9024 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
9025 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
9027 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
9029 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
9034 arrow[0].x = Round(x - j);
9035 arrow[0].y = Round(y + j*dx);
9037 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
9038 arrow[1].y = Round(arrow[0].y - 2*j*dx);
9041 x = (double) d_x - k;
9042 y = (double) d_y - k*dy;
9045 x = (double) d_x + k;
9046 y = (double) d_y + k*dy;
9049 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
9051 arrow[6].x = Round(x - j);
9052 arrow[6].y = Round(y + j*dx);
9054 arrow[2].x = Round(arrow[6].x + 2*j);
9055 arrow[2].y = Round(arrow[6].y - 2*j*dx);
9057 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
9058 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
9063 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
9064 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
9067 XFillPolygon(xDisplay, xBoardWindow, highlineGC, arrow, 7, Nonconvex, CoordModeOrigin);
9068 // Polygon( hdc, arrow, 7 );
9071 /* [AS] Draw an arrow between two squares */
9072 void DrawArrowBetweenSquares( int s_col, int s_row, int d_col, int d_row )
9074 int s_x, s_y, d_x, d_y, hor, vert, i;
9076 if( s_col == d_col && s_row == d_row ) {
9080 /* Get source and destination points */
9081 SquareToPos( s_row, s_col, &s_x, &s_y);
9082 SquareToPos( d_row, d_col, &d_x, &d_y);
9085 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
9087 else if( d_y < s_y ) {
9088 d_y += squareSize / 2 + squareSize / 4;
9091 d_y += squareSize / 2;
9095 d_x += squareSize / 2 - squareSize / 4;
9097 else if( d_x < s_x ) {
9098 d_x += squareSize / 2 + squareSize / 4;
9101 d_x += squareSize / 2;
9104 s_x += squareSize / 2;
9105 s_y += squareSize / 2;
9108 A_WIDTH = squareSize / 14.; //[HGM] make float
9110 DrawArrowBetweenPoints( s_x, s_y, d_x, d_y );
9112 hor = 64*s_col + 32; vert = 64*s_row + 32;
9113 for(i=0; i<= 64; i++) {
9114 damage[0][vert+6>>6][hor+6>>6] = True;
9115 damage[0][vert-6>>6][hor+6>>6] = True;
9116 damage[0][vert+6>>6][hor-6>>6] = True;
9117 damage[0][vert-6>>6][hor-6>>6] = True;
9118 hor += d_col - s_col; vert += d_row - s_row;
9122 Boolean IsDrawArrowEnabled()
9124 return appData.highlightMoveWithArrow && squareSize >= 32;
9127 void DrawArrowHighlight(int fromX, int fromY, int toX,int toY)
9129 if( IsDrawArrowEnabled() && fromX >= 0 && fromY >= 0 && toX >= 0 && toY >= 0)
9130 DrawArrowBetweenSquares(fromX, fromY, toX, toY);