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, defaultLineGap;
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 defaultLineGap = lineGap;
2090 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
2092 /* [HR] height treated separately (hacked) */
2093 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
2094 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
2095 if (appData.showJail == 1) {
2096 /* Jail on top and bottom */
2097 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2098 XtSetArg(boardArgs[2], XtNheight,
2099 boardHeight + 2*(lineGap + squareSize));
2100 } else if (appData.showJail == 2) {
2102 XtSetArg(boardArgs[1], XtNwidth,
2103 boardWidth + 2*(lineGap + squareSize));
2104 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2107 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2108 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2112 * Determine what fonts to use.
2114 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2115 clockFontID = XLoadFont(xDisplay, appData.clockFont);
2116 clockFontStruct = XQueryFont(xDisplay, clockFontID);
2117 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2118 coordFontID = XLoadFont(xDisplay, appData.coordFont);
2119 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2120 appData.font = FindFont(appData.font, fontPxlSize);
2121 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
2122 countFontStruct = XQueryFont(xDisplay, countFontID);
2123 // appData.font = FindFont(appData.font, fontPxlSize);
2125 xdb = XtDatabase(xDisplay);
2126 XrmPutStringResource(&xdb, "*font", appData.font);
2129 * Detect if there are not enough colors available and adapt.
2131 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2132 appData.monoMode = True;
2135 forceMono = MakeColors();
2138 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2141 if (appData.bitmapDirectory == NULL ||
2142 appData.bitmapDirectory[0] == NULLCHAR)
2143 appData.bitmapDirectory = DEF_BITMAP_DIR;
2146 if (appData.lowTimeWarning && !appData.monoMode) {
2147 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2148 vFrom.size = strlen(appData.lowTimeWarningColor);
2149 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2150 if (vTo.addr == NULL)
2151 appData.monoMode = True;
2153 lowTimeWarningColor = *(Pixel *) vTo.addr;
2156 if (appData.monoMode && appData.debugMode) {
2157 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2158 (unsigned long) XWhitePixel(xDisplay, xScreen),
2159 (unsigned long) XBlackPixel(xDisplay, xScreen));
2162 ParseIcsTextColors();
2163 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2164 textColors[ColorNone].attr = 0;
2166 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2172 layoutName = "tinyLayout";
2173 } else if (smallLayout) {
2174 layoutName = "smallLayout";
2176 layoutName = "normalLayout";
2178 /* Outer layoutWidget is there only to provide a name for use in
2179 resources that depend on the layout style */
2181 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2182 layoutArgs, XtNumber(layoutArgs));
2184 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2185 formArgs, XtNumber(formArgs));
2186 XtSetArg(args[0], XtNdefaultDistance, &sep);
2187 XtGetValues(formWidget, args, 1);
2190 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2191 XtSetArg(args[0], XtNtop, XtChainTop);
2192 XtSetArg(args[1], XtNbottom, XtChainTop);
2193 XtSetArg(args[2], XtNright, XtChainLeft);
2194 XtSetValues(menuBarWidget, args, 3);
2196 widgetList[j++] = whiteTimerWidget =
2197 XtCreateWidget("whiteTime", labelWidgetClass,
2198 formWidget, timerArgs, XtNumber(timerArgs));
2199 XtSetArg(args[0], XtNfont, clockFontStruct);
2200 XtSetArg(args[1], XtNtop, XtChainTop);
2201 XtSetArg(args[2], XtNbottom, XtChainTop);
2202 XtSetValues(whiteTimerWidget, args, 3);
2204 widgetList[j++] = blackTimerWidget =
2205 XtCreateWidget("blackTime", labelWidgetClass,
2206 formWidget, timerArgs, XtNumber(timerArgs));
2207 XtSetArg(args[0], XtNfont, clockFontStruct);
2208 XtSetArg(args[1], XtNtop, XtChainTop);
2209 XtSetArg(args[2], XtNbottom, XtChainTop);
2210 XtSetValues(blackTimerWidget, args, 3);
2212 if (appData.titleInWindow) {
2213 widgetList[j++] = titleWidget =
2214 XtCreateWidget("title", labelWidgetClass, formWidget,
2215 titleArgs, XtNumber(titleArgs));
2216 XtSetArg(args[0], XtNtop, XtChainTop);
2217 XtSetArg(args[1], XtNbottom, XtChainTop);
2218 XtSetValues(titleWidget, args, 2);
2221 if (appData.showButtonBar) {
2222 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2223 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2224 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2225 XtSetArg(args[2], XtNtop, XtChainTop);
2226 XtSetArg(args[3], XtNbottom, XtChainTop);
2227 XtSetValues(buttonBarWidget, args, 4);
2230 widgetList[j++] = messageWidget =
2231 XtCreateWidget("message", labelWidgetClass, formWidget,
2232 messageArgs, XtNumber(messageArgs));
2233 XtSetArg(args[0], XtNtop, XtChainTop);
2234 XtSetArg(args[1], XtNbottom, XtChainTop);
2235 XtSetValues(messageWidget, args, 2);
2237 widgetList[j++] = boardWidget =
2238 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2239 XtNumber(boardArgs));
2241 XtManageChildren(widgetList, j);
2243 timerWidth = (boardWidth - sep) / 2;
2244 XtSetArg(args[0], XtNwidth, timerWidth);
2245 XtSetValues(whiteTimerWidget, args, 1);
2246 XtSetValues(blackTimerWidget, args, 1);
2248 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2249 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2250 XtGetValues(whiteTimerWidget, args, 2);
2252 if (appData.showButtonBar) {
2253 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2254 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2255 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2259 * formWidget uses these constraints but they are stored
2263 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2264 XtSetValues(menuBarWidget, args, i);
2265 if (appData.titleInWindow) {
2268 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2269 XtSetValues(whiteTimerWidget, args, i);
2271 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2272 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2273 XtSetValues(blackTimerWidget, args, i);
2275 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2276 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2277 XtSetValues(titleWidget, args, i);
2279 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2280 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2281 XtSetValues(messageWidget, args, i);
2282 if (appData.showButtonBar) {
2284 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2285 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2286 XtSetValues(buttonBarWidget, args, i);
2290 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2291 XtSetValues(whiteTimerWidget, args, i);
2293 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2294 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2295 XtSetValues(blackTimerWidget, args, i);
2297 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2298 XtSetValues(titleWidget, args, i);
2300 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2301 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2302 XtSetValues(messageWidget, args, i);
2303 if (appData.showButtonBar) {
2305 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2306 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2307 XtSetValues(buttonBarWidget, args, i);
2312 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2313 XtSetValues(whiteTimerWidget, args, i);
2315 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2316 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2317 XtSetValues(blackTimerWidget, args, i);
2319 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2320 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2321 XtSetValues(messageWidget, args, i);
2322 if (appData.showButtonBar) {
2324 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2325 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2326 XtSetValues(buttonBarWidget, args, i);
2330 XtSetArg(args[0], XtNfromVert, messageWidget);
2331 XtSetArg(args[1], XtNtop, XtChainTop);
2332 XtSetArg(args[2], XtNbottom, XtChainBottom);
2333 XtSetArg(args[3], XtNleft, XtChainLeft);
2334 XtSetArg(args[4], XtNright, XtChainRight);
2335 XtSetValues(boardWidget, args, 5);
2337 XtRealizeWidget(shellWidget);
2340 XtSetArg(args[0], XtNx, wpMain.x);
2341 XtSetArg(args[1], XtNy, wpMain.y);
2342 XtSetValues(shellWidget, args, 2);
2346 * Correct the width of the message and title widgets.
2347 * It is not known why some systems need the extra fudge term.
2348 * The value "2" is probably larger than needed.
2350 XawFormDoLayout(formWidget, False);
2352 #define WIDTH_FUDGE 2
2354 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2355 XtSetArg(args[i], XtNheight, &h); i++;
2356 XtGetValues(messageWidget, args, i);
2357 if (appData.showButtonBar) {
2359 XtSetArg(args[i], XtNwidth, &w); i++;
2360 XtGetValues(buttonBarWidget, args, i);
2361 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2363 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2366 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2367 if (gres != XtGeometryYes && appData.debugMode) {
2368 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2369 programName, gres, w, h, wr, hr);
2372 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2373 /* The size used for the child widget in layout lags one resize behind
2374 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2376 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2377 if (gres != XtGeometryYes && appData.debugMode) {
2378 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2379 programName, gres, w, h, wr, hr);
2382 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2383 XtSetArg(args[1], XtNright, XtChainRight);
2384 XtSetValues(messageWidget, args, 2);
2386 if (appData.titleInWindow) {
2388 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2389 XtSetArg(args[i], XtNheight, &h); i++;
2390 XtGetValues(titleWidget, args, i);
2392 w = boardWidth - 2*bor;
2394 XtSetArg(args[0], XtNwidth, &w);
2395 XtGetValues(menuBarWidget, args, 1);
2396 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2399 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2400 if (gres != XtGeometryYes && appData.debugMode) {
2402 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2403 programName, gres, w, h, wr, hr);
2406 XawFormDoLayout(formWidget, True);
2408 xBoardWindow = XtWindow(boardWidget);
2410 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2411 // not need to go into InitDrawingSizes().
2415 * Create X checkmark bitmap and initialize option menu checks.
2417 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2418 checkmark_bits, checkmark_width, checkmark_height);
2419 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2420 #ifndef OPTIONSDIALOG
2421 if (appData.alwaysPromoteToQueen) {
2422 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2425 if (appData.animateDragging) {
2426 XtSetValues(XtNameToWidget(menuBarWidget,
2427 "menuOptions.Animate Dragging"),
2430 if (appData.animate) {
2431 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2434 if (appData.autoCallFlag) {
2435 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2438 if (appData.autoFlipView) {
2439 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2442 if (appData.blindfold) {
2443 XtSetValues(XtNameToWidget(menuBarWidget,
2444 "menuOptions.Blindfold"), args, 1);
2446 if (appData.flashCount > 0) {
2447 XtSetValues(XtNameToWidget(menuBarWidget,
2448 "menuOptions.Flash Moves"),
2452 if (appData.highlightDragging) {
2453 XtSetValues(XtNameToWidget(menuBarWidget,
2454 "menuOptions.Highlight Dragging"),
2458 if (appData.highlightLastMove) {
2459 XtSetValues(XtNameToWidget(menuBarWidget,
2460 "menuOptions.Highlight Last Move"),
2463 if (appData.highlightMoveWithArrow) {
2464 XtSetValues(XtNameToWidget(menuBarWidget,
2465 "menuOptions.Arrow"),
2468 // if (appData.icsAlarm) {
2469 // XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2472 if (appData.ringBellAfterMoves) {
2473 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2476 if (appData.oneClick) {
2477 XtSetValues(XtNameToWidget(menuBarWidget,
2478 "menuOptions.OneClick"), args, 1);
2480 if (appData.periodicUpdates) {
2481 XtSetValues(XtNameToWidget(menuBarWidget,
2482 "menuOptions.Periodic Updates"), args, 1);
2484 if (appData.ponderNextMove) {
2485 XtSetValues(XtNameToWidget(menuBarWidget,
2486 "menuOptions.Ponder Next Move"), args, 1);
2488 if (appData.popupExitMessage) {
2489 XtSetValues(XtNameToWidget(menuBarWidget,
2490 "menuOptions.Popup Exit Message"), args, 1);
2492 if (appData.popupMoveErrors) {
2493 XtSetValues(XtNameToWidget(menuBarWidget,
2494 "menuOptions.Popup Move Errors"), args, 1);
2496 // if (appData.premove) {
2497 // XtSetValues(XtNameToWidget(menuBarWidget,
2498 // "menuOptions.Premove"), args, 1);
2500 if (appData.showCoords) {
2501 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2504 if (appData.hideThinkingFromHuman) {
2505 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2508 if (appData.testLegality) {
2509 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2513 if (saveSettingsOnExit) {
2514 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2521 ReadBitmap(&wIconPixmap, "icon_white.bm",
2522 icon_white_bits, icon_white_width, icon_white_height);
2523 ReadBitmap(&bIconPixmap, "icon_black.bm",
2524 icon_black_bits, icon_black_width, icon_black_height);
2525 iconPixmap = wIconPixmap;
2527 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2528 XtSetValues(shellWidget, args, i);
2531 * Create a cursor for the board widget.
2533 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2534 XChangeWindowAttributes(xDisplay, xBoardWindow,
2535 CWCursor, &window_attributes);
2538 * Inhibit shell resizing.
2540 shellArgs[0].value = (XtArgVal) &w;
2541 shellArgs[1].value = (XtArgVal) &h;
2542 XtGetValues(shellWidget, shellArgs, 2);
2543 shellArgs[4].value = shellArgs[2].value = w;
2544 shellArgs[5].value = shellArgs[3].value = h;
2545 XtSetValues(shellWidget, &shellArgs[2], 4);
2546 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2547 marginH = h - boardHeight;
2549 CatchDeleteWindow(shellWidget, "QuitProc");
2554 if (appData.bitmapDirectory[0] != NULLCHAR) {
2558 CreateXPMBoard(appData.liteBackTextureFile, 1);
2559 CreateXPMBoard(appData.darkBackTextureFile, 0);
2563 /* Create regular pieces */
2564 if (!useImages) CreatePieces();
2569 if (appData.animate || appData.animateDragging)
2572 XtAugmentTranslations(formWidget,
2573 XtParseTranslationTable(globalTranslations));
2574 XtAugmentTranslations(boardWidget,
2575 XtParseTranslationTable(boardTranslations));
2576 XtAugmentTranslations(whiteTimerWidget,
2577 XtParseTranslationTable(whiteTranslations));
2578 XtAugmentTranslations(blackTimerWidget,
2579 XtParseTranslationTable(blackTranslations));
2581 /* Why is the following needed on some versions of X instead
2582 * of a translation? */
2583 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2584 (XtEventHandler) EventProc, NULL);
2587 /* [AS] Restore layout */
2588 if( wpMoveHistory.visible ) {
2592 if( wpEvalGraph.visible )
2597 if( wpEngineOutput.visible ) {
2598 EngineOutputPopUp();
2603 if (errorExitStatus == -1) {
2604 if (appData.icsActive) {
2605 /* We now wait until we see "login:" from the ICS before
2606 sending the logon script (problems with timestamp otherwise) */
2607 /*ICSInitScript();*/
2608 if (appData.icsInputBox) ICSInputBoxPopUp();
2612 signal(SIGWINCH, TermSizeSigHandler);
2614 signal(SIGINT, IntSigHandler);
2615 signal(SIGTERM, IntSigHandler);
2616 if (*appData.cmailGameName != NULLCHAR) {
2617 signal(SIGUSR1, CmailSigHandler);
2620 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2622 XtSetKeyboardFocus(shellWidget, formWidget);
2624 XtAppMainLoop(appContext);
2625 if (appData.debugMode) fclose(debugFP); // [DM] debug
2632 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2633 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2635 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2636 unlink(gameCopyFilename);
2637 unlink(gamePasteFilename);
2640 RETSIGTYPE TermSizeSigHandler(int sig)
2653 CmailSigHandler(sig)
2659 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2661 /* Activate call-back function CmailSigHandlerCallBack() */
2662 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2664 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2668 CmailSigHandlerCallBack(isr, closure, message, count, error)
2676 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2678 /**** end signal code ****/
2684 /* try to open the icsLogon script, either in the location given
2685 * or in the users HOME directory
2692 f = fopen(appData.icsLogon, "r");
2695 homedir = getenv("HOME");
2696 if (homedir != NULL)
2698 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2699 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2700 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2701 f = fopen(buf, "r");
2706 ProcessICSInitScript(f);
2708 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2717 EditCommentPopDown();
2732 if (!menuBarWidget) return;
2733 w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2735 DisplayError("menuEdit.Revert", 0);
2737 XtSetSensitive(w, !grey);
2739 w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2741 DisplayError("menuEdit.Annotate", 0);
2743 XtSetSensitive(w, !grey);
2748 SetMenuEnables(enab)
2752 if (!menuBarWidget) return;
2753 while (enab->name != NULL) {
2754 w = XtNameToWidget(menuBarWidget, enab->name);
2756 DisplayError(enab->name, 0);
2758 XtSetSensitive(w, enab->value);
2764 Enables icsEnables[] = {
2765 { "menuFile.Mail Move", False },
2766 { "menuFile.Reload CMail Message", False },
2767 { "menuMode.Machine Black", False },
2768 { "menuMode.Machine White", False },
2769 { "menuMode.Analysis Mode", False },
2770 { "menuMode.Analyze File", False },
2771 { "menuMode.Two Machines", False },
2772 { "menuMode.Machine Match", False },
2774 { "menuEngine.Hint", False },
2775 { "menuEngine.Book", False },
2776 { "menuEngine.Move Now", False },
2777 #ifndef OPTIONSDIALOG
2778 { "menuOptions.Periodic Updates", False },
2779 { "menuOptions.Hide Thinking", False },
2780 { "menuOptions.Ponder Next Move", False },
2782 { "menuEngine.Engine #1 Settings", False },
2784 { "menuEngine.Engine #2 Settings", False },
2785 { "menuEdit.Annotate", False },
2789 Enables ncpEnables[] = {
2790 { "menuFile.Mail Move", False },
2791 { "menuFile.Reload CMail Message", False },
2792 { "menuMode.Machine White", False },
2793 { "menuMode.Machine Black", False },
2794 { "menuMode.Analysis Mode", False },
2795 { "menuMode.Analyze File", False },
2796 { "menuMode.Two Machines", False },
2797 { "menuMode.Machine Match", False },
2798 { "menuMode.ICS Client", False },
2799 { "menuView.ICStex", False },
2800 { "menuView.ICS Input Box", False },
2801 { "Action", False },
2802 { "menuEdit.Revert", False },
2803 { "menuEdit.Annotate", False },
2804 { "menuEngine.Engine #1 Settings", False },
2805 { "menuEngine.Engine #2 Settings", False },
2806 { "menuEngine.Move Now", False },
2807 { "menuEngine.Retract Move", False },
2808 { "menuOptions.ICS", False },
2809 #ifndef OPTIONSDIALOG
2810 { "menuOptions.Auto Flag", False },
2811 { "menuOptions.Auto Flip View", False },
2812 // { "menuOptions.ICS Alarm", False },
2813 { "menuOptions.Move Sound", False },
2814 { "menuOptions.Hide Thinking", False },
2815 { "menuOptions.Periodic Updates", False },
2816 { "menuOptions.Ponder Next Move", False },
2818 { "menuEngine.Hint", False },
2819 { "menuEngine.Book", False },
2823 Enables gnuEnables[] = {
2824 { "menuMode.ICS Client", False },
2825 { "menuView.ICStex", False },
2826 { "menuView.ICS Input Box", False },
2827 { "menuAction.Accept", False },
2828 { "menuAction.Decline", False },
2829 { "menuAction.Rematch", False },
2830 { "menuAction.Adjourn", False },
2831 { "menuAction.Stop Examining", False },
2832 { "menuAction.Stop Observing", False },
2833 { "menuAction.Upload to Examine", False },
2834 { "menuEdit.Revert", False },
2835 { "menuEdit.Annotate", False },
2836 { "menuOptions.ICS", False },
2838 /* The next two options rely on SetCmailMode being called *after* */
2839 /* SetGNUMode so that when GNU is being used to give hints these */
2840 /* menu options are still available */
2842 { "menuFile.Mail Move", False },
2843 { "menuFile.Reload CMail Message", False },
2847 Enables cmailEnables[] = {
2849 { "menuAction.Call Flag", False },
2850 { "menuAction.Draw", True },
2851 { "menuAction.Adjourn", False },
2852 { "menuAction.Abort", False },
2853 { "menuAction.Stop Observing", False },
2854 { "menuAction.Stop Examining", False },
2855 { "menuFile.Mail Move", True },
2856 { "menuFile.Reload CMail Message", True },
2860 Enables trainingOnEnables[] = {
2861 { "menuMode.Edit Comment", False },
2862 { "menuMode.Pause", False },
2863 { "menuEdit.Forward", False },
2864 { "menuEdit.Backward", False },
2865 { "menuEdit.Forward to End", False },
2866 { "menuEdit.Back to Start", False },
2867 { "menuEngine.Move Now", False },
2868 { "menuEdit.Truncate Game", False },
2872 Enables trainingOffEnables[] = {
2873 { "menuMode.Edit Comment", True },
2874 { "menuMode.Pause", True },
2875 { "menuEdit.Forward", True },
2876 { "menuEdit.Backward", True },
2877 { "menuEdit.Forward to End", True },
2878 { "menuEdit.Back to Start", True },
2879 { "menuEngine.Move Now", True },
2880 { "menuEdit.Truncate Game", True },
2884 Enables machineThinkingEnables[] = {
2885 { "menuFile.Load Game", False },
2886 // { "menuFile.Load Next Game", False },
2887 // { "menuFile.Load Previous Game", False },
2888 // { "menuFile.Reload Same Game", False },
2889 { "menuEdit.Paste Game", False },
2890 { "menuFile.Load Position", False },
2891 // { "menuFile.Load Next Position", False },
2892 // { "menuFile.Load Previous Position", False },
2893 // { "menuFile.Reload Same Position", False },
2894 { "menuEdit.Paste Position", False },
2895 { "menuMode.Machine White", False },
2896 { "menuMode.Machine Black", False },
2897 { "menuMode.Two Machines", False },
2898 { "menuMode.Machine Match", False },
2899 { "menuEngine.Retract Move", False },
2903 Enables userThinkingEnables[] = {
2904 { "menuFile.Load Game", True },
2905 // { "menuFile.Load Next Game", True },
2906 // { "menuFile.Load Previous Game", True },
2907 // { "menuFile.Reload Same Game", True },
2908 { "menuEdit.Paste Game", True },
2909 { "menuFile.Load Position", True },
2910 // { "menuFile.Load Next Position", True },
2911 // { "menuFile.Load Previous Position", True },
2912 // { "menuFile.Reload Same Position", True },
2913 { "menuEdit.Paste Position", True },
2914 { "menuMode.Machine White", True },
2915 { "menuMode.Machine Black", True },
2916 { "menuMode.Two Machines", True },
2917 { "menuMode.Machine Match", True },
2918 { "menuEngine.Retract Move", True },
2924 SetMenuEnables(icsEnables);
2927 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2928 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2935 SetMenuEnables(ncpEnables);
2941 SetMenuEnables(gnuEnables);
2947 SetMenuEnables(cmailEnables);
2953 SetMenuEnables(trainingOnEnables);
2954 if (appData.showButtonBar) {
2955 XtSetSensitive(buttonBarWidget, False);
2961 SetTrainingModeOff()
2963 SetMenuEnables(trainingOffEnables);
2964 if (appData.showButtonBar) {
2965 XtSetSensitive(buttonBarWidget, True);
2970 SetUserThinkingEnables()
2972 if (appData.noChessProgram) return;
2973 SetMenuEnables(userThinkingEnables);
2977 SetMachineThinkingEnables()
2979 if (appData.noChessProgram) return;
2980 SetMenuEnables(machineThinkingEnables);
2982 case MachinePlaysBlack:
2983 case MachinePlaysWhite:
2984 case TwoMachinesPlay:
2985 XtSetSensitive(XtNameToWidget(menuBarWidget,
2986 ModeToWidgetName(gameMode)), True);
2993 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2994 #define HISTORY_SIZE 64
2995 static char *history[HISTORY_SIZE];
2996 int histIn = 0, histP = 0;
2999 SaveInHistory(char *cmd)
3001 if (history[histIn] != NULL) {
3002 free(history[histIn]);
3003 history[histIn] = NULL;
3005 if (*cmd == NULLCHAR) return;
3006 history[histIn] = StrSave(cmd);
3007 histIn = (histIn + 1) % HISTORY_SIZE;
3008 if (history[histIn] != NULL) {
3009 free(history[histIn]);
3010 history[histIn] = NULL;
3016 PrevInHistory(char *cmd)
3019 if (histP == histIn) {
3020 if (history[histIn] != NULL) free(history[histIn]);
3021 history[histIn] = StrSave(cmd);
3023 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
3024 if (newhp == histIn || history[newhp] == NULL) return NULL;
3026 return history[histP];
3032 if (histP == histIn) return NULL;
3033 histP = (histP + 1) % HISTORY_SIZE;
3034 return history[histP];
3036 // end of borrowed code
3038 #define Abs(n) ((n)<0 ? -(n) : (n))
3041 * Find a font that matches "pattern" that is as close as
3042 * possible to the targetPxlSize. Prefer fonts that are k
3043 * pixels smaller to fonts that are k pixels larger. The
3044 * pattern must be in the X Consortium standard format,
3045 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3046 * The return value should be freed with XtFree when no
3050 FindFont(pattern, targetPxlSize)
3054 char **fonts, *p, *best, *scalable, *scalableTail;
3055 int i, j, nfonts, minerr, err, pxlSize;
3058 char **missing_list;
3060 char *def_string, *base_fnt_lst, strInt[3];
3062 XFontStruct **fnt_list;
3064 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3065 snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
3066 p = strstr(pattern, "--");
3067 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3068 strcat(base_fnt_lst, strInt);
3069 strcat(base_fnt_lst, strchr(p + 2, '-'));
3071 if ((fntSet = XCreateFontSet(xDisplay,
3075 &def_string)) == NULL) {
3077 fprintf(stderr, _("Unable to create font set.\n"));
3081 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3083 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3085 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3086 programName, pattern);
3094 for (i=0; i<nfonts; i++) {
3097 if (*p != '-') continue;
3099 if (*p == NULLCHAR) break;
3100 if (*p++ == '-') j++;
3102 if (j < 7) continue;
3105 scalable = fonts[i];
3108 err = pxlSize - targetPxlSize;
3109 if (Abs(err) < Abs(minerr) ||
3110 (minerr > 0 && err < 0 && -err == minerr)) {
3116 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3117 /* If the error is too big and there is a scalable font,
3118 use the scalable font. */
3119 int headlen = scalableTail - scalable;
3120 p = (char *) XtMalloc(strlen(scalable) + 10);
3121 while (isdigit(*scalableTail)) scalableTail++;
3122 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3124 p = (char *) XtMalloc(strlen(best) + 2);
3125 safeStrCpy(p, best, strlen(best)+1 );
3127 if (appData.debugMode) {
3128 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3129 pattern, targetPxlSize, p);
3132 if (missing_count > 0)
3133 XFreeStringList(missing_list);
3134 XFreeFontSet(xDisplay, fntSet);
3136 XFreeFontNames(fonts);
3142 { // [HGM] deletes GCs that are to be remade, to prevent resource leak;
3143 // must be called before all non-first callse to CreateGCs()
3144 XtReleaseGC(shellWidget, highlineGC);
3145 XtReleaseGC(shellWidget, lightSquareGC);
3146 XtReleaseGC(shellWidget, darkSquareGC);
3147 XtReleaseGC(shellWidget, lineGC);
3148 if (appData.monoMode) {
3149 if (DefaultDepth(xDisplay, xScreen) == 1) {
3150 XtReleaseGC(shellWidget, wbPieceGC);
3152 XtReleaseGC(shellWidget, bwPieceGC);
3155 XtReleaseGC(shellWidget, prelineGC);
3156 XtReleaseGC(shellWidget, jailSquareGC);
3157 XtReleaseGC(shellWidget, wdPieceGC);
3158 XtReleaseGC(shellWidget, wlPieceGC);
3159 XtReleaseGC(shellWidget, wjPieceGC);
3160 XtReleaseGC(shellWidget, bdPieceGC);
3161 XtReleaseGC(shellWidget, blPieceGC);
3162 XtReleaseGC(shellWidget, bjPieceGC);
3166 void CreateGCs(int redo)
3168 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3169 | GCBackground | GCFunction | GCPlaneMask;
3170 XGCValues gc_values;
3173 gc_values.plane_mask = AllPlanes;
3174 gc_values.line_width = lineGap;
3175 gc_values.line_style = LineSolid;
3176 gc_values.function = GXcopy;
3179 DeleteGCs(); // called a second time; clean up old GCs first
3180 } else { // [HGM] grid and font GCs created on first call only
3181 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3182 gc_values.background = XWhitePixel(xDisplay, xScreen);
3183 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3184 XSetFont(xDisplay, coordGC, coordFontID);
3186 // [HGM] make font for holdings counts (white on black)
3187 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3188 gc_values.background = XBlackPixel(xDisplay, xScreen);
3189 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3190 XSetFont(xDisplay, countGC, countFontID);
3192 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3193 gc_values.background = XBlackPixel(xDisplay, xScreen);
3194 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3196 if (appData.monoMode) {
3197 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3198 gc_values.background = XWhitePixel(xDisplay, xScreen);
3199 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3201 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3202 gc_values.background = XBlackPixel(xDisplay, xScreen);
3203 lightSquareGC = wbPieceGC
3204 = XtGetGC(shellWidget, value_mask, &gc_values);
3206 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3207 gc_values.background = XWhitePixel(xDisplay, xScreen);
3208 darkSquareGC = bwPieceGC
3209 = XtGetGC(shellWidget, value_mask, &gc_values);
3211 if (DefaultDepth(xDisplay, xScreen) == 1) {
3212 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3213 gc_values.function = GXcopyInverted;
3214 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3215 gc_values.function = GXcopy;
3216 if (XBlackPixel(xDisplay, xScreen) == 1) {
3217 bwPieceGC = darkSquareGC;
3218 wbPieceGC = copyInvertedGC;
3220 bwPieceGC = copyInvertedGC;
3221 wbPieceGC = lightSquareGC;
3225 gc_values.foreground = highlightSquareColor;
3226 gc_values.background = highlightSquareColor;
3227 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3229 gc_values.foreground = premoveHighlightColor;
3230 gc_values.background = premoveHighlightColor;
3231 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3233 gc_values.foreground = lightSquareColor;
3234 gc_values.background = darkSquareColor;
3235 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3237 gc_values.foreground = darkSquareColor;
3238 gc_values.background = lightSquareColor;
3239 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3241 gc_values.foreground = jailSquareColor;
3242 gc_values.background = jailSquareColor;
3243 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3245 gc_values.foreground = whitePieceColor;
3246 gc_values.background = darkSquareColor;
3247 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3249 gc_values.foreground = whitePieceColor;
3250 gc_values.background = lightSquareColor;
3251 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3253 gc_values.foreground = whitePieceColor;
3254 gc_values.background = jailSquareColor;
3255 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3257 gc_values.foreground = blackPieceColor;
3258 gc_values.background = darkSquareColor;
3259 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3261 gc_values.foreground = blackPieceColor;
3262 gc_values.background = lightSquareColor;
3263 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3265 gc_values.foreground = blackPieceColor;
3266 gc_values.background = jailSquareColor;
3267 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3271 void loadXIM(xim, xmask, filename, dest, mask)
3284 fp = fopen(filename, "rb");
3286 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3293 for (y=0; y<h; ++y) {
3294 for (x=0; x<h; ++x) {
3299 XPutPixel(xim, x, y, blackPieceColor);
3301 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3304 XPutPixel(xim, x, y, darkSquareColor);
3306 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3309 XPutPixel(xim, x, y, whitePieceColor);
3311 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3314 XPutPixel(xim, x, y, lightSquareColor);
3316 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3324 /* create Pixmap of piece */
3325 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3327 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3330 /* create Pixmap of clipmask
3331 Note: We assume the white/black pieces have the same
3332 outline, so we make only 6 masks. This is okay
3333 since the XPM clipmask routines do the same. */
3335 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3337 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3340 /* now create the 1-bit version */
3341 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3344 values.foreground = 1;
3345 values.background = 0;
3347 /* Don't use XtGetGC, not read only */
3348 maskGC = XCreateGC(xDisplay, *mask,
3349 GCForeground | GCBackground, &values);
3350 XCopyPlane(xDisplay, temp, *mask, maskGC,
3351 0, 0, squareSize, squareSize, 0, 0, 1);
3352 XFreePixmap(xDisplay, temp);
3357 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3359 void CreateXIMPieces()
3364 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3369 /* The XSynchronize calls were copied from CreatePieces.
3370 Not sure if needed, but can't hurt */
3371 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3374 /* temp needed by loadXIM() */
3375 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3376 0, 0, ss, ss, AllPlanes, XYPixmap);
3378 if (strlen(appData.pixmapDirectory) == 0) {
3382 if (appData.monoMode) {
3383 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3387 fprintf(stderr, _("\nLoading XIMs...\n"));
3389 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3390 fprintf(stderr, "%d", piece+1);
3391 for (kind=0; kind<4; kind++) {
3392 fprintf(stderr, ".");
3393 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3394 ExpandPathName(appData.pixmapDirectory),
3395 piece <= (int) WhiteKing ? "" : "w",
3396 pieceBitmapNames[piece],
3398 ximPieceBitmap[kind][piece] =
3399 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3400 0, 0, ss, ss, AllPlanes, XYPixmap);
3401 if (appData.debugMode)
3402 fprintf(stderr, _("(File:%s:) "), buf);
3403 loadXIM(ximPieceBitmap[kind][piece],
3405 &(xpmPieceBitmap2[kind][piece]),
3406 &(ximMaskPm2[piece]));
3407 if(piece <= (int)WhiteKing)
3408 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3410 fprintf(stderr," ");
3412 /* Load light and dark squares */
3413 /* If the LSQ and DSQ pieces don't exist, we will
3414 draw them with solid squares. */
3415 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3416 if (access(buf, 0) != 0) {
3420 fprintf(stderr, _("light square "));
3422 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3423 0, 0, ss, ss, AllPlanes, XYPixmap);
3424 if (appData.debugMode)
3425 fprintf(stderr, _("(File:%s:) "), buf);
3427 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3428 fprintf(stderr, _("dark square "));
3429 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3430 ExpandPathName(appData.pixmapDirectory), ss);
3431 if (appData.debugMode)
3432 fprintf(stderr, _("(File:%s:) "), buf);
3434 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3435 0, 0, ss, ss, AllPlanes, XYPixmap);
3436 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3437 xpmJailSquare = xpmLightSquare;
3439 fprintf(stderr, _("Done.\n"));
3441 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3444 static VariantClass oldVariant = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
3447 void CreateXPMBoard(char *s, int kind)
3451 if(s == NULL || *s == 0 || *s == '*') { useTexture &= ~(kind+1); return; }
3452 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3453 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3457 void FreeXPMPieces()
3458 { // [HGM] to prevent resoucre leak on calling CreaeXPMPieces() a second time,
3459 // thisroutine has to be called t free the old piece pixmaps
3461 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++)
3462 for (kind=0; kind<4; kind++) XFreePixmap(xDisplay, xpmPieceBitmap2[kind][piece]);
3464 XFreePixmap(xDisplay, xpmLightSquare);
3465 XFreePixmap(xDisplay, xpmDarkSquare);
3469 void CreateXPMPieces()
3473 u_int ss = squareSize;
3475 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3476 XpmColorSymbol symbols[4];
3477 static int redo = False;
3479 if(redo) FreeXPMPieces(); else redo = 1;
3481 /* The XSynchronize calls were copied from CreatePieces.
3482 Not sure if needed, but can't hurt */
3483 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3485 /* Setup translations so piece colors match square colors */
3486 symbols[0].name = "light_piece";
3487 symbols[0].value = appData.whitePieceColor;
3488 symbols[1].name = "dark_piece";
3489 symbols[1].value = appData.blackPieceColor;
3490 symbols[2].name = "light_square";
3491 symbols[2].value = appData.lightSquareColor;
3492 symbols[3].name = "dark_square";
3493 symbols[3].value = appData.darkSquareColor;
3495 attr.valuemask = XpmColorSymbols;
3496 attr.colorsymbols = symbols;
3497 attr.numsymbols = 4;
3499 if (appData.monoMode) {
3500 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3504 if (strlen(appData.pixmapDirectory) == 0) {
3505 XpmPieces* pieces = builtInXpms;
3508 while (pieces->size != squareSize && pieces->size) pieces++;
3509 if (!pieces->size) {
3510 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3513 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3514 for (kind=0; kind<4; kind++) {
3516 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3517 pieces->xpm[piece][kind],
3518 &(xpmPieceBitmap2[kind][piece]),
3519 NULL, &attr)) != 0) {
3520 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3524 if(piece <= (int) WhiteKing)
3525 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3529 xpmJailSquare = xpmLightSquare;
3533 fprintf(stderr, _("\nLoading XPMs...\n"));
3536 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3537 fprintf(stderr, "%d ", piece+1);
3538 for (kind=0; kind<4; kind++) {
3539 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3540 ExpandPathName(appData.pixmapDirectory),
3541 piece > (int) WhiteKing ? "w" : "",
3542 pieceBitmapNames[piece],
3544 if (appData.debugMode) {
3545 fprintf(stderr, _("(File:%s:) "), buf);
3547 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3548 &(xpmPieceBitmap2[kind][piece]),
3549 NULL, &attr)) != 0) {
3550 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3551 // [HGM] missing: read of unorthodox piece failed; substitute King.
3552 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3553 ExpandPathName(appData.pixmapDirectory),
3555 if (appData.debugMode) {
3556 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3558 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3559 &(xpmPieceBitmap2[kind][piece]),
3563 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3568 if(piece <= (int) WhiteKing)
3569 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3572 /* Load light and dark squares */
3573 /* If the LSQ and DSQ pieces don't exist, we will
3574 draw them with solid squares. */
3575 fprintf(stderr, _("light square "));
3576 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3577 if (access(buf, 0) != 0) {
3581 if (appData.debugMode)
3582 fprintf(stderr, _("(File:%s:) "), buf);
3584 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3585 &xpmLightSquare, NULL, &attr)) != 0) {
3586 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3589 fprintf(stderr, _("dark square "));
3590 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3591 ExpandPathName(appData.pixmapDirectory), ss);
3592 if (appData.debugMode) {
3593 fprintf(stderr, _("(File:%s:) "), buf);
3595 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3596 &xpmDarkSquare, NULL, &attr)) != 0) {
3597 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3601 xpmJailSquare = xpmLightSquare;
3602 fprintf(stderr, _("Done.\n"));
3604 oldVariant = -1; // kludge to force re-makig of animation masks
3605 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3608 #endif /* HAVE_LIBXPM */
3611 /* No built-in bitmaps */
3616 u_int ss = squareSize;
3618 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3621 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3622 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3623 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3624 pieceBitmapNames[piece],
3625 ss, kind == SOLID ? 's' : 'o');
3626 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3627 if(piece <= (int)WhiteKing)
3628 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3632 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3636 /* With built-in bitmaps */
3639 BuiltInBits* bib = builtInBits;
3642 u_int ss = squareSize;
3644 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3647 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3649 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3650 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3651 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3652 pieceBitmapNames[piece],
3653 ss, kind == SOLID ? 's' : 'o');
3654 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3655 bib->bits[kind][piece], ss, ss);
3656 if(piece <= (int)WhiteKing)
3657 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3661 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3666 void ReadBitmap(pm, name, bits, wreq, hreq)
3669 unsigned char bits[];
3675 char msg[MSG_SIZ], fullname[MSG_SIZ];
3677 if (*appData.bitmapDirectory != NULLCHAR) {
3678 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3679 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3680 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3681 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3682 &w, &h, pm, &x_hot, &y_hot);
3683 fprintf(stderr, "load %s\n", name);
3684 if (errcode != BitmapSuccess) {
3686 case BitmapOpenFailed:
3687 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3689 case BitmapFileInvalid:
3690 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3692 case BitmapNoMemory:
3693 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3697 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3701 fprintf(stderr, _("%s: %s...using built-in\n"),
3703 } else if (w != wreq || h != hreq) {
3705 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3706 programName, fullname, w, h, wreq, hreq);
3712 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3721 if (lineGap == 0) return;
3723 /* [HR] Split this into 2 loops for non-square boards. */
3725 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3726 gridSegments[i].x1 = 0;
3727 gridSegments[i].x2 =
3728 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3729 gridSegments[i].y1 = gridSegments[i].y2
3730 = lineGap / 2 + (i * (squareSize + lineGap));
3733 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3734 gridSegments[j + i].y1 = 0;
3735 gridSegments[j + i].y2 =
3736 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3737 gridSegments[j + i].x1 = gridSegments[j + i].x2
3738 = lineGap / 2 + (j * (squareSize + lineGap));
3742 static void MenuBarSelect(w, addr, index)
3747 XtActionProc proc = (XtActionProc) addr;
3749 (proc)(NULL, NULL, NULL, NULL);
3752 void CreateMenuBarPopup(parent, name, mb)
3762 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3765 XtSetArg(args[j], XtNleftMargin, 20); j++;
3766 XtSetArg(args[j], XtNrightMargin, 20); j++;
3768 while (mi->string != NULL) {
3769 if (strcmp(mi->string, "----") == 0) {
3770 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3773 XtSetArg(args[j], XtNlabel, XtNewString(mi->string));
3774 entry = XtCreateManagedWidget(mi->ref, smeBSBObjectClass,
3776 XtAddCallback(entry, XtNcallback,
3777 (XtCallbackProc) MenuBarSelect,
3778 (caddr_t) mi->proc);
3784 Widget CreateMenuBar(mb)
3788 Widget anchor, menuBar;
3790 char menuName[MSG_SIZ];
3793 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3794 XtSetArg(args[j], XtNvSpace, 0); j++;
3795 XtSetArg(args[j], XtNborderWidth, 0); j++;
3796 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3797 formWidget, args, j);
3799 while (mb->name != NULL) {
3800 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3801 strncat(menuName, mb->ref, MSG_SIZ - strlen(menuName) - 1);
3803 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3806 shortName[0] = mb->name[0];
3807 shortName[1] = NULLCHAR;
3808 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3811 XtSetArg(args[j], XtNlabel, XtNewString(mb->name)); j++;
3814 XtSetArg(args[j], XtNborderWidth, 0); j++;
3815 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3817 CreateMenuBarPopup(menuBar, menuName, mb);
3823 Widget CreateButtonBar(mi)
3827 Widget button, buttonBar;
3831 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3833 XtSetArg(args[j], XtNhSpace, 0); j++;
3835 XtSetArg(args[j], XtNborderWidth, 0); j++;
3836 XtSetArg(args[j], XtNvSpace, 0); j++;
3837 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3838 formWidget, args, j);
3840 while (mi->string != NULL) {
3843 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3844 XtSetArg(args[j], XtNborderWidth, 0); j++;
3846 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3847 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3848 buttonBar, args, j);
3849 XtAddCallback(button, XtNcallback,
3850 (XtCallbackProc) MenuBarSelect,
3851 (caddr_t) mi->proc);
3858 CreatePieceMenu(name, color)
3865 ChessSquare selection;
3867 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3868 boardWidget, args, 0);
3870 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3871 String item = pieceMenuStrings[color][i];
3873 if (strcmp(item, "----") == 0) {
3874 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3877 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3878 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3880 selection = pieceMenuTranslation[color][i];
3881 XtAddCallback(entry, XtNcallback,
3882 (XtCallbackProc) PieceMenuSelect,
3883 (caddr_t) selection);
3884 if (selection == WhitePawn || selection == BlackPawn) {
3885 XtSetArg(args[0], XtNpopupOnEntry, entry);
3886 XtSetValues(menu, args, 1);
3899 ChessSquare selection;
3901 whitePieceMenu = CreatePieceMenu("menuW", 0);
3902 blackPieceMenu = CreatePieceMenu("menuB", 1);
3904 XtRegisterGrabAction(PieceMenuPopup, True,
3905 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3906 GrabModeAsync, GrabModeAsync);
3908 XtSetArg(args[0], XtNlabel, _("Drop"));
3909 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3910 boardWidget, args, 1);
3911 for (i = 0; i < DROP_MENU_SIZE; i++) {
3912 String item = dropMenuStrings[i];
3914 if (strcmp(item, "----") == 0) {
3915 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3918 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3919 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3921 selection = dropMenuTranslation[i];
3922 XtAddCallback(entry, XtNcallback,
3923 (XtCallbackProc) DropMenuSelect,
3924 (caddr_t) selection);
3929 void SetupDropMenu()
3937 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3938 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3939 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3940 dmEnables[i].piece);
3941 XtSetSensitive(entry, p != NULL || !appData.testLegality
3942 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3943 && !appData.icsActive));
3945 while (p && *p++ == dmEnables[i].piece) count++;
3946 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3948 XtSetArg(args[j], XtNlabel, label); j++;
3949 XtSetValues(entry, args, j);
3953 void PieceMenuPopup(w, event, params, num_params)
3957 Cardinal *num_params;
3959 String whichMenu; int menuNr;
3960 if (event->type == ButtonRelease)
3961 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3962 else if (event->type == ButtonPress)
3963 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3965 case 0: whichMenu = params[0]; break;
3966 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3968 case -1: if (errorUp) ErrorPopDown();
3971 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3974 static void PieceMenuSelect(w, piece, junk)
3979 if (pmFromX < 0 || pmFromY < 0) return;
3980 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3983 static void DropMenuSelect(w, piece, junk)
3988 if (pmFromX < 0 || pmFromY < 0) return;
3989 DropMenuEvent(piece, pmFromX, pmFromY);
3992 void WhiteClock(w, event, prms, nprms)
4001 void BlackClock(w, event, prms, nprms)
4012 * If the user selects on a border boundary, return -1; if off the board,
4013 * return -2. Otherwise map the event coordinate to the square.
4015 int EventToSquare(x, limit)
4023 if ((x % (squareSize + lineGap)) >= squareSize)
4025 x /= (squareSize + lineGap);
4031 static void do_flash_delay(msec)
4037 static void drawHighlight(file, rank, gc)
4043 if (lineGap == 0) return;
4046 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
4047 (squareSize + lineGap);
4048 y = lineGap/2 + rank * (squareSize + lineGap);
4050 x = lineGap/2 + file * (squareSize + lineGap);
4051 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
4052 (squareSize + lineGap);
4055 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
4056 squareSize+lineGap, squareSize+lineGap);
4059 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
4060 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4063 SetHighlights(fromX, fromY, toX, toY)
4064 int fromX, fromY, toX, toY;
4066 if (hi1X != fromX || hi1Y != fromY) {
4067 if (hi1X >= 0 && hi1Y >= 0) {
4068 drawHighlight(hi1X, hi1Y, lineGC);
4070 } // [HGM] first erase both, then draw new!
4071 if (hi2X != toX || hi2Y != toY) {
4072 if (hi2X >= 0 && hi2Y >= 0) {
4073 drawHighlight(hi2X, hi2Y, lineGC);
4076 if (hi1X != fromX || hi1Y != fromY) {
4077 if (fromX >= 0 && fromY >= 0) {
4078 drawHighlight(fromX, fromY, highlineGC);
4081 if (hi2X != toX || hi2Y != toY) {
4082 if (toX >= 0 && toY >= 0) {
4083 drawHighlight(toX, toY, highlineGC);
4095 SetHighlights(-1, -1, -1, -1);
4100 SetPremoveHighlights(fromX, fromY, toX, toY)
4101 int fromX, fromY, toX, toY;
4103 if (pm1X != fromX || pm1Y != fromY) {
4104 if (pm1X >= 0 && pm1Y >= 0) {
4105 drawHighlight(pm1X, pm1Y, lineGC);
4107 if (fromX >= 0 && fromY >= 0) {
4108 drawHighlight(fromX, fromY, prelineGC);
4111 if (pm2X != toX || pm2Y != toY) {
4112 if (pm2X >= 0 && pm2Y >= 0) {
4113 drawHighlight(pm2X, pm2Y, lineGC);
4115 if (toX >= 0 && toY >= 0) {
4116 drawHighlight(toX, toY, prelineGC);
4126 ClearPremoveHighlights()
4128 SetPremoveHighlights(-1, -1, -1, -1);
4131 static int CutOutSquare(x, y, x0, y0, kind)
4132 int x, y, *x0, *y0, kind;
4134 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
4135 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
4137 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
4138 if(textureW[kind] < W*squareSize)
4139 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
4141 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
4142 if(textureH[kind] < H*squareSize)
4143 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
4145 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
4149 static void BlankSquare(x, y, color, piece, dest, fac)
4150 int x, y, color, fac;
4153 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
4155 if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
4156 XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
4157 squareSize, squareSize, x*fac, y*fac);
4159 if (useImages && useImageSqs) {
4163 pm = xpmLightSquare;
4168 case 2: /* neutral */
4173 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4174 squareSize, squareSize, x*fac, y*fac);
4184 case 2: /* neutral */
4189 XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
4194 I split out the routines to draw a piece so that I could
4195 make a generic flash routine.
4197 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4199 int square_color, x, y;
4202 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4203 switch (square_color) {
4205 case 2: /* neutral */
4207 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4208 ? *pieceToOutline(piece)
4209 : *pieceToSolid(piece),
4210 dest, bwPieceGC, 0, 0,
4211 squareSize, squareSize, x, y);
4214 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4215 ? *pieceToSolid(piece)
4216 : *pieceToOutline(piece),
4217 dest, wbPieceGC, 0, 0,
4218 squareSize, squareSize, x, y);
4223 static void monoDrawPiece(piece, square_color, x, y, dest)
4225 int square_color, x, y;
4228 switch (square_color) {
4230 case 2: /* neutral */
4232 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4233 ? *pieceToOutline(piece)
4234 : *pieceToSolid(piece),
4235 dest, bwPieceGC, 0, 0,
4236 squareSize, squareSize, x, y, 1);
4239 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4240 ? *pieceToSolid(piece)
4241 : *pieceToOutline(piece),
4242 dest, wbPieceGC, 0, 0,
4243 squareSize, squareSize, x, y, 1);
4248 static void colorDrawPiece(piece, square_color, x, y, dest)
4250 int square_color, x, y;
4253 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4254 switch (square_color) {
4256 XCopyPlane(xDisplay, *pieceToSolid(piece),
4257 dest, (int) piece < (int) BlackPawn
4258 ? wlPieceGC : blPieceGC, 0, 0,
4259 squareSize, squareSize, x, y, 1);
4262 XCopyPlane(xDisplay, *pieceToSolid(piece),
4263 dest, (int) piece < (int) BlackPawn
4264 ? wdPieceGC : bdPieceGC, 0, 0,
4265 squareSize, squareSize, x, y, 1);
4267 case 2: /* neutral */
4269 XCopyPlane(xDisplay, *pieceToSolid(piece),
4270 dest, (int) piece < (int) BlackPawn
4271 ? wjPieceGC : bjPieceGC, 0, 0,
4272 squareSize, squareSize, x, y, 1);
4277 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4279 int square_color, x, y;
4282 int kind, p = piece;
4284 switch (square_color) {
4286 case 2: /* neutral */
4288 if ((int)piece < (int) BlackPawn) {
4296 if ((int)piece < (int) BlackPawn) {
4304 if(appData.upsideDown && flipView) { kind ^= 2; p += p < BlackPawn ? BlackPawn : -BlackPawn; }// swap white and black pieces
4305 if(useTexture & square_color+1) {
4306 BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
4307 XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
4308 XSetClipOrigin(xDisplay, wlPieceGC, x, y);
4309 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);
4310 XSetClipMask(xDisplay, wlPieceGC, None);
4311 XSetClipOrigin(xDisplay, wlPieceGC, 0, 0);
4313 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4314 dest, wlPieceGC, 0, 0,
4315 squareSize, squareSize, x, y);
4318 typedef void (*DrawFunc)();
4320 DrawFunc ChooseDrawFunc()
4322 if (appData.monoMode) {
4323 if (DefaultDepth(xDisplay, xScreen) == 1) {
4324 return monoDrawPiece_1bit;
4326 return monoDrawPiece;
4330 return colorDrawPieceImage;
4332 return colorDrawPiece;
4336 /* [HR] determine square color depending on chess variant. */
4337 static int SquareColor(row, column)
4342 if (gameInfo.variant == VariantXiangqi) {
4343 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4345 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4347 } else if (row <= 4) {
4353 square_color = ((column + row) % 2) == 1;
4356 /* [hgm] holdings: next line makes all holdings squares light */
4357 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4359 return square_color;
4362 void DrawSquare(row, column, piece, do_flash)
4363 int row, column, do_flash;
4366 int square_color, x, y, direction, font_ascent, font_descent;
4369 XCharStruct overall;
4373 /* Calculate delay in milliseconds (2-delays per complete flash) */
4374 flash_delay = 500 / appData.flashRate;
4377 x = lineGap + ((BOARD_WIDTH-1)-column) *
4378 (squareSize + lineGap);
4379 y = lineGap + row * (squareSize + lineGap);
4381 x = lineGap + column * (squareSize + lineGap);
4382 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4383 (squareSize + lineGap);
4386 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4388 square_color = SquareColor(row, column);
4390 if ( // [HGM] holdings: blank out area between board and holdings
4391 column == BOARD_LEFT-1 || column == BOARD_RGHT
4392 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4393 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4394 BlankSquare(x, y, 2, EmptySquare, xBoardWindow, 1);
4396 // [HGM] print piece counts next to holdings
4397 string[1] = NULLCHAR;
4398 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4399 string[0] = '0' + piece;
4400 XTextExtents(countFontStruct, string, 1, &direction,
4401 &font_ascent, &font_descent, &overall);
4402 if (appData.monoMode) {
4403 XDrawImageString(xDisplay, xBoardWindow, countGC,
4404 x + squareSize - overall.width - 2,
4405 y + font_ascent + 1, string, 1);
4407 XDrawString(xDisplay, xBoardWindow, countGC,
4408 x + squareSize - overall.width - 2,
4409 y + font_ascent + 1, string, 1);
4412 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4413 string[0] = '0' + piece;
4414 XTextExtents(countFontStruct, string, 1, &direction,
4415 &font_ascent, &font_descent, &overall);
4416 if (appData.monoMode) {
4417 XDrawImageString(xDisplay, xBoardWindow, countGC,
4418 x + 2, y + font_ascent + 1, string, 1);
4420 XDrawString(xDisplay, xBoardWindow, countGC,
4421 x + 2, y + font_ascent + 1, string, 1);
4425 if (piece == EmptySquare || appData.blindfold) {
4426 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4428 drawfunc = ChooseDrawFunc();
4430 if (do_flash && appData.flashCount > 0) {
4431 for (i=0; i<appData.flashCount; ++i) {
4432 drawfunc(piece, square_color, x, y, xBoardWindow);
4433 XSync(xDisplay, False);
4434 do_flash_delay(flash_delay);
4436 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4437 XSync(xDisplay, False);
4438 do_flash_delay(flash_delay);
4441 drawfunc(piece, square_color, x, y, xBoardWindow);
4445 string[1] = NULLCHAR;
4446 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4447 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4448 string[0] = 'a' + column - BOARD_LEFT;
4449 XTextExtents(coordFontStruct, string, 1, &direction,
4450 &font_ascent, &font_descent, &overall);
4451 if (appData.monoMode) {
4452 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4453 x + squareSize - overall.width - 2,
4454 y + squareSize - font_descent - 1, string, 1);
4456 XDrawString(xDisplay, xBoardWindow, coordGC,
4457 x + squareSize - overall.width - 2,
4458 y + squareSize - font_descent - 1, string, 1);
4461 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4462 string[0] = ONE + row;
4463 XTextExtents(coordFontStruct, string, 1, &direction,
4464 &font_ascent, &font_descent, &overall);
4465 if (appData.monoMode) {
4466 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4467 x + 2, y + font_ascent + 1, string, 1);
4469 XDrawString(xDisplay, xBoardWindow, coordGC,
4470 x + 2, y + font_ascent + 1, string, 1);
4473 if(!partnerUp && marker[row][column]) {
4474 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4475 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4480 /* Why is this needed on some versions of X? */
4481 void EventProc(widget, unused, event)
4486 if (!XtIsRealized(widget))
4489 switch (event->type) {
4491 if (event->xexpose.count > 0) return; /* no clipping is done */
4492 XDrawPosition(widget, True, NULL);
4493 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4494 flipView = !flipView; partnerUp = !partnerUp;
4495 XDrawPosition(widget, True, NULL);
4496 flipView = !flipView; partnerUp = !partnerUp;
4500 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
4507 void DrawPosition(fullRedraw, board)
4508 /*Boolean*/int fullRedraw;
4511 XDrawPosition(boardWidget, fullRedraw, board);
4514 /* Returns 1 if there are "too many" differences between b1 and b2
4515 (i.e. more than 1 move was made) */
4516 static int too_many_diffs(b1, b2)
4522 for (i=0; i<BOARD_HEIGHT; ++i) {
4523 for (j=0; j<BOARD_WIDTH; ++j) {
4524 if (b1[i][j] != b2[i][j]) {
4525 if (++c > 4) /* Castling causes 4 diffs */
4533 /* Matrix describing castling maneuvers */
4534 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4535 static int castling_matrix[4][5] = {
4536 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4537 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4538 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4539 { 7, 7, 4, 5, 6 } /* 0-0, black */
4542 /* Checks whether castling occurred. If it did, *rrow and *rcol
4543 are set to the destination (row,col) of the rook that moved.
4545 Returns 1 if castling occurred, 0 if not.
4547 Note: Only handles a max of 1 castling move, so be sure
4548 to call too_many_diffs() first.
4550 static int check_castle_draw(newb, oldb, rrow, rcol)
4557 /* For each type of castling... */
4558 for (i=0; i<4; ++i) {
4559 r = castling_matrix[i];
4561 /* Check the 4 squares involved in the castling move */
4563 for (j=1; j<=4; ++j) {
4564 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4571 /* All 4 changed, so it must be a castling move */
4580 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4581 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4583 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4586 void DrawSeekBackground( int left, int top, int right, int bottom )
4588 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4591 void DrawSeekText(char *buf, int x, int y)
4593 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4596 void DrawSeekDot(int x, int y, int colorNr)
4598 int square = colorNr & 0x80;
4601 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4603 XFillRectangle(xDisplay, xBoardWindow, color,
4604 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4606 XFillArc(xDisplay, xBoardWindow, color,
4607 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4610 static int damage[2][BOARD_RANKS][BOARD_FILES];
4613 * event handler for redrawing the board
4615 void XDrawPosition(w, repaint, board)
4617 /*Boolean*/int repaint;
4621 static int lastFlipView = 0;
4622 static int lastBoardValid[2] = {0, 0};
4623 static Board lastBoard[2];
4626 int nr = twoBoards*partnerUp;
4628 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4630 if (board == NULL) {
4631 if (!lastBoardValid[nr]) return;
4632 board = lastBoard[nr];
4634 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4635 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4636 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Flip View"),
4641 * It would be simpler to clear the window with XClearWindow()
4642 * but this causes a very distracting flicker.
4645 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4647 if ( lineGap && IsDrawArrowEnabled())
4648 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4649 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4651 /* If too much changes (begin observing new game, etc.), don't
4653 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4655 /* Special check for castling so we don't flash both the king
4656 and the rook (just flash the king). */
4658 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4659 /* Draw rook with NO flashing. King will be drawn flashing later */
4660 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4661 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4665 /* First pass -- Draw (newly) empty squares and repair damage.
4666 This prevents you from having a piece show up twice while it
4667 is flashing on its new square */
4668 for (i = 0; i < BOARD_HEIGHT; i++)
4669 for (j = 0; j < BOARD_WIDTH; j++)
4670 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4671 || damage[nr][i][j]) {
4672 DrawSquare(i, j, board[i][j], 0);
4673 damage[nr][i][j] = False;
4676 /* Second pass -- Draw piece(s) in new position and flash them */
4677 for (i = 0; i < BOARD_HEIGHT; i++)
4678 for (j = 0; j < BOARD_WIDTH; j++)
4679 if (board[i][j] != lastBoard[nr][i][j]) {
4680 DrawSquare(i, j, board[i][j], do_flash);
4684 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4685 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4686 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4688 for (i = 0; i < BOARD_HEIGHT; i++)
4689 for (j = 0; j < BOARD_WIDTH; j++) {
4690 DrawSquare(i, j, board[i][j], 0);
4691 damage[nr][i][j] = False;
4695 CopyBoard(lastBoard[nr], board);
4696 lastBoardValid[nr] = 1;
4697 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4698 lastFlipView = flipView;
4700 /* Draw highlights */
4701 if (pm1X >= 0 && pm1Y >= 0) {
4702 drawHighlight(pm1X, pm1Y, prelineGC);
4704 if (pm2X >= 0 && pm2Y >= 0) {
4705 drawHighlight(pm2X, pm2Y, prelineGC);
4707 if (hi1X >= 0 && hi1Y >= 0) {
4708 drawHighlight(hi1X, hi1Y, highlineGC);
4710 if (hi2X >= 0 && hi2Y >= 0) {
4711 drawHighlight(hi2X, hi2Y, highlineGC);
4713 DrawArrowHighlight(hi1X, hi1Y, hi2X, hi2Y);
4715 /* If piece being dragged around board, must redraw that too */
4718 XSync(xDisplay, False);
4723 * event handler for redrawing the board
4725 void DrawPositionProc(w, event, prms, nprms)
4731 XDrawPosition(w, True, NULL);
4736 * event handler for parsing user moves
4738 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4739 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4740 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4741 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4742 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4743 // and at the end FinishMove() to perform the move after optional promotion popups.
4744 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4745 void HandleUserMove(w, event, prms, nprms)
4751 if (w != boardWidget || errorExitStatus != -1) return;
4752 if(nprms) shiftKey = !strcmp(prms[0], "1");
4755 if (event->type == ButtonPress) {
4756 XtPopdown(promotionShell);
4757 XtDestroyWidget(promotionShell);
4758 promotionUp = False;
4766 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4767 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4768 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4771 void AnimateUserMove (Widget w, XEvent * event,
4772 String * params, Cardinal * nParams)
4774 DragPieceMove(event->xmotion.x, event->xmotion.y);
4777 void HandlePV (Widget w, XEvent * event,
4778 String * params, Cardinal * nParams)
4779 { // [HGM] pv: walk PV
4780 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4783 Widget CommentCreate(name, text, mutable, callback, lines)
4785 int /*Boolean*/ mutable;
4786 XtCallbackProc callback;
4790 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4795 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4796 XtGetValues(boardWidget, args, j);
4799 XtSetArg(args[j], XtNresizable, True); j++;
4802 XtCreatePopupShell(name, topLevelShellWidgetClass,
4803 shellWidget, args, j);
4806 XtCreatePopupShell(name, transientShellWidgetClass,
4807 shellWidget, args, j);
4810 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4811 layoutArgs, XtNumber(layoutArgs));
4813 XtCreateManagedWidget("form", formWidgetClass, layout,
4814 formArgs, XtNumber(formArgs));
4818 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4819 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4821 XtSetArg(args[j], XtNstring, text); j++;
4822 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4823 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4824 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4825 XtSetArg(args[j], XtNright, XtChainRight); j++;
4826 XtSetArg(args[j], XtNresizable, True); j++;
4827 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4828 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4829 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4830 XtSetArg(args[j], XtNautoFill, True); j++;
4831 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4833 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4834 XtOverrideTranslations(edit, XtParseTranslationTable(commentTranslations));
4838 XtSetArg(args[j], XtNfromVert, edit); j++;
4839 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4840 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4841 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4842 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4844 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4845 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4848 XtSetArg(args[j], XtNfromVert, edit); j++;
4849 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4850 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4851 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4852 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4853 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4855 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4856 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4859 XtSetArg(args[j], XtNfromVert, edit); j++;
4860 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4861 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4862 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4863 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4864 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4866 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4867 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4870 XtSetArg(args[j], XtNfromVert, edit); j++;
4871 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4872 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4873 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4874 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4876 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4877 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4880 XtSetArg(args[j], XtNfromVert, edit); j++;
4881 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4882 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4883 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4884 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4885 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4887 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4888 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4891 XtRealizeWidget(shell);
4893 if (commentX == -1) {
4896 Dimension pw_height;
4897 Dimension ew_height;
4900 XtSetArg(args[j], XtNheight, &ew_height); j++;
4901 XtGetValues(edit, args, j);
4904 XtSetArg(args[j], XtNheight, &pw_height); j++;
4905 XtGetValues(shell, args, j);
4906 commentH = pw_height + (lines - 1) * ew_height;
4907 commentW = bw_width - 16;
4909 XSync(xDisplay, False);
4911 /* This code seems to tickle an X bug if it is executed too soon
4912 after xboard starts up. The coordinates get transformed as if
4913 the main window was positioned at (0, 0).
4915 XtTranslateCoords(shellWidget,
4916 (bw_width - commentW) / 2, 0 - commentH / 2,
4917 &commentX, &commentY);
4919 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4920 RootWindowOfScreen(XtScreen(shellWidget)),
4921 (bw_width - commentW) / 2, 0 - commentH / 2,
4926 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4929 if(wpComment.width > 0) {
4930 commentX = wpComment.x;
4931 commentY = wpComment.y;
4932 commentW = wpComment.width;
4933 commentH = wpComment.height;
4937 XtSetArg(args[j], XtNheight, commentH); j++;
4938 XtSetArg(args[j], XtNwidth, commentW); j++;
4939 XtSetArg(args[j], XtNx, commentX); j++;
4940 XtSetArg(args[j], XtNy, commentY); j++;
4941 XtSetValues(shell, args, j);
4942 XtSetKeyboardFocus(shell, edit);
4947 static int savedIndex; /* gross that this is global */
4949 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
4952 XawTextPosition index, dummy;
4955 XawTextGetSelectionPos(w, &index, &dummy);
4956 XtSetArg(arg, XtNstring, &val);
4957 XtGetValues(w, &arg, 1);
4958 ReplaceComment(savedIndex, val);
4959 if(savedIndex != currentMove) ToNrEvent(savedIndex);
4960 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
4963 void EditCommentPopUp(index, title, text)
4972 if (text == NULL) text = "";
4974 if (editShell == NULL) {
4976 CommentCreate(title, text, True, EditCommentCallback, 4);
4977 XtRealizeWidget(editShell);
4978 CatchDeleteWindow(editShell, "EditCommentPopDown");
4980 edit = XtNameToWidget(editShell, "*form.text");
4982 XtSetArg(args[j], XtNstring, text); j++;
4983 XtSetValues(edit, args, j);
4985 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4986 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4987 XtSetValues(editShell, args, j);
4990 XtPopup(editShell, XtGrabNone);
4994 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4995 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"),
4997 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"),
5001 void EditCommentCallback(w, client_data, call_data)
5003 XtPointer client_data, call_data;
5011 XtSetArg(args[j], XtNlabel, &name); j++;
5012 XtGetValues(w, args, j);
5014 if (strcmp(name, _("ok")) == 0) {
5015 edit = XtNameToWidget(editShell, "*form.text");
5017 XtSetArg(args[j], XtNstring, &val); j++;
5018 XtGetValues(edit, args, j);
5019 ReplaceComment(savedIndex, val);
5020 EditCommentPopDown();
5021 } else if (strcmp(name, _("cancel")) == 0) {
5022 EditCommentPopDown();
5023 } else if (strcmp(name, _("clear")) == 0) {
5024 edit = XtNameToWidget(editShell, "*form.text");
5025 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5026 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5030 void EditCommentPopDown()
5035 if (!editUp) return;
5037 XtSetArg(args[j], XtNx, &commentX); j++;
5038 XtSetArg(args[j], XtNy, &commentY); j++;
5039 XtSetArg(args[j], XtNheight, &commentH); j++;
5040 XtSetArg(args[j], XtNwidth, &commentW); j++;
5041 XtGetValues(editShell, args, j);
5042 XtPopdown(editShell);
5045 XtSetArg(args[j], XtNleftBitmap, None); j++;
5046 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"),
5048 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"),
5052 void ICSInputBoxPopUp()
5057 extern Option boxOptions[];
5059 void ICSInputSendText()
5066 edit = boxOptions[0].handle;
5068 XtSetArg(args[j], XtNstring, &val); j++;
5069 XtGetValues(edit, args, j);
5071 SendMultiLineToICS(val);
5072 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5073 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5076 void ICSInputBoxPopDown()
5081 void CommentPopUp(title, text)
5088 savedIndex = currentMove; // [HGM] vari
5089 if (commentShell == NULL) {
5091 CommentCreate(title, text, False, CommentCallback, 4);
5092 XtRealizeWidget(commentShell);
5093 CatchDeleteWindow(commentShell, "CommentPopDown");
5095 edit = XtNameToWidget(commentShell, "*form.text");
5097 XtSetArg(args[j], XtNstring, text); j++;
5098 XtSetValues(edit, args, j);
5100 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5101 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5102 XtSetValues(commentShell, args, j);
5105 XtPopup(commentShell, XtGrabNone);
5106 XSync(xDisplay, False);
5111 void CommentCallback(w, client_data, call_data)
5113 XtPointer client_data, call_data;
5120 XtSetArg(args[j], XtNlabel, &name); j++;
5121 XtGetValues(w, args, j);
5123 if (strcmp(name, _("close")) == 0) {
5125 } else if (strcmp(name, _("edit")) == 0) {
5132 void CommentPopDown()
5137 if (!commentUp) return;
5139 XtSetArg(args[j], XtNx, &commentX); j++;
5140 XtSetArg(args[j], XtNy, &commentY); j++;
5141 XtSetArg(args[j], XtNwidth, &commentW); j++;
5142 XtSetArg(args[j], XtNheight, &commentH); j++;
5143 XtGetValues(commentShell, args, j);
5144 XtPopdown(commentShell);
5145 XSync(xDisplay, False);
5149 void FileNamePopUp(label, def, proc, openMode)
5155 fileProc = proc; /* I can't see a way not */
5156 fileOpenMode = openMode; /* to use globals here */
5157 { // [HGM] use file-selector dialog stolen from Ghostview
5159 int index; // this is not supported yet
5161 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5162 def, openMode, NULL, &name))
5163 (void) (*fileProc)(f, index=0, name);
5167 void FileNamePopDown()
5169 if (!filenameUp) return;
5170 XtPopdown(fileNameShell);
5171 XtDestroyWidget(fileNameShell);
5176 void FileNameCallback(w, client_data, call_data)
5178 XtPointer client_data, call_data;
5183 XtSetArg(args[0], XtNlabel, &name);
5184 XtGetValues(w, args, 1);
5186 if (strcmp(name, _("cancel")) == 0) {
5191 FileNameAction(w, NULL, NULL, NULL);
5194 void FileNameAction(w, event, prms, nprms)
5206 name = XawDialogGetValueString(w = XtParent(w));
5208 if ((name != NULL) && (*name != NULLCHAR)) {
5209 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
5210 XtPopdown(w = XtParent(XtParent(w)));
5214 p = strrchr(buf, ' ');
5221 fullname = ExpandPathName(buf);
5223 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5226 f = fopen(fullname, fileOpenMode);
5228 DisplayError(_("Failed to open file"), errno);
5230 (void) (*fileProc)(f, index, buf);
5237 XtPopdown(w = XtParent(XtParent(w)));
5243 void PromotionPopUp()
5246 Widget dialog, layout;
5248 Dimension bw_width, pw_width;
5252 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5253 XtGetValues(boardWidget, args, j);
5256 XtSetArg(args[j], XtNresizable, True); j++;
5257 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5259 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5260 shellWidget, args, j);
5262 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5263 layoutArgs, XtNumber(layoutArgs));
5266 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5267 XtSetArg(args[j], XtNborderWidth, 0); j++;
5268 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5271 if(gameInfo.variant != VariantShogi) {
5272 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) {
5273 XawDialogAddButton(dialog, _("Warlord"), PromotionCallback,
5274 (XtPointer) dialog);
5275 XawDialogAddButton(dialog, _("General"), PromotionCallback,
5276 (XtPointer) dialog);
5277 XawDialogAddButton(dialog, _("Lieutenant"), PromotionCallback,
5278 (XtPointer) dialog);
5279 XawDialogAddButton(dialog, _("Captain"), PromotionCallback,
5280 (XtPointer) dialog);
5282 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5283 (XtPointer) dialog);
5284 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5285 (XtPointer) dialog);
5286 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5287 (XtPointer) dialog);
5288 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5289 (XtPointer) dialog);
5291 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5292 gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
\r
5293 gameInfo.variant == VariantGiveaway) {
5294 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5295 (XtPointer) dialog);
5297 if(gameInfo.variant == VariantCapablanca ||
5298 gameInfo.variant == VariantGothic ||
5299 gameInfo.variant == VariantCapaRandom) {
5300 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5301 (XtPointer) dialog);
5302 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5303 (XtPointer) dialog);
5305 } else // [HGM] shogi
5307 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5308 (XtPointer) dialog);
5309 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5310 (XtPointer) dialog);
5312 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5313 (XtPointer) dialog);
5315 XtRealizeWidget(promotionShell);
5316 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5319 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5320 XtGetValues(promotionShell, args, j);
5322 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5323 lineGap + squareSize/3 +
5324 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5325 0 : 6*(squareSize + lineGap)), &x, &y);
5328 XtSetArg(args[j], XtNx, x); j++;
5329 XtSetArg(args[j], XtNy, y); j++;
5330 XtSetValues(promotionShell, args, j);
5332 XtPopup(promotionShell, XtGrabNone);
5337 void PromotionPopDown()
5339 if (!promotionUp) return;
5340 XtPopdown(promotionShell);
5341 XtDestroyWidget(promotionShell);
5342 promotionUp = False;
5345 void PromotionCallback(w, client_data, call_data)
5347 XtPointer client_data, call_data;
5353 XtSetArg(args[0], XtNlabel, &name);
5354 XtGetValues(w, args, 1);
5358 if (fromX == -1) return;
5360 if (strcmp(name, _("cancel")) == 0) {
5364 } else if (strcmp(name, _("Knight")) == 0) {
5366 } else if (strcmp(name, _("Promote")) == 0) {
5368 } else if (strcmp(name, _("Defer")) == 0) {
5371 promoChar = ToLower(name[0]);
5374 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5376 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5377 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5382 void ErrorCallback(w, client_data, call_data)
5384 XtPointer client_data, call_data;
5387 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5389 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5395 if (!errorUp) return;
5397 XtPopdown(errorShell);
5398 XtDestroyWidget(errorShell);
5399 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5402 void ErrorPopUp(title, label, modal)
5403 char *title, *label;
5407 Widget dialog, layout;
5411 Dimension bw_width, pw_width;
5412 Dimension pw_height;
5416 XtSetArg(args[i], XtNresizable, True); i++;
5417 XtSetArg(args[i], XtNtitle, title); i++;
5419 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5420 shellWidget, args, i);
5422 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5423 layoutArgs, XtNumber(layoutArgs));
5426 XtSetArg(args[i], XtNlabel, label); i++;
5427 XtSetArg(args[i], XtNborderWidth, 0); i++;
5428 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5431 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5433 XtRealizeWidget(errorShell);
5434 CatchDeleteWindow(errorShell, "ErrorPopDown");
5437 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5438 XtGetValues(boardWidget, args, i);
5440 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5441 XtSetArg(args[i], XtNheight, &pw_height); i++;
5442 XtGetValues(errorShell, args, i);
5445 /* This code seems to tickle an X bug if it is executed too soon
5446 after xboard starts up. The coordinates get transformed as if
5447 the main window was positioned at (0, 0).
5449 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5450 0 - pw_height + squareSize / 3, &x, &y);
5452 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5453 RootWindowOfScreen(XtScreen(boardWidget)),
5454 (bw_width - pw_width) / 2,
5455 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5459 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5462 XtSetArg(args[i], XtNx, x); i++;
5463 XtSetArg(args[i], XtNy, y); i++;
5464 XtSetValues(errorShell, args, i);
5467 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5470 /* Disable all user input other than deleting the window */
5471 static int frozen = 0;
5475 /* Grab by a widget that doesn't accept input */
5476 XtAddGrab(messageWidget, TRUE, FALSE);
5480 /* Undo a FreezeUI */
5483 if (!frozen) return;
5484 XtRemoveGrab(messageWidget);
5488 char *ModeToWidgetName(mode)
5492 case BeginningOfGame:
5493 if (appData.icsActive)
5494 return "menuMode.ICS Client";
5495 else if (appData.noChessProgram ||
5496 *appData.cmailGameName != NULLCHAR)
5497 return "menuMode.Edit Game";
5499 return "menuMode.Machine Black";
5500 case MachinePlaysBlack:
5501 return "menuMode.Machine Black";
5502 case MachinePlaysWhite:
5503 return "menuMode.Machine White";
5505 return "menuMode.Analysis Mode";
5507 return "menuMode.Analyze File";
5508 case TwoMachinesPlay:
5509 return "menuMode.Two Machines";
5511 return "menuMode.Edit Game";
5512 case PlayFromGameFile:
5513 return "menuFile.Load Game";
5515 return "menuMode.Edit Position";
5517 return "menuMode.Training";
5518 case IcsPlayingWhite:
5519 case IcsPlayingBlack:
5523 return "menuMode.ICS Client";
5530 void ModeHighlight()
5533 static int oldPausing = FALSE;
5534 static GameMode oldmode = (GameMode) -1;
5537 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5539 if (pausing != oldPausing) {
5540 oldPausing = pausing;
5542 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5544 XtSetArg(args[0], XtNleftBitmap, None);
5546 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5549 if (appData.showButtonBar) {
5550 /* Always toggle, don't set. Previous code messes up when
5551 invoked while the button is pressed, as releasing it
5552 toggles the state again. */
5555 XtSetArg(args[0], XtNbackground, &oldbg);
5556 XtSetArg(args[1], XtNforeground, &oldfg);
5557 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5559 XtSetArg(args[0], XtNbackground, oldfg);
5560 XtSetArg(args[1], XtNforeground, oldbg);
5562 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5566 wname = ModeToWidgetName(oldmode);
5567 if (wname != NULL) {
5568 XtSetArg(args[0], XtNleftBitmap, None);
5569 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5571 wname = ModeToWidgetName(gameMode);
5572 if (wname != NULL) {
5573 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5574 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5578 /* Maybe all the enables should be handled here, not just this one */
5579 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5580 gameMode == Training || gameMode == PlayFromGameFile);
5585 * Button/menu procedures
5587 void ResetProc(w, event, prms, nprms)
5596 int LoadGamePopUp(f, gameNumber, title)
5601 cmailMsgLoaded = FALSE;
5602 if (gameNumber == 0) {
5603 int error = GameListBuild(f);
5605 DisplayError(_("Cannot build game list"), error);
5606 } else if (!ListEmpty(&gameList) &&
5607 ((ListGame *) gameList.tailPred)->number > 1) {
5608 GameListPopUp(f, title);
5614 return LoadGame(f, gameNumber, title, FALSE);
5617 void LoadGameProc(w, event, prms, nprms)
5623 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5626 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5629 void LoadNextGameProc(w, event, prms, nprms)
5638 void LoadPrevGameProc(w, event, prms, nprms)
5647 void ReloadGameProc(w, event, prms, nprms)
5656 void LoadNextPositionProc(w, event, prms, nprms)
5665 void LoadPrevPositionProc(w, event, prms, nprms)
5674 void ReloadPositionProc(w, event, prms, nprms)
5683 void LoadPositionProc(w, event, prms, nprms)
5689 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5692 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5695 void SaveGameProc(w, event, prms, nprms)
5701 FileNamePopUp(_("Save game file name?"),
5702 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5706 void SavePositionProc(w, event, prms, nprms)
5712 FileNamePopUp(_("Save position file name?"),
5713 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5717 void ReloadCmailMsgProc(w, event, prms, nprms)
5723 ReloadCmailMsgEvent(FALSE);
5726 void MailMoveProc(w, event, prms, nprms)
5735 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5736 char *selected_fen_position=NULL;
5739 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5740 Atom *type_return, XtPointer *value_return,
5741 unsigned long *length_return, int *format_return)
5743 char *selection_tmp;
5745 if (!selected_fen_position) return False; /* should never happen */
5746 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5747 /* note: since no XtSelectionDoneProc was registered, Xt will
5748 * automatically call XtFree on the value returned. So have to
5749 * make a copy of it allocated with XtMalloc */
5750 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5751 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
5753 *value_return=selection_tmp;
5754 *length_return=strlen(selection_tmp);
5755 *type_return=*target;
5756 *format_return = 8; /* bits per byte */
5758 } else if (*target == XA_TARGETS(xDisplay)) {
5759 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5760 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5761 targets_tmp[1] = XA_STRING;
5762 *value_return = targets_tmp;
5763 *type_return = XA_ATOM;
5765 *format_return = 8 * sizeof(Atom);
5766 if (*format_return > 32) {
5767 *length_return *= *format_return / 32;
5768 *format_return = 32;
5776 /* note: when called from menu all parameters are NULL, so no clue what the
5777 * Widget which was clicked on was, or what the click event was
5779 void CopyPositionProc(w, event, prms, nprms)
5786 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5787 * have a notion of a position that is selected but not copied.
5788 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5790 if(gameMode == EditPosition) EditPositionDone(TRUE);
5791 if (selected_fen_position) free(selected_fen_position);
5792 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5793 if (!selected_fen_position) return;
5794 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5796 SendPositionSelection,
5797 NULL/* lose_ownership_proc */ ,
5798 NULL/* transfer_done_proc */);
5799 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5801 SendPositionSelection,
5802 NULL/* lose_ownership_proc */ ,
5803 NULL/* transfer_done_proc */);
5806 /* function called when the data to Paste is ready */
5808 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5809 Atom *type, XtPointer value, unsigned long *len, int *format)
5812 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5813 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5814 EditPositionPasteFEN(fenstr);
5818 /* called when Paste Position button is pressed,
5819 * all parameters will be NULL */
5820 void PastePositionProc(w, event, prms, nprms)
5826 XtGetSelectionValue(menuBarWidget,
5827 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5828 /* (XtSelectionCallbackProc) */ PastePositionCB,
5829 NULL, /* client_data passed to PastePositionCB */
5831 /* better to use the time field from the event that triggered the
5832 * call to this function, but that isn't trivial to get
5840 SendGameSelection(Widget w, Atom *selection, Atom *target,
5841 Atom *type_return, XtPointer *value_return,
5842 unsigned long *length_return, int *format_return)
5844 char *selection_tmp;
5846 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5847 FILE* f = fopen(gameCopyFilename, "r");
5850 if (f == NULL) return False;
5854 selection_tmp = XtMalloc(len + 1);
5855 count = fread(selection_tmp, 1, len, f);
5858 XtFree(selection_tmp);
5861 selection_tmp[len] = NULLCHAR;
5862 *value_return = selection_tmp;
5863 *length_return = len;
5864 *type_return = *target;
5865 *format_return = 8; /* bits per byte */
5867 } else if (*target == XA_TARGETS(xDisplay)) {
5868 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5869 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5870 targets_tmp[1] = XA_STRING;
5871 *value_return = targets_tmp;
5872 *type_return = XA_ATOM;
5874 *format_return = 8 * sizeof(Atom);
5875 if (*format_return > 32) {
5876 *length_return *= *format_return / 32;
5877 *format_return = 32;
5885 /* note: when called from menu all parameters are NULL, so no clue what the
5886 * Widget which was clicked on was, or what the click event was
5888 void CopyGameProc(w, event, prms, nprms)
5896 ret = SaveGameToFile(gameCopyFilename, FALSE);
5900 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5901 * have a notion of a game that is selected but not copied.
5902 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5904 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5907 NULL/* lose_ownership_proc */ ,
5908 NULL/* transfer_done_proc */);
5909 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5912 NULL/* lose_ownership_proc */ ,
5913 NULL/* transfer_done_proc */);
5916 /* function called when the data to Paste is ready */
5918 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5919 Atom *type, XtPointer value, unsigned long *len, int *format)
5922 if (value == NULL || *len == 0) {
5923 return; /* nothing had been selected to copy */
5925 f = fopen(gamePasteFilename, "w");
5927 DisplayError(_("Can't open temp file"), errno);
5930 fwrite(value, 1, *len, f);
5933 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5936 /* called when Paste Game button is pressed,
5937 * all parameters will be NULL */
5938 void PasteGameProc(w, event, prms, nprms)
5944 XtGetSelectionValue(menuBarWidget,
5945 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5946 /* (XtSelectionCallbackProc) */ PasteGameCB,
5947 NULL, /* client_data passed to PasteGameCB */
5949 /* better to use the time field from the event that triggered the
5950 * call to this function, but that isn't trivial to get
5960 SaveGameProc(NULL, NULL, NULL, NULL);
5964 void QuitProc(w, event, prms, nprms)
5973 void PauseProc(w, event, prms, nprms)
5983 void MachineBlackProc(w, event, prms, nprms)
5989 MachineBlackEvent();
5992 void MachineWhiteProc(w, event, prms, nprms)
5998 MachineWhiteEvent();
6001 void AnalyzeModeProc(w, event, prms, nprms)
6009 if (!first.analysisSupport) {
6010 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6011 DisplayError(buf, 0);
6014 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
6015 if (appData.icsActive) {
6016 if (gameMode != IcsObserving) {
6017 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
6018 DisplayError(buf, 0);
6020 if (appData.icsEngineAnalyze) {
6021 if (appData.debugMode)
6022 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
6028 /* if enable, use want disable icsEngineAnalyze */
6029 if (appData.icsEngineAnalyze) {
6034 appData.icsEngineAnalyze = TRUE;
6035 if (appData.debugMode)
6036 fprintf(debugFP, _("ICS engine analyze starting... \n"));
6038 #ifndef OPTIONSDIALOG
6039 if (!appData.showThinking)
6040 ShowThinkingProc(w,event,prms,nprms);
6046 void AnalyzeFileProc(w, event, prms, nprms)
6052 if (!first.analysisSupport) {
6054 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6055 DisplayError(buf, 0);
6059 #ifndef OPTIONSDIALOG
6060 if (!appData.showThinking)
6061 ShowThinkingProc(w,event,prms,nprms);
6064 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
6065 AnalysisPeriodicEvent(1);
6068 void TwoMachinesProc(w, event, prms, nprms)
6077 void MatchProc(w, event, prms, nprms)
6083 if(gameMode != BeginningOfGame) { DisplayError(_("You can only start a match from the initial position."), 0); return; }
6084 matchMode = 2; // This is back-end, really
\r
6085 appData.matchGames = appData.defaultMatchGames;
\r
6087 first.matchWins = second.matchWins = 0;
\r
6091 void IcsClientProc(w, event, prms, nprms)
6100 void EditGameProc(w, event, prms, nprms)
6109 void EditPositionProc(w, event, prms, nprms)
6115 EditPositionEvent();
6118 void TrainingProc(w, event, prms, nprms)
6127 void EditCommentProc(w, event, prms, nprms)
6134 EditCommentPopDown();
6140 void IcsInputBoxProc(w, event, prms, nprms)
6146 if (!PopDown(4)) ICSInputBoxPopUp();
6149 void AcceptProc(w, event, prms, nprms)
6158 void DeclineProc(w, event, prms, nprms)
6167 void RematchProc(w, event, prms, nprms)
6176 void CallFlagProc(w, event, prms, nprms)
6185 void DrawProc(w, event, prms, nprms)
6194 void AbortProc(w, event, prms, nprms)
6203 void AdjournProc(w, event, prms, nprms)
6212 void ResignProc(w, event, prms, nprms)
6221 void AdjuWhiteProc(w, event, prms, nprms)
6227 UserAdjudicationEvent(+1);
6230 void AdjuBlackProc(w, event, prms, nprms)
6236 UserAdjudicationEvent(-1);
6239 void AdjuDrawProc(w, event, prms, nprms)
6245 UserAdjudicationEvent(0);
6248 void EnterKeyProc(w, event, prms, nprms)
6254 if (shellUp[4] == True)
6258 void UpKeyProc(w, event, prms, nprms)
6263 { // [HGM] input: let up-arrow recall previous line from history
6270 if (!shellUp[4]) return;
6271 edit = boxOptions[0].handle;
6273 XtSetArg(args[j], XtNstring, &val); j++;
6274 XtGetValues(edit, args, j);
6275 val = PrevInHistory(val);
6276 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6277 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6279 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6280 XawTextReplace(edit, 0, 0, &t);
6281 XawTextSetInsertionPoint(edit, 9999);
6285 void DownKeyProc(w, event, prms, nprms)
6290 { // [HGM] input: let down-arrow recall next line from history
6295 if (!shellUp[4]) return;
6296 edit = boxOptions[0].handle;
6297 val = NextInHistory();
6298 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6299 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6301 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6302 XawTextReplace(edit, 0, 0, &t);
6303 XawTextSetInsertionPoint(edit, 9999);
6307 void StopObservingProc(w, event, prms, nprms)
6313 StopObservingEvent();
6316 void StopExaminingProc(w, event, prms, nprms)
6322 StopExaminingEvent();
6325 void UploadProc(w, event, prms, nprms)
6335 void ForwardProc(w, event, prms, nprms)
6345 void BackwardProc(w, event, prms, nprms)
6354 void ToStartProc(w, event, prms, nprms)
6363 void ToEndProc(w, event, prms, nprms)
6372 void RevertProc(w, event, prms, nprms)
6381 void AnnotateProc(w, event, prms, nprms)
6390 void TruncateGameProc(w, event, prms, nprms)
6396 TruncateGameEvent();
6398 void RetractMoveProc(w, event, prms, nprms)
6407 void MoveNowProc(w, event, prms, nprms)
6416 void FlipViewProc(w, event, prms, nprms)
6422 flipView = !flipView;
6423 DrawPosition(True, NULL);
6426 void PonderNextMoveProc(w, event, prms, nprms)
6434 PonderNextMoveEvent(!appData.ponderNextMove);
6435 #ifndef OPTIONSDIALOG
6436 if (appData.ponderNextMove) {
6437 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6439 XtSetArg(args[0], XtNleftBitmap, None);
6441 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6446 #ifndef OPTIONSDIALOG
6447 void AlwaysQueenProc(w, event, prms, nprms)
6455 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6457 if (appData.alwaysPromoteToQueen) {
6458 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6460 XtSetArg(args[0], XtNleftBitmap, None);
6462 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6466 void AnimateDraggingProc(w, event, prms, nprms)
6474 appData.animateDragging = !appData.animateDragging;
6476 if (appData.animateDragging) {
6477 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6480 XtSetArg(args[0], XtNleftBitmap, None);
6482 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6486 void AnimateMovingProc(w, event, prms, nprms)
6494 appData.animate = !appData.animate;
6496 if (appData.animate) {
6497 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6500 XtSetArg(args[0], XtNleftBitmap, None);
6502 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6506 void AutoflagProc(w, event, prms, nprms)
6514 appData.autoCallFlag = !appData.autoCallFlag;
6516 if (appData.autoCallFlag) {
6517 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6519 XtSetArg(args[0], XtNleftBitmap, None);
6521 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6525 void AutoflipProc(w, event, prms, nprms)
6533 appData.autoFlipView = !appData.autoFlipView;
6535 if (appData.autoFlipView) {
6536 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6538 XtSetArg(args[0], XtNleftBitmap, None);
6540 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6544 void BlindfoldProc(w, event, prms, nprms)
6552 appData.blindfold = !appData.blindfold;
6554 if (appData.blindfold) {
6555 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6557 XtSetArg(args[0], XtNleftBitmap, None);
6559 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6562 DrawPosition(True, NULL);
6565 void TestLegalityProc(w, event, prms, nprms)
6573 appData.testLegality = !appData.testLegality;
6575 if (appData.testLegality) {
6576 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6578 XtSetArg(args[0], XtNleftBitmap, None);
6580 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6585 void FlashMovesProc(w, event, prms, nprms)
6593 if (appData.flashCount == 0) {
6594 appData.flashCount = 3;
6596 appData.flashCount = -appData.flashCount;
6599 if (appData.flashCount > 0) {
6600 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6602 XtSetArg(args[0], XtNleftBitmap, None);
6604 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6609 void HighlightDraggingProc(w, event, prms, nprms)
6617 appData.highlightDragging = !appData.highlightDragging;
6619 if (appData.highlightDragging) {
6620 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6622 XtSetArg(args[0], XtNleftBitmap, None);
6624 XtSetValues(XtNameToWidget(menuBarWidget,
6625 "menuOptions.Highlight Dragging"), args, 1);
6629 void HighlightLastMoveProc(w, event, prms, nprms)
6637 appData.highlightLastMove = !appData.highlightLastMove;
6639 if (appData.highlightLastMove) {
6640 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6642 XtSetArg(args[0], XtNleftBitmap, None);
6644 XtSetValues(XtNameToWidget(menuBarWidget,
6645 "menuOptions.Highlight Last Move"), args, 1);
6648 void HighlightArrowProc(w, event, prms, nprms)
6656 appData.highlightMoveWithArrow = !appData.highlightMoveWithArrow;
6658 if (appData.highlightMoveWithArrow) {
6659 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6661 XtSetArg(args[0], XtNleftBitmap, None);
6663 XtSetValues(XtNameToWidget(menuBarWidget,
6664 "menuOptions.Arrow"), args, 1);
6668 void IcsAlarmProc(w, event, prms, nprms)
6676 appData.icsAlarm = !appData.icsAlarm;
6678 if (appData.icsAlarm) {
6679 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6681 XtSetArg(args[0], XtNleftBitmap, None);
6683 XtSetValues(XtNameToWidget(menuBarWidget,
6684 "menuOptions.ICS Alarm"), args, 1);
6688 void MoveSoundProc(w, event, prms, nprms)
6696 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6698 if (appData.ringBellAfterMoves) {
6699 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6701 XtSetArg(args[0], XtNleftBitmap, None);
6703 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6707 void OneClickProc(w, event, prms, nprms)
6715 appData.oneClick = !appData.oneClick;
6717 if (appData.oneClick) {
6718 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6720 XtSetArg(args[0], XtNleftBitmap, None);
6722 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.OneClick"),
6726 void PeriodicUpdatesProc(w, event, prms, nprms)
6734 PeriodicUpdatesEvent(!appData.periodicUpdates);
6736 if (appData.periodicUpdates) {
6737 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6739 XtSetArg(args[0], XtNleftBitmap, None);
6741 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6745 void PopupExitMessageProc(w, event, prms, nprms)
6753 appData.popupExitMessage = !appData.popupExitMessage;
6755 if (appData.popupExitMessage) {
6756 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6758 XtSetArg(args[0], XtNleftBitmap, None);
6760 XtSetValues(XtNameToWidget(menuBarWidget,
6761 "menuOptions.Popup Exit Message"), args, 1);
6764 void PopupMoveErrorsProc(w, event, prms, nprms)
6772 appData.popupMoveErrors = !appData.popupMoveErrors;
6774 if (appData.popupMoveErrors) {
6775 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6777 XtSetArg(args[0], XtNleftBitmap, None);
6779 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6784 void PremoveProc(w, event, prms, nprms)
6792 appData.premove = !appData.premove;
6794 if (appData.premove) {
6795 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6797 XtSetArg(args[0], XtNleftBitmap, None);
6799 XtSetValues(XtNameToWidget(menuBarWidget,
6800 "menuOptions.Premove"), args, 1);
6804 void ShowCoordsProc(w, event, prms, nprms)
6812 appData.showCoords = !appData.showCoords;
6814 if (appData.showCoords) {
6815 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6817 XtSetArg(args[0], XtNleftBitmap, None);
6819 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6822 DrawPosition(True, NULL);
6825 void ShowThinkingProc(w, event, prms, nprms)
6831 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6832 ShowThinkingEvent();
6835 void HideThinkingProc(w, event, prms, nprms)
6843 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6844 ShowThinkingEvent();
6846 if (appData.hideThinkingFromHuman) {
6847 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6849 XtSetArg(args[0], XtNleftBitmap, None);
6851 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6856 void SaveOnExitProc(w, event, prms, nprms)
6864 saveSettingsOnExit = !saveSettingsOnExit;
6866 if (saveSettingsOnExit) {
6867 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6869 XtSetArg(args[0], XtNleftBitmap, None);
6871 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6875 void SaveSettingsProc(w, event, prms, nprms)
6881 SaveSettings(settingsFileName);
6884 void InfoProc(w, event, prms, nprms)
6891 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6896 void ManProc(w, event, prms, nprms)
6904 if (nprms && *nprms > 0)
6908 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6912 void HintProc(w, event, prms, nprms)
6921 void BookProc(w, event, prms, nprms)
6930 void AboutProc(w, event, prms, nprms)
6938 char *zippy = " (with Zippy code)";
6942 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6943 programVersion, zippy,
6944 "Copyright 1991 Digital Equipment Corporation",
6945 "Enhancements Copyright 1992-2009 Free Software Foundation",
6946 "Enhancements Copyright 2005 Alessandro Scotti",
6947 PACKAGE, " is free software and carries NO WARRANTY;",
6948 "see the file COPYING for more information.");
6949 ErrorPopUp(_("About XBoard"), buf, FALSE);
6952 void DebugProc(w, event, prms, nprms)
6958 appData.debugMode = !appData.debugMode;
6961 void AboutGameProc(w, event, prms, nprms)
6970 void NothingProc(w, event, prms, nprms)
6979 void Iconify(w, event, prms, nprms)
6988 XtSetArg(args[0], XtNiconic, True);
6989 XtSetValues(shellWidget, args, 1);
6992 void DisplayMessage(message, extMessage)
6993 char *message, *extMessage;
6995 /* display a message in the message widget */
7004 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
7009 message = extMessage;
7013 /* need to test if messageWidget already exists, since this function
7014 can also be called during the startup, if for example a Xresource
7015 is not set up correctly */
7018 XtSetArg(arg, XtNlabel, message);
7019 XtSetValues(messageWidget, &arg, 1);
7025 void DisplayTitle(text)
7030 char title[MSG_SIZ];
7033 if (text == NULL) text = "";
7035 if (appData.titleInWindow) {
7037 XtSetArg(args[i], XtNlabel, text); i++;
7038 XtSetValues(titleWidget, args, i);
7041 if (*text != NULLCHAR) {
7042 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
7043 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
7044 } else if (appData.icsActive) {
7045 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7046 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7047 } else if (appData.cmailGameName[0] != NULLCHAR) {
7048 snprintf(icon, sizeof(icon), "%s", "CMail");
7049 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7051 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7052 } else if (gameInfo.variant == VariantGothic) {
7053 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7054 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
7057 } else if (gameInfo.variant == VariantFalcon) {
7058 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7059 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
7061 } else if (appData.noChessProgram) {
7062 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7063 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
7065 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
7066 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7069 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7070 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7071 XtSetValues(shellWidget, args, i);
7076 DisplayError(message, error)
7083 if (appData.debugMode || appData.matchMode) {
7084 fprintf(stderr, "%s: %s\n", programName, message);
7087 if (appData.debugMode || appData.matchMode) {
7088 fprintf(stderr, "%s: %s: %s\n",
7089 programName, message, strerror(error));
7091 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7094 ErrorPopUp(_("Error"), message, FALSE);
7098 void DisplayMoveError(message)
7103 DrawPosition(FALSE, NULL);
7104 if (appData.debugMode || appData.matchMode) {
7105 fprintf(stderr, "%s: %s\n", programName, message);
7107 if (appData.popupMoveErrors) {
7108 ErrorPopUp(_("Error"), message, FALSE);
7110 DisplayMessage(message, "");
7115 void DisplayFatalError(message, error, status)
7121 errorExitStatus = status;
7123 fprintf(stderr, "%s: %s\n", programName, message);
7125 fprintf(stderr, "%s: %s: %s\n",
7126 programName, message, strerror(error));
7127 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7130 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7131 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7137 void DisplayInformation(message)
7141 ErrorPopUp(_("Information"), message, TRUE);
7144 void DisplayNote(message)
7148 ErrorPopUp(_("Note"), message, FALSE);
7152 NullXErrorCheck(dpy, error_event)
7154 XErrorEvent *error_event;
7159 void DisplayIcsInteractionTitle(message)
7162 if (oldICSInteractionTitle == NULL) {
7163 /* Magic to find the old window title, adapted from vim */
7164 char *wina = getenv("WINDOWID");
7166 Window win = (Window) atoi(wina);
7167 Window root, parent, *children;
7168 unsigned int nchildren;
7169 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7171 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7172 if (!XQueryTree(xDisplay, win, &root, &parent,
7173 &children, &nchildren)) break;
7174 if (children) XFree((void *)children);
7175 if (parent == root || parent == 0) break;
7178 XSetErrorHandler(oldHandler);
7180 if (oldICSInteractionTitle == NULL) {
7181 oldICSInteractionTitle = "xterm";
7184 printf("\033]0;%s\007", message);
7188 char pendingReplyPrefix[MSG_SIZ];
7189 ProcRef pendingReplyPR;
7191 void AskQuestionProc(w, event, prms, nprms)
7198 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7202 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7205 void AskQuestionPopDown()
7207 if (!askQuestionUp) return;
7208 XtPopdown(askQuestionShell);
7209 XtDestroyWidget(askQuestionShell);
7210 askQuestionUp = False;
7213 void AskQuestionReplyAction(w, event, prms, nprms)
7223 reply = XawDialogGetValueString(w = XtParent(w));
7224 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
7225 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
7226 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
7227 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
7228 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7229 AskQuestionPopDown();
7231 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7234 void AskQuestionCallback(w, client_data, call_data)
7236 XtPointer client_data, call_data;
7241 XtSetArg(args[0], XtNlabel, &name);
7242 XtGetValues(w, args, 1);
7244 if (strcmp(name, _("cancel")) == 0) {
7245 AskQuestionPopDown();
7247 AskQuestionReplyAction(w, NULL, NULL, NULL);
7251 void AskQuestion(title, question, replyPrefix, pr)
7252 char *title, *question, *replyPrefix;
7256 Widget popup, layout, dialog, edit;
7262 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
7263 pendingReplyPR = pr;
7266 XtSetArg(args[i], XtNresizable, True); i++;
7267 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7268 askQuestionShell = popup =
7269 XtCreatePopupShell(title, transientShellWidgetClass,
7270 shellWidget, args, i);
7273 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7274 layoutArgs, XtNumber(layoutArgs));
7277 XtSetArg(args[i], XtNlabel, question); i++;
7278 XtSetArg(args[i], XtNvalue, ""); i++;
7279 XtSetArg(args[i], XtNborderWidth, 0); i++;
7280 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7283 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7284 (XtPointer) dialog);
7285 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7286 (XtPointer) dialog);
7288 XtRealizeWidget(popup);
7289 CatchDeleteWindow(popup, "AskQuestionPopDown");
7291 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7292 &x, &y, &win_x, &win_y, &mask);
7294 XtSetArg(args[0], XtNx, x - 10);
7295 XtSetArg(args[1], XtNy, y - 30);
7296 XtSetValues(popup, args, 2);
7298 XtPopup(popup, XtGrabExclusive);
7299 askQuestionUp = True;
7301 edit = XtNameToWidget(dialog, "*value");
7302 XtSetKeyboardFocus(popup, edit);
7310 if (*name == NULLCHAR) {
7312 } else if (strcmp(name, "$") == 0) {
7313 putc(BELLCHAR, stderr);
7316 char *prefix = "", *sep = "";
7317 if(!strchr(name, '/')) { prefix = appData.soundDirectory; sep = "/"; }
7318 snprintf(buf, sizeof(buf), "%s '%s%s%s' &", appData.soundProgram, prefix, sep, name);
7326 PlaySound(appData.soundMove);
7332 PlaySound(appData.soundIcsWin);
7338 PlaySound(appData.soundIcsLoss);
7344 PlaySound(appData.soundIcsDraw);
7348 PlayIcsUnfinishedSound()
7350 PlaySound(appData.soundIcsUnfinished);
7356 PlaySound(appData.soundIcsAlarm);
7362 system("stty echo");
7368 system("stty -echo");
7372 Colorize(cc, continuation)
7377 int count, outCount, error;
7379 if (textColors[(int)cc].bg > 0) {
7380 if (textColors[(int)cc].fg > 0) {
7381 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7382 textColors[(int)cc].fg, textColors[(int)cc].bg);
7384 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7385 textColors[(int)cc].bg);
7388 if (textColors[(int)cc].fg > 0) {
7389 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7390 textColors[(int)cc].fg);
7392 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7395 count = strlen(buf);
7396 outCount = OutputToProcess(NoProc, buf, count, &error);
7397 if (outCount < count) {
7398 DisplayFatalError(_("Error writing to display"), error, 1);
7401 if (continuation) return;
7404 PlaySound(appData.soundShout);
7407 PlaySound(appData.soundSShout);
7410 PlaySound(appData.soundChannel1);
7413 PlaySound(appData.soundChannel);
7416 PlaySound(appData.soundKibitz);
7419 PlaySound(appData.soundTell);
7421 case ColorChallenge:
7422 PlaySound(appData.soundChallenge);
7425 PlaySound(appData.soundRequest);
7428 PlaySound(appData.soundSeek);
7439 return getpwuid(getuid())->pw_name;
7443 ExpandPathName(path)
7446 static char static_buf[4*MSG_SIZ];
7447 char *d, *s, buf[4*MSG_SIZ];
7453 while (*s && isspace(*s))
7462 if (*(s+1) == '/') {
7463 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7467 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7468 { char *p; if(p = strchr(buf, '/')) *p = 0; }
7469 pwd = getpwnam(buf);
7472 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7476 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7477 strcat(d, strchr(s+1, '/'));
7481 safeStrCpy(d, s, 4*MSG_SIZ );
7488 static char host_name[MSG_SIZ];
7490 #if HAVE_GETHOSTNAME
7491 gethostname(host_name, MSG_SIZ);
7493 #else /* not HAVE_GETHOSTNAME */
7494 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7495 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7497 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7499 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7500 #endif /* not HAVE_GETHOSTNAME */
7503 XtIntervalId delayedEventTimerXID = 0;
7504 DelayedEventCallback delayedEventCallback = 0;
7509 delayedEventTimerXID = 0;
7510 delayedEventCallback();
7514 ScheduleDelayedEvent(cb, millisec)
7515 DelayedEventCallback cb; long millisec;
7517 if(delayedEventTimerXID && delayedEventCallback == cb)
7518 // [HGM] alive: replace, rather than add or flush identical event
7519 XtRemoveTimeOut(delayedEventTimerXID);
7520 delayedEventCallback = cb;
7521 delayedEventTimerXID =
7522 XtAppAddTimeOut(appContext, millisec,
7523 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7526 DelayedEventCallback
7529 if (delayedEventTimerXID) {
7530 return delayedEventCallback;
7537 CancelDelayedEvent()
7539 if (delayedEventTimerXID) {
7540 XtRemoveTimeOut(delayedEventTimerXID);
7541 delayedEventTimerXID = 0;
7545 XtIntervalId loadGameTimerXID = 0;
7547 int LoadGameTimerRunning()
7549 return loadGameTimerXID != 0;
7552 int StopLoadGameTimer()
7554 if (loadGameTimerXID != 0) {
7555 XtRemoveTimeOut(loadGameTimerXID);
7556 loadGameTimerXID = 0;
7564 LoadGameTimerCallback(arg, id)
7568 loadGameTimerXID = 0;
7573 StartLoadGameTimer(millisec)
7577 XtAppAddTimeOut(appContext, millisec,
7578 (XtTimerCallbackProc) LoadGameTimerCallback,
7582 XtIntervalId analysisClockXID = 0;
7585 AnalysisClockCallback(arg, id)
7589 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7590 || appData.icsEngineAnalyze) { // [DM]
7591 AnalysisPeriodicEvent(0);
7592 StartAnalysisClock();
7597 StartAnalysisClock()
7600 XtAppAddTimeOut(appContext, 2000,
7601 (XtTimerCallbackProc) AnalysisClockCallback,
7605 XtIntervalId clockTimerXID = 0;
7607 int ClockTimerRunning()
7609 return clockTimerXID != 0;
7612 int StopClockTimer()
7614 if (clockTimerXID != 0) {
7615 XtRemoveTimeOut(clockTimerXID);
7624 ClockTimerCallback(arg, id)
7633 StartClockTimer(millisec)
7637 XtAppAddTimeOut(appContext, millisec,
7638 (XtTimerCallbackProc) ClockTimerCallback,
7643 DisplayTimerLabel(w, color, timer, highlight)
7652 /* check for low time warning */
7653 Pixel foregroundOrWarningColor = timerForegroundPixel;
7656 appData.lowTimeWarning &&
7657 (timer / 1000) < appData.icsAlarmTime)
7658 foregroundOrWarningColor = lowTimeWarningColor;
7660 if (appData.clockMode) {
7661 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7662 XtSetArg(args[0], XtNlabel, buf);
7664 snprintf(buf, MSG_SIZ, "%s ", color);
7665 XtSetArg(args[0], XtNlabel, buf);
7670 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7671 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7673 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7674 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7677 XtSetValues(w, args, 3);
7681 DisplayWhiteClock(timeRemaining, highlight)
7687 if(appData.noGUI) return;
7688 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7689 if (highlight && iconPixmap == bIconPixmap) {
7690 iconPixmap = wIconPixmap;
7691 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7692 XtSetValues(shellWidget, args, 1);
7697 DisplayBlackClock(timeRemaining, highlight)
7703 if(appData.noGUI) return;
7704 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7705 if (highlight && iconPixmap == wIconPixmap) {
7706 iconPixmap = bIconPixmap;
7707 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7708 XtSetValues(shellWidget, args, 1);
7726 int StartChildProcess(cmdLine, dir, pr)
7733 int to_prog[2], from_prog[2];
7737 if (appData.debugMode) {
7738 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7741 /* We do NOT feed the cmdLine to the shell; we just
7742 parse it into blank-separated arguments in the
7743 most simple-minded way possible.
7746 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7749 while(*p == ' ') p++;
7751 if(*p == '"' || *p == '\'')
7752 p = strchr(++argv[i-1], *p);
7753 else p = strchr(p, ' ');
7754 if (p == NULL) break;
7759 SetUpChildIO(to_prog, from_prog);
7761 if ((pid = fork()) == 0) {
7763 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7764 close(to_prog[1]); // first close the unused pipe ends
7765 close(from_prog[0]);
7766 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7767 dup2(from_prog[1], 1);
7768 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7769 close(from_prog[1]); // and closing again loses one of the pipes!
7770 if(fileno(stderr) >= 2) // better safe than sorry...
7771 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7773 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7778 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7780 execvp(argv[0], argv);
7782 /* If we get here, exec failed */
7787 /* Parent process */
7789 close(from_prog[1]);
7791 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7794 cp->fdFrom = from_prog[0];
7795 cp->fdTo = to_prog[1];
7800 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7801 static RETSIGTYPE AlarmCallBack(int n)
7807 DestroyChildProcess(pr, signalType)
7811 ChildProc *cp = (ChildProc *) pr;
7813 if (cp->kind != CPReal) return;
7815 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7816 signal(SIGALRM, AlarmCallBack);
7818 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7819 kill(cp->pid, SIGKILL); // kill it forcefully
7820 wait((int *) 0); // and wait again
7824 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7826 /* Process is exiting either because of the kill or because of
7827 a quit command sent by the backend; either way, wait for it to die.
7836 InterruptChildProcess(pr)
7839 ChildProc *cp = (ChildProc *) pr;
7841 if (cp->kind != CPReal) return;
7842 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7845 int OpenTelnet(host, port, pr)
7850 char cmdLine[MSG_SIZ];
7852 if (port[0] == NULLCHAR) {
7853 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7855 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7857 return StartChildProcess(cmdLine, "", pr);
7860 int OpenTCP(host, port, pr)
7866 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7867 #else /* !OMIT_SOCKETS */
7869 struct sockaddr_in sa;
7871 unsigned short uport;
7874 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7878 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7879 sa.sin_family = AF_INET;
7880 sa.sin_addr.s_addr = INADDR_ANY;
7881 uport = (unsigned short) 0;
7882 sa.sin_port = htons(uport);
7883 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7887 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7888 if (!(hp = gethostbyname(host))) {
7890 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7891 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7892 hp->h_addrtype = AF_INET;
7894 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7895 hp->h_addr_list[0] = (char *) malloc(4);
7896 hp->h_addr_list[0][0] = b0;
7897 hp->h_addr_list[0][1] = b1;
7898 hp->h_addr_list[0][2] = b2;
7899 hp->h_addr_list[0][3] = b3;
7904 sa.sin_family = hp->h_addrtype;
7905 uport = (unsigned short) atoi(port);
7906 sa.sin_port = htons(uport);
7907 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7909 if (connect(s, (struct sockaddr *) &sa,
7910 sizeof(struct sockaddr_in)) < 0) {
7914 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7921 #endif /* !OMIT_SOCKETS */
7926 int OpenCommPort(name, pr)
7933 fd = open(name, 2, 0);
7934 if (fd < 0) return errno;
7936 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7946 int OpenLoopback(pr)
7952 SetUpChildIO(to, from);
7954 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7957 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7964 int OpenRcmd(host, user, cmd, pr)
7965 char *host, *user, *cmd;
7968 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7972 #define INPUT_SOURCE_BUF_SIZE 8192
7981 char buf[INPUT_SOURCE_BUF_SIZE];
7986 DoInputCallback(closure, source, xid)
7991 InputSource *is = (InputSource *) closure;
7996 if (is->lineByLine) {
7997 count = read(is->fd, is->unused,
7998 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
8000 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
8003 is->unused += count;
8005 while (p < is->unused) {
8006 q = memchr(p, '\n', is->unused - p);
8007 if (q == NULL) break;
8009 (is->func)(is, is->closure, p, q - p, 0);
8013 while (p < is->unused) {
8018 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8023 (is->func)(is, is->closure, is->buf, count, error);
8027 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8034 ChildProc *cp = (ChildProc *) pr;
8036 is = (InputSource *) calloc(1, sizeof(InputSource));
8037 is->lineByLine = lineByLine;
8041 is->fd = fileno(stdin);
8043 is->kind = cp->kind;
8044 is->fd = cp->fdFrom;
8047 is->unused = is->buf;
8050 is->xid = XtAppAddInput(appContext, is->fd,
8051 (XtPointer) (XtInputReadMask),
8052 (XtInputCallbackProc) DoInputCallback,
8054 is->closure = closure;
8055 return (InputSourceRef) is;
8059 RemoveInputSource(isr)
8062 InputSource *is = (InputSource *) isr;
8064 if (is->xid == 0) return;
8065 XtRemoveInput(is->xid);
8069 int OutputToProcess(pr, message, count, outError)
8075 static int line = 0;
8076 ChildProc *cp = (ChildProc *) pr;
8081 if (appData.noJoin || !appData.useInternalWrap)
8082 outCount = fwrite(message, 1, count, stdout);
8085 int width = get_term_width();
8086 int len = wrap(NULL, message, count, width, &line);
8087 char *msg = malloc(len);
8091 outCount = fwrite(message, 1, count, stdout);
8094 dbgchk = wrap(msg, message, count, width, &line);
8095 if (dbgchk != len && appData.debugMode)
8096 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8097 outCount = fwrite(msg, 1, dbgchk, stdout);
8103 outCount = write(cp->fdTo, message, count);
8113 /* Output message to process, with "ms" milliseconds of delay
8114 between each character. This is needed when sending the logon
8115 script to ICC, which for some reason doesn't like the
8116 instantaneous send. */
8117 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8124 ChildProc *cp = (ChildProc *) pr;
8129 r = write(cp->fdTo, message++, 1);
8142 /**** Animation code by Hugh Fisher, DCS, ANU.
8144 Known problem: if a window overlapping the board is
8145 moved away while a piece is being animated underneath,
8146 the newly exposed area won't be updated properly.
8147 I can live with this.
8149 Known problem: if you look carefully at the animation
8150 of pieces in mono mode, they are being drawn as solid
8151 shapes without interior detail while moving. Fixing
8152 this would be a major complication for minimal return.
8155 /* Masks for XPM pieces. Black and white pieces can have
8156 different shapes, but in the interest of retaining my
8157 sanity pieces must have the same outline on both light
8158 and dark squares, and all pieces must use the same
8159 background square colors/images. */
8161 static int xpmDone = 0;
8164 CreateAnimMasks (pieceDepth)
8171 unsigned long plane;
8174 /* Need a bitmap just to get a GC with right depth */
8175 buf = XCreatePixmap(xDisplay, xBoardWindow,
8177 values.foreground = 1;
8178 values.background = 0;
8179 /* Don't use XtGetGC, not read only */
8180 maskGC = XCreateGC(xDisplay, buf,
8181 GCForeground | GCBackground, &values);
8182 XFreePixmap(xDisplay, buf);
8184 buf = XCreatePixmap(xDisplay, xBoardWindow,
8185 squareSize, squareSize, pieceDepth);
8186 values.foreground = XBlackPixel(xDisplay, xScreen);
8187 values.background = XWhitePixel(xDisplay, xScreen);
8188 bufGC = XCreateGC(xDisplay, buf,
8189 GCForeground | GCBackground, &values);
8191 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8192 /* Begin with empty mask */
8193 if(!xpmDone) // [HGM] pieces: keep using existing
8194 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8195 squareSize, squareSize, 1);
8196 XSetFunction(xDisplay, maskGC, GXclear);
8197 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8198 0, 0, squareSize, squareSize);
8200 /* Take a copy of the piece */
8205 XSetFunction(xDisplay, bufGC, GXcopy);
8206 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8208 0, 0, squareSize, squareSize, 0, 0);
8210 /* XOR the background (light) over the piece */
8211 XSetFunction(xDisplay, bufGC, GXxor);
8213 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8214 0, 0, squareSize, squareSize, 0, 0);
8216 XSetForeground(xDisplay, bufGC, lightSquareColor);
8217 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8220 /* We now have an inverted piece image with the background
8221 erased. Construct mask by just selecting all the non-zero
8222 pixels - no need to reconstruct the original image. */
8223 XSetFunction(xDisplay, maskGC, GXor);
8225 /* Might be quicker to download an XImage and create bitmap
8226 data from it rather than this N copies per piece, but it
8227 only takes a fraction of a second and there is a much
8228 longer delay for loading the pieces. */
8229 for (n = 0; n < pieceDepth; n ++) {
8230 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8231 0, 0, squareSize, squareSize,
8237 XFreePixmap(xDisplay, buf);
8238 XFreeGC(xDisplay, bufGC);
8239 XFreeGC(xDisplay, maskGC);
8243 InitAnimState (anim, info)
8245 XWindowAttributes * info;
8250 /* Each buffer is square size, same depth as window */
8251 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8252 squareSize, squareSize, info->depth);
8253 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8254 squareSize, squareSize, info->depth);
8256 /* Create a plain GC for blitting */
8257 mask = GCForeground | GCBackground | GCFunction |
8258 GCPlaneMask | GCGraphicsExposures;
8259 values.foreground = XBlackPixel(xDisplay, xScreen);
8260 values.background = XWhitePixel(xDisplay, xScreen);
8261 values.function = GXcopy;
8262 values.plane_mask = AllPlanes;
8263 values.graphics_exposures = False;
8264 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8266 /* Piece will be copied from an existing context at
8267 the start of each new animation/drag. */
8268 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8270 /* Outline will be a read-only copy of an existing */
8271 anim->outlineGC = None;
8277 XWindowAttributes info;
8279 if (xpmDone && gameInfo.variant == oldVariant) return;
8280 if(xpmDone) oldVariant = gameInfo.variant; // first time pieces might not be created yet
8281 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8283 InitAnimState(&game, &info);
8284 InitAnimState(&player, &info);
8286 /* For XPM pieces, we need bitmaps to use as masks. */
8288 CreateAnimMasks(info.depth);
8294 static Boolean frameWaiting;
8296 static RETSIGTYPE FrameAlarm (sig)
8299 frameWaiting = False;
8300 /* In case System-V style signals. Needed?? */
8301 signal(SIGALRM, FrameAlarm);
8308 struct itimerval delay;
8310 XSync(xDisplay, False);
8313 frameWaiting = True;
8314 signal(SIGALRM, FrameAlarm);
8315 delay.it_interval.tv_sec =
8316 delay.it_value.tv_sec = time / 1000;
8317 delay.it_interval.tv_usec =
8318 delay.it_value.tv_usec = (time % 1000) * 1000;
8319 setitimer(ITIMER_REAL, &delay, NULL);
8320 while (frameWaiting) pause();
8321 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8322 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8323 setitimer(ITIMER_REAL, &delay, NULL);
8333 XSync(xDisplay, False);
8335 usleep(time * 1000);
8340 /* Convert board position to corner of screen rect and color */
8343 ScreenSquare(column, row, pt, color)
8344 int column; int row; XPoint * pt; int * color;
8347 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8348 pt->y = lineGap + row * (squareSize + lineGap);
8350 pt->x = lineGap + column * (squareSize + lineGap);
8351 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8353 *color = SquareColor(row, column);
8356 /* Convert window coords to square */
8359 BoardSquare(x, y, column, row)
8360 int x; int y; int * column; int * row;
8362 *column = EventToSquare(x, BOARD_WIDTH);
8363 if (flipView && *column >= 0)
8364 *column = BOARD_WIDTH - 1 - *column;
8365 *row = EventToSquare(y, BOARD_HEIGHT);
8366 if (!flipView && *row >= 0)
8367 *row = BOARD_HEIGHT - 1 - *row;
8372 #undef Max /* just in case */
8374 #define Max(a, b) ((a) > (b) ? (a) : (b))
8375 #define Min(a, b) ((a) < (b) ? (a) : (b))
8378 SetRect(rect, x, y, width, height)
8379 XRectangle * rect; int x; int y; int width; int height;
8383 rect->width = width;
8384 rect->height = height;
8387 /* Test if two frames overlap. If they do, return
8388 intersection rect within old and location of
8389 that rect within new. */
8392 Intersect(old, new, size, area, pt)
8393 XPoint * old; XPoint * new;
8394 int size; XRectangle * area; XPoint * pt;
8396 if (old->x > new->x + size || new->x > old->x + size ||
8397 old->y > new->y + size || new->y > old->y + size) {
8400 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8401 size - abs(old->x - new->x), size - abs(old->y - new->y));
8402 pt->x = Max(old->x - new->x, 0);
8403 pt->y = Max(old->y - new->y, 0);
8408 /* For two overlapping frames, return the rect(s)
8409 in the old that do not intersect with the new. */
8412 CalcUpdateRects(old, new, size, update, nUpdates)
8413 XPoint * old; XPoint * new; int size;
8414 XRectangle update[]; int * nUpdates;
8418 /* If old = new (shouldn't happen) then nothing to draw */
8419 if (old->x == new->x && old->y == new->y) {
8423 /* Work out what bits overlap. Since we know the rects
8424 are the same size we don't need a full intersect calc. */
8426 /* Top or bottom edge? */
8427 if (new->y > old->y) {
8428 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8430 } else if (old->y > new->y) {
8431 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8432 size, old->y - new->y);
8435 /* Left or right edge - don't overlap any update calculated above. */
8436 if (new->x > old->x) {
8437 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8438 new->x - old->x, size - abs(new->y - old->y));
8440 } else if (old->x > new->x) {
8441 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8442 old->x - new->x, size - abs(new->y - old->y));
8449 /* Generate a series of frame coords from start->mid->finish.
8450 The movement rate doubles until the half way point is
8451 reached, then halves back down to the final destination,
8452 which gives a nice slow in/out effect. The algorithmn
8453 may seem to generate too many intermediates for short
8454 moves, but remember that the purpose is to attract the
8455 viewers attention to the piece about to be moved and
8456 then to where it ends up. Too few frames would be less
8460 Tween(start, mid, finish, factor, frames, nFrames)
8461 XPoint * start; XPoint * mid;
8462 XPoint * finish; int factor;
8463 XPoint frames[]; int * nFrames;
8465 int fraction, n, count;
8469 /* Slow in, stepping 1/16th, then 1/8th, ... */
8471 for (n = 0; n < factor; n++)
8473 for (n = 0; n < factor; n++) {
8474 frames[count].x = start->x + (mid->x - start->x) / fraction;
8475 frames[count].y = start->y + (mid->y - start->y) / fraction;
8477 fraction = fraction / 2;
8481 frames[count] = *mid;
8484 /* Slow out, stepping 1/2, then 1/4, ... */
8486 for (n = 0; n < factor; n++) {
8487 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8488 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8490 fraction = fraction * 2;
8495 /* Draw a piece on the screen without disturbing what's there */
8498 SelectGCMask(piece, clip, outline, mask)
8499 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8503 /* Bitmap for piece being moved. */
8504 if (appData.monoMode) {
8505 *mask = *pieceToSolid(piece);
8506 } else if (useImages) {
8508 *mask = xpmMask[piece];
8510 *mask = ximMaskPm[piece];
8513 *mask = *pieceToSolid(piece);
8516 /* GC for piece being moved. Square color doesn't matter, but
8517 since it gets modified we make a copy of the original. */
8519 if (appData.monoMode)
8524 if (appData.monoMode)
8529 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8531 /* Outline only used in mono mode and is not modified */
8533 *outline = bwPieceGC;
8535 *outline = wbPieceGC;
8539 OverlayPiece(piece, clip, outline, dest)
8540 ChessSquare piece; GC clip; GC outline; Drawable dest;
8545 /* Draw solid rectangle which will be clipped to shape of piece */
8546 XFillRectangle(xDisplay, dest, clip,
8547 0, 0, squareSize, squareSize);
8548 if (appData.monoMode)
8549 /* Also draw outline in contrasting color for black
8550 on black / white on white cases */
8551 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8552 0, 0, squareSize, squareSize, 0, 0, 1);
8554 /* Copy the piece */
8559 if(appData.upsideDown && flipView) kind ^= 2;
8560 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8562 0, 0, squareSize, squareSize,
8567 /* Animate the movement of a single piece */
8570 BeginAnimation(anim, piece, startColor, start)
8578 if(appData.upsideDown && flipView) piece += piece < BlackPawn ? BlackPawn : -BlackPawn;
8579 /* The old buffer is initialised with the start square (empty) */
8580 BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0);
8581 anim->prevFrame = *start;
8583 /* The piece will be drawn using its own bitmap as a matte */
8584 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8585 XSetClipMask(xDisplay, anim->pieceGC, mask);
8589 AnimationFrame(anim, frame, piece)
8594 XRectangle updates[4];
8599 /* Save what we are about to draw into the new buffer */
8600 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8601 frame->x, frame->y, squareSize, squareSize,
8604 /* Erase bits of the previous frame */
8605 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8606 /* Where the new frame overlapped the previous,
8607 the contents in newBuf are wrong. */
8608 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8609 overlap.x, overlap.y,
8610 overlap.width, overlap.height,
8612 /* Repaint the areas in the old that don't overlap new */
8613 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8614 for (i = 0; i < count; i++)
8615 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8616 updates[i].x - anim->prevFrame.x,
8617 updates[i].y - anim->prevFrame.y,
8618 updates[i].width, updates[i].height,
8619 updates[i].x, updates[i].y);
8621 /* Easy when no overlap */
8622 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8623 0, 0, squareSize, squareSize,
8624 anim->prevFrame.x, anim->prevFrame.y);
8627 /* Save this frame for next time round */
8628 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8629 0, 0, squareSize, squareSize,
8631 anim->prevFrame = *frame;
8633 /* Draw piece over original screen contents, not current,
8634 and copy entire rect. Wipes out overlapping piece images. */
8635 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8636 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8637 0, 0, squareSize, squareSize,
8638 frame->x, frame->y);
8642 EndAnimation (anim, finish)
8646 XRectangle updates[4];
8651 /* The main code will redraw the final square, so we
8652 only need to erase the bits that don't overlap. */
8653 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8654 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8655 for (i = 0; i < count; i++)
8656 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8657 updates[i].x - anim->prevFrame.x,
8658 updates[i].y - anim->prevFrame.y,
8659 updates[i].width, updates[i].height,
8660 updates[i].x, updates[i].y);
8662 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8663 0, 0, squareSize, squareSize,
8664 anim->prevFrame.x, anim->prevFrame.y);
8669 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8671 ChessSquare piece; int startColor;
8672 XPoint * start; XPoint * finish;
8673 XPoint frames[]; int nFrames;
8677 BeginAnimation(anim, piece, startColor, start);
8678 for (n = 0; n < nFrames; n++) {
8679 AnimationFrame(anim, &(frames[n]), piece);
8680 FrameDelay(appData.animSpeed);
8682 EndAnimation(anim, finish);
8686 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
8689 ChessSquare piece = board[fromY][toY];
8690 board[fromY][toY] = EmptySquare;
8691 DrawPosition(FALSE, board);
8693 x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap);
8694 y = lineGap + toY * (squareSize + lineGap);
8696 x = lineGap + toX * (squareSize + lineGap);
8697 y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap);
8699 for(i=1; i<4*kFactor; i++) {
8700 int r = squareSize * 9 * i/(20*kFactor - 5);
8701 XFillArc(xDisplay, xBoardWindow, highlineGC,
8702 x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360);
8703 FrameDelay(appData.animSpeed);
8705 board[fromY][toY] = piece;
8708 /* Main control logic for deciding what to animate and how */
8711 AnimateMove(board, fromX, fromY, toX, toY)
8720 XPoint start, finish, mid;
8721 XPoint frames[kFactor * 2 + 1];
8722 int nFrames, startColor, endColor;
8724 /* Are we animating? */
8725 if (!appData.animate || appData.blindfold)
8728 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8729 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8730 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8732 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8733 piece = board[fromY][fromX];
8734 if (piece >= EmptySquare) return;
8739 hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1;
8742 if (appData.debugMode) {
8743 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8744 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8745 piece, fromX, fromY, toX, toY); }
8747 ScreenSquare(fromX, fromY, &start, &startColor);
8748 ScreenSquare(toX, toY, &finish, &endColor);
8751 /* Knight: make straight movement then diagonal */
8752 if (abs(toY - fromY) < abs(toX - fromX)) {
8753 mid.x = start.x + (finish.x - start.x) / 2;
8757 mid.y = start.y + (finish.y - start.y) / 2;
8760 mid.x = start.x + (finish.x - start.x) / 2;
8761 mid.y = start.y + (finish.y - start.y) / 2;
8764 /* Don't use as many frames for very short moves */
8765 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8766 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8768 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8769 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8770 if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
8772 for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
8773 if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
8776 /* Be sure end square is redrawn */
8777 damage[0][toY][toX] = True;
8781 DragPieceBegin(x, y)
8784 int boardX, boardY, color;
8787 /* Are we animating? */
8788 if (!appData.animateDragging || appData.blindfold)
8791 /* Figure out which square we start in and the
8792 mouse position relative to top left corner. */
8793 BoardSquare(x, y, &boardX, &boardY);
8794 player.startBoardX = boardX;
8795 player.startBoardY = boardY;
8796 ScreenSquare(boardX, boardY, &corner, &color);
8797 player.startSquare = corner;
8798 player.startColor = color;
8799 /* As soon as we start dragging, the piece will jump slightly to
8800 be centered over the mouse pointer. */
8801 player.mouseDelta.x = squareSize/2;
8802 player.mouseDelta.y = squareSize/2;
8803 /* Initialise animation */
8804 player.dragPiece = PieceForSquare(boardX, boardY);
8806 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8807 player.dragActive = True;
8808 BeginAnimation(&player, player.dragPiece, color, &corner);
8809 /* Mark this square as needing to be redrawn. Note that
8810 we don't remove the piece though, since logically (ie
8811 as seen by opponent) the move hasn't been made yet. */
8812 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8813 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8814 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8815 corner.x, corner.y, squareSize, squareSize,
8816 0, 0); // [HGM] zh: unstack in stead of grab
8817 if(gatingPiece != EmptySquare) {
8818 /* Kludge alert: When gating we want the introduced
8819 piece to appear on the from square. To generate an
8820 image of it, we draw it on the board, copy the image,
8821 and draw the original piece again. */
8822 ChessSquare piece = boards[currentMove][boardY][boardX];
8823 DrawSquare(boardY, boardX, gatingPiece, 0);
8824 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8825 corner.x, corner.y, squareSize, squareSize, 0, 0);
8826 DrawSquare(boardY, boardX, piece, 0);
8828 damage[0][boardY][boardX] = True;
8830 player.dragActive = False;
8840 /* Are we animating? */
8841 if (!appData.animateDragging || appData.blindfold)
8845 if (! player.dragActive)
8847 /* Move piece, maintaining same relative position
8848 of mouse within square */
8849 corner.x = x - player.mouseDelta.x;
8850 corner.y = y - player.mouseDelta.y;
8851 AnimationFrame(&player, &corner, player.dragPiece);
8853 if (appData.highlightDragging) {
8855 BoardSquare(x, y, &boardX, &boardY);
8856 SetHighlights(fromX, fromY, boardX, boardY);
8865 int boardX, boardY, color;
8868 /* Are we animating? */
8869 if (!appData.animateDragging || appData.blindfold)
8873 if (! player.dragActive)
8875 /* Last frame in sequence is square piece is
8876 placed on, which may not match mouse exactly. */
8877 BoardSquare(x, y, &boardX, &boardY);
8878 ScreenSquare(boardX, boardY, &corner, &color);
8879 EndAnimation(&player, &corner);
8881 /* Be sure end square is redrawn */
8882 damage[0][boardY][boardX] = True;
8884 /* This prevents weird things happening with fast successive
8885 clicks which on my Sun at least can cause motion events
8886 without corresponding press/release. */
8887 player.dragActive = False;
8890 /* Handle expose event while piece being dragged */
8895 if (!player.dragActive || appData.blindfold)
8898 /* What we're doing: logically, the move hasn't been made yet,
8899 so the piece is still in it's original square. But visually
8900 it's being dragged around the board. So we erase the square
8901 that the piece is on and draw it at the last known drag point. */
8902 BlankSquare(player.startSquare.x, player.startSquare.y,
8903 player.startColor, EmptySquare, xBoardWindow, 1);
8904 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8905 damage[0][player.startBoardY][player.startBoardX] = TRUE;
8908 #include <sys/ioctl.h>
8909 int get_term_width()
8911 int fd, default_width;
8914 default_width = 79; // this is FICS default anyway...
8916 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8918 if (!ioctl(fd, TIOCGSIZE, &win))
8919 default_width = win.ts_cols;
8920 #elif defined(TIOCGWINSZ)
8922 if (!ioctl(fd, TIOCGWINSZ, &win))
8923 default_width = win.ws_col;
8925 return default_width;
8931 static int old_width = 0;
8932 int new_width = get_term_width();
8934 if (old_width != new_width)
8935 ics_printf("set width %d\n", new_width);
8936 old_width = new_width;
8939 void NotifyFrontendLogin()
8944 /* [AS] Arrow highlighting support */
8946 static double A_WIDTH = 5; /* Width of arrow body */
8948 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
8949 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
8951 static double Sqr( double x )
8956 static int Round( double x )
8958 return (int) (x + 0.5);
8961 void SquareToPos(int rank, int file, int *x, int *y)
8964 *x = lineGap + ((BOARD_WIDTH-1)-file) * (squareSize + lineGap);
8965 *y = lineGap + rank * (squareSize + lineGap);
8967 *x = lineGap + file * (squareSize + lineGap);
8968 *y = lineGap + ((BOARD_HEIGHT-1)-rank) * (squareSize + lineGap);
8972 /* Draw an arrow between two points using current settings */
8973 void DrawArrowBetweenPoints( int s_x, int s_y, int d_x, int d_y )
8976 double dx, dy, j, k, x, y;
8979 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
8981 arrow[0].x = s_x + A_WIDTH + 0.5;
8984 arrow[1].x = s_x + A_WIDTH + 0.5;
8985 arrow[1].y = d_y - h;
8987 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8988 arrow[2].y = d_y - h;
8993 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
8994 arrow[5].y = d_y - h;
8996 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8997 arrow[4].y = d_y - h;
8999 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
9002 else if( d_y == s_y ) {
9003 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
9006 arrow[0].y = s_y + A_WIDTH + 0.5;
9008 arrow[1].x = d_x - w;
9009 arrow[1].y = s_y + A_WIDTH + 0.5;
9011 arrow[2].x = d_x - w;
9012 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9017 arrow[5].x = d_x - w;
9018 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
9020 arrow[4].x = d_x - w;
9021 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9024 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
9027 /* [AS] Needed a lot of paper for this! :-) */
9028 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
9029 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
9031 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
9033 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
9038 arrow[0].x = Round(x - j);
9039 arrow[0].y = Round(y + j*dx);
9041 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
9042 arrow[1].y = Round(arrow[0].y - 2*j*dx);
9045 x = (double) d_x - k;
9046 y = (double) d_y - k*dy;
9049 x = (double) d_x + k;
9050 y = (double) d_y + k*dy;
9053 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
9055 arrow[6].x = Round(x - j);
9056 arrow[6].y = Round(y + j*dx);
9058 arrow[2].x = Round(arrow[6].x + 2*j);
9059 arrow[2].y = Round(arrow[6].y - 2*j*dx);
9061 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
9062 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
9067 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
9068 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
9071 XFillPolygon(xDisplay, xBoardWindow, highlineGC, arrow, 7, Nonconvex, CoordModeOrigin);
9072 // Polygon( hdc, arrow, 7 );
9075 /* [AS] Draw an arrow between two squares */
9076 void DrawArrowBetweenSquares( int s_col, int s_row, int d_col, int d_row )
9078 int s_x, s_y, d_x, d_y, hor, vert, i;
9080 if( s_col == d_col && s_row == d_row ) {
9084 /* Get source and destination points */
9085 SquareToPos( s_row, s_col, &s_x, &s_y);
9086 SquareToPos( d_row, d_col, &d_x, &d_y);
9089 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
9091 else if( d_y < s_y ) {
9092 d_y += squareSize / 2 + squareSize / 4;
9095 d_y += squareSize / 2;
9099 d_x += squareSize / 2 - squareSize / 4;
9101 else if( d_x < s_x ) {
9102 d_x += squareSize / 2 + squareSize / 4;
9105 d_x += squareSize / 2;
9108 s_x += squareSize / 2;
9109 s_y += squareSize / 2;
9112 A_WIDTH = squareSize / 14.; //[HGM] make float
9114 DrawArrowBetweenPoints( s_x, s_y, d_x, d_y );
9116 hor = 64*s_col + 32; vert = 64*s_row + 32;
9117 for(i=0; i<= 64; i++) {
9118 damage[0][vert+6>>6][hor+6>>6] = True;
9119 damage[0][vert-6>>6][hor+6>>6] = True;
9120 damage[0][vert+6>>6][hor-6>>6] = True;
9121 damage[0][vert-6>>6][hor-6>>6] = True;
9122 hor += d_col - s_col; vert += d_row - s_row;
9126 Boolean IsDrawArrowEnabled()
9128 return appData.highlightMoveWithArrow && squareSize >= 32;
9131 void DrawArrowHighlight(int fromX, int fromY, int toX,int toY)
9133 if( IsDrawArrowEnabled() && fromX >= 0 && fromY >= 0 && toX >= 0 && toY >= 0)
9134 DrawArrowBetweenSquares(fromX, fromY, toX, toY);