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 FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
458 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
459 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
460 void IcsOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
461 void SoundOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
462 void BoardOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
463 void LoadOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
464 void SaveOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
465 void GameListOptionsPopDown P(());
466 void ShufflePopDown P(());
467 void TimeControlPopDown P(());
468 void GenericPopDown P(());
469 void update_ics_width P(());
470 int get_term_width P(());
471 int CopyMemoProc P(());
472 void DrawArrowHighlight P((int fromX, int fromY, int toX,int toY));
473 Boolean IsDrawArrowEnabled P(());
476 * XBoard depends on Xt R4 or higher
478 int xtVersion = XtSpecificationRelease;
483 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
484 jailSquareColor, highlightSquareColor, premoveHighlightColor;
485 Pixel lowTimeWarningColor;
486 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
487 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
488 wjPieceGC, bjPieceGC, prelineGC, countGC;
489 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
490 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
491 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
492 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
493 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
494 ICSInputShell, fileNameShell, askQuestionShell;
495 Widget historyShell, evalGraphShell, gameListShell;
496 int hOffset; // [HGM] dual
497 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
498 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
499 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
500 Font clockFontID, coordFontID, countFontID;
501 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
502 XtAppContext appContext;
504 char *oldICSInteractionTitle;
508 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
510 Position commentX = -1, commentY = -1;
511 Dimension commentW, commentH;
512 typedef unsigned int BoardSize;
514 Boolean chessProgram;
516 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
517 int squareSize, smallLayout = 0, tinyLayout = 0,
518 marginW, marginH, // [HGM] for run-time resizing
519 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
520 ICSInputBoxUp = False, askQuestionUp = False,
521 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
522 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
523 Pixel timerForegroundPixel, timerBackgroundPixel;
524 Pixel buttonForegroundPixel, buttonBackgroundPixel;
525 char *chessDir, *programName, *programVersion,
526 *gameCopyFilename, *gamePasteFilename;
527 Boolean alwaysOnTop = False;
528 Boolean saveSettingsOnExit;
529 char *settingsFileName;
530 char *icsTextMenuString;
532 char *firstChessProgramNames;
533 char *secondChessProgramNames;
535 WindowPlacement wpMain;
536 WindowPlacement wpConsole;
537 WindowPlacement wpComment;
538 WindowPlacement wpMoveHistory;
539 WindowPlacement wpEvalGraph;
540 WindowPlacement wpEngineOutput;
541 WindowPlacement wpGameList;
542 WindowPlacement wpTags;
546 Pixmap pieceBitmap[2][(int)BlackPawn];
547 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
548 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
549 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
550 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
551 Pixmap xpmBoardBitmap[2];
552 int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
553 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
554 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
555 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
556 XImage *ximLightSquare, *ximDarkSquare;
559 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
560 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
562 #define White(piece) ((int)(piece) < (int)BlackPawn)
564 /* Variables for doing smooth animation. This whole thing
565 would be much easier if the board was double-buffered,
566 but that would require a fairly major rewrite. */
571 GC blitGC, pieceGC, outlineGC;
572 XPoint startSquare, prevFrame, mouseDelta;
576 int startBoardX, startBoardY;
579 /* There can be two pieces being animated at once: a player
580 can begin dragging a piece before the remote opponent has moved. */
582 static AnimState game, player;
584 /* Bitmaps for use as masks when drawing XPM pieces.
585 Need one for each black and white piece. */
586 static Pixmap xpmMask[BlackKing + 1];
588 /* This magic number is the number of intermediate frames used
589 in each half of the animation. For short moves it's reduced
590 by 1. The total number of frames will be factor * 2 + 1. */
593 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
595 MenuItem fileMenu[] = {
596 {N_("New Game Ctrl+N"), "New Game", ResetProc},
597 {N_("New Shuffle Game ..."), "New Shuffle Game", ShuffleMenuProc},
598 {N_("New Variant ... Alt+Shift+V"), "New Variant", NewVariantProc}, // [HGM] variant: not functional yet
599 {"----", NULL, NothingProc},
600 {N_("Load Game Ctrl+O"), "Load Game", LoadGameProc},
601 {N_("Load Position Ctrl+Shift+O"), "Load Position", LoadPositionProc},
602 // {N_("Load Next Game"), "Load Next Game", LoadNextGameProc},
603 // {N_("Load Previous Game"), "Load Previous Game", LoadPrevGameProc},
604 // {N_("Reload Same Game"), "Reload Same Game", ReloadGameProc},
605 {N_("Next Position Shift+PgDn"), "Load Next Position", LoadNextPositionProc},
606 {N_("Prev Position Shift+PgUp"), "Load Previous Position", LoadPrevPositionProc},
607 {"----", NULL, NothingProc},
608 // {N_("Reload Same Position"), "Reload Same Position", ReloadPositionProc},
609 {N_("Save Game Ctrl+S"), "Save Game", SaveGameProc},
610 {N_("Save Position Ctrl+Shift+S"), "Save Position", SavePositionProc},
611 {"----", NULL, NothingProc},
612 {N_("Mail Move"), "Mail Move", MailMoveProc},
613 {N_("Reload CMail Message"), "Reload CMail Message", ReloadCmailMsgProc},
614 {"----", NULL, NothingProc},
615 {N_("Quit Ctr+Q"), "Exit", QuitProc},
619 MenuItem editMenu[] = {
620 {N_("Copy Game Ctrl+C"), "Copy Game", CopyGameProc},
621 {N_("Copy Position Ctrl+Shift+C"), "Copy Position", CopyPositionProc},
622 {"----", NULL, NothingProc},
623 {N_("Paste Game Ctrl+V"), "Paste Game", PasteGameProc},
624 {N_("Paste Position Ctrl+Shift+V"), "Paste Position", PastePositionProc},
625 {"----", NULL, NothingProc},
626 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
627 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
628 {N_("Edit Tags"), "Edit Tags", EditTagsProc},
629 {N_("Edit Comment"), "Edit Comment", EditCommentProc},
630 {"----", NULL, NothingProc},
631 {N_("Revert Home"), "Revert", RevertProc},
632 {N_("Annotate"), "Annotate", AnnotateProc},
633 {N_("Truncate Game End"), "Truncate Game", TruncateGameProc},
634 {"----", NULL, NothingProc},
635 {N_("Backward Alt+Left"), "Backward", BackwardProc},
636 {N_("Forward Alt+Right"), "Forward", ForwardProc},
637 {N_("Back to Start Alt+Home"), "Back to Start", ToStartProc},
638 {N_("Forward to End Alt+End"), "Forward to End", ToEndProc},
642 MenuItem viewMenu[] = {
643 {N_("Flip View F2"), "Flip View", FlipViewProc},
644 {"----", NULL, NothingProc},
645 {N_("Engine Output Alt+Shift+O"), "Show Engine Output", EngineOutputProc},
646 {N_("Move History Alt+Shift+H"), "Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
647 {N_("Evaluation Graph Alt+Shift+E"), "Show Evaluation Graph", EvalGraphProc},
648 {N_("Game List Alt+Shift+G"), "Show Game List", ShowGameListProc},
649 {"----", NULL, NothingProc},
650 {N_("Tags"), "Show Tags", EditTagsProc},
651 {N_("Comments"), "Show Comments", EditCommentProc},
652 {N_("ICS Input Box"), "ICS Input Box", IcsInputBoxProc},
653 {"----", NULL, NothingProc},
654 {N_("Board..."), "Board Options", BoardOptionsProc},
655 {N_("Game List Tags..."), "Game List", GameListOptionsPopUp},
659 MenuItem modeMenu[] = {
660 {N_("Machine White Ctrl+W"), "Machine White", MachineWhiteProc},
661 {N_("Machine Black Ctrl+B"), "Machine Black", MachineBlackProc},
662 {N_("Two Machines Ctrl+T"), "Two Machines", TwoMachinesProc},
663 {N_("Analysis Mode Ctrl+A"), "Analysis Mode", AnalyzeModeProc},
664 {N_("Analyze File Ctrl+F"), "Analyze File", AnalyzeFileProc },
665 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
666 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
667 {N_("Training"), "Training", TrainingProc},
668 {N_("ICS Client"), "ICS Client", IcsClientProc},
669 {"----", NULL, NothingProc},
670 {N_("Machine Match"), "Machine Match", MatchProc},
671 {N_("Pause Pause"), "Pause", PauseProc},
675 MenuItem actionMenu[] = {
676 {N_("Accept F3"), "Accept", AcceptProc},
677 {N_("Decline F4"), "Decline", DeclineProc},
678 {N_("Rematch F12"), "Rematch", RematchProc},
679 {"----", NULL, NothingProc},
680 {N_("Call Flag F5"), "Call Flag", CallFlagProc},
681 {N_("Draw F6"), "Draw", DrawProc},
682 {N_("Adjourn F7"), "Adjourn", AdjournProc},
683 {N_("Abort F8"),"Abort", AbortProc},
684 {N_("Resign F9"), "Resign", ResignProc},
685 {"----", NULL, NothingProc},
686 {N_("Stop Observing F10"), "Stop Observing", StopObservingProc},
687 {N_("Stop Examining F11"), "Stop Examining", StopExaminingProc},
688 {N_("Upload to Examine"), "Upload to Examine", UploadProc},
689 {"----", NULL, NothingProc},
690 {N_("Adjudicate to White"), "Adjudicate to White", AdjuWhiteProc},
691 {N_("Adjudicate to Black"), "Adjudicate to Black", AdjuBlackProc},
692 {N_("Adjudicate Draw"), "Adjudicate Draw", AdjuDrawProc},
696 MenuItem engineMenu[] = {
697 {N_("Engine #1 Settings ..."), "Engine #1 Settings", FirstSettingsProc},
698 {N_("Engine #2 Settings ..."), "Engine #2 Settings", SecondSettingsProc},
699 {"----", NULL, NothingProc},
700 {N_("Hint"), "Hint", HintProc},
701 {N_("Book"), "Book", BookProc},
702 {"----", NULL, NothingProc},
703 {N_("Move Now Ctrl+M"), "Move Now", MoveNowProc},
704 {N_("Retract Move Ctrl+X"), "Retract Move", RetractMoveProc},
708 MenuItem optionsMenu[] = {
709 #define OPTIONSDIALOG
711 {N_("General ..."), "General", OptionsProc},
713 {N_("Time Control ... Alt+Shift+T"), "Time Control", TimeControlProc},
714 {N_("Common Engine ... Alt+Shift+U"), "Common Engine", UciMenuProc},
715 {N_("Adjudications ... Alt+Shift+J"), "Adjudications", EngineMenuProc},
716 {N_("ICS ..."), "ICS", IcsOptionsProc},
717 {N_("Match ..."), "Match", MatchOptionsProc},
718 {N_("Load Game ..."), "Load Game", LoadOptionsProc},
719 {N_("Save Game ..."), "Save Game", SaveOptionsProc},
720 // {N_(" ..."), "", OptionsProc},
721 {N_("Game List ..."), "Game List", GameListOptionsPopUp},
722 {N_("Sounds ..."), "Sounds", SoundOptionsProc},
723 {"----", NULL, NothingProc},
724 #ifndef OPTIONSDIALOG
725 {N_("Always Queen Ctrl+Shift+Q"), "Always Queen", AlwaysQueenProc},
726 {N_("Animate Dragging"), "Animate Dragging", AnimateDraggingProc},
727 {N_("Animate Moving Ctrl+Shift+A"), "Animate Moving", AnimateMovingProc},
728 {N_("Auto Flag Ctrl+Shift+F"), "Auto Flag", AutoflagProc},
729 {N_("Auto Flip View"), "Auto Flip View", AutoflipProc},
730 {N_("Blindfold"), "Blindfold", BlindfoldProc},
731 {N_("Flash Moves"), "Flash Moves", FlashMovesProc},
733 {N_("Highlight Dragging"), "Highlight Dragging", HighlightDraggingProc},
735 {N_("Highlight Last Move"), "Highlight Last Move", HighlightLastMoveProc},
736 {N_("Highlight With Arrow"), "Arrow", HighlightArrowProc},
737 {N_("Move Sound"), "Move Sound", MoveSoundProc},
738 // {N_("ICS Alarm"), "ICS Alarm", IcsAlarmProc},
739 {N_("One-Click Moving"), "OneClick", OneClickProc},
740 {N_("Periodic Updates"), "Periodic Updates", PeriodicUpdatesProc},
741 {N_("Ponder Next Move Ctrl+Shift+P"), "Ponder Next Move", PonderNextMoveProc},
742 {N_("Popup Exit Message"), "Popup Exit Message", PopupExitMessageProc},
743 {N_("Popup Move Errors"), "Popup Move Errors", PopupMoveErrorsProc},
744 // {N_("Premove"), "Premove", PremoveProc},
745 {N_("Show Coords"), "Show Coords", ShowCoordsProc},
746 {N_("Hide Thinking Ctrl+Shift+H"), "Hide Thinking", HideThinkingProc},
747 {N_("Test Legality Ctrl+Shift+L"), "Test Legality", TestLegalityProc},
748 {"----", NULL, NothingProc},
750 {N_("Save Settings Now"), "Save Settings Now", SaveSettingsProc},
751 {N_("Save Settings on Exit"), "Save Settings on Exit", SaveOnExitProc},
755 MenuItem helpMenu[] = {
756 {N_("Info XBoard"), "Info XBoard", InfoProc},
757 {N_("Man XBoard F1"), "Man XBoard", ManProc},
758 {"----", NULL, NothingProc},
759 {N_("About XBoard"), "About XBoard", AboutProc},
764 {N_("File"), "File", fileMenu},
765 {N_("Edit"), "Edit", editMenu},
766 {N_("View"), "View", viewMenu},
767 {N_("Mode"), "Mode", modeMenu},
768 {N_("Action"), "Action", actionMenu},
769 {N_("Engine"), "Engine", engineMenu},
770 {N_("Options"), "Options", optionsMenu},
771 {N_("Help"), "Help", helpMenu},
775 #define PAUSE_BUTTON "P"
776 MenuItem buttonBar[] = {
777 {"<<", "<<", ToStartProc},
778 {"<", "<", BackwardProc},
779 {PAUSE_BUTTON, PAUSE_BUTTON, PauseProc},
780 {">", ">", ForwardProc},
781 {">>", ">>", ToEndProc},
785 #define PIECE_MENU_SIZE 18
786 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
787 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
788 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
789 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
790 N_("Empty square"), N_("Clear board") },
791 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
792 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
793 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
794 N_("Empty square"), N_("Clear board") }
796 /* must be in same order as PieceMenuStrings! */
797 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
798 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
799 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
800 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
801 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
802 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
803 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
804 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
805 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
808 #define DROP_MENU_SIZE 6
809 String dropMenuStrings[DROP_MENU_SIZE] = {
810 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
812 /* must be in same order as PieceMenuStrings! */
813 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
814 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
815 WhiteRook, WhiteQueen
823 DropMenuEnables dmEnables[] = {
841 { XtNborderWidth, 0 },
842 { XtNdefaultDistance, 0 },
846 { XtNborderWidth, 0 },
847 { XtNresizable, (XtArgVal) True },
851 { XtNborderWidth, 0 },
857 { XtNjustify, (XtArgVal) XtJustifyRight },
858 { XtNlabel, (XtArgVal) "..." },
859 { XtNresizable, (XtArgVal) True },
860 { XtNresize, (XtArgVal) False }
863 Arg messageArgs[] = {
864 { XtNjustify, (XtArgVal) XtJustifyLeft },
865 { XtNlabel, (XtArgVal) "..." },
866 { XtNresizable, (XtArgVal) True },
867 { XtNresize, (XtArgVal) False }
871 { XtNborderWidth, 0 },
872 { XtNjustify, (XtArgVal) XtJustifyLeft }
875 XtResource clientResources[] = {
876 { "flashCount", "flashCount", XtRInt, sizeof(int),
877 XtOffset(AppDataPtr, flashCount), XtRImmediate,
878 (XtPointer) FLASH_COUNT },
881 XrmOptionDescRec shellOptions[] = {
882 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
883 { "-flash", "flashCount", XrmoptionNoArg, "3" },
884 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
887 XtActionsRec boardActions[] = {
888 { "DrawPosition", DrawPositionProc },
889 { "HandleUserMove", HandleUserMove },
890 { "AnimateUserMove", AnimateUserMove },
891 { "HandlePV", HandlePV },
892 { "SelectPV", SelectPV },
893 { "StopPV", StopPV },
894 { "FileNameAction", FileNameAction },
895 { "AskQuestionProc", AskQuestionProc },
896 { "AskQuestionReplyAction", AskQuestionReplyAction },
897 { "PieceMenuPopup", PieceMenuPopup },
898 { "WhiteClock", WhiteClock },
899 { "BlackClock", BlackClock },
900 { "Iconify", Iconify },
901 { "ResetProc", ResetProc },
902 { "NewVariantProc", NewVariantProc },
903 { "LoadGameProc", LoadGameProc },
904 { "LoadNextGameProc", LoadNextGameProc },
905 { "LoadPrevGameProc", LoadPrevGameProc },
906 { "LoadSelectedProc", LoadSelectedProc },
907 { "SetFilterProc", SetFilterProc },
908 { "ReloadGameProc", ReloadGameProc },
909 { "LoadPositionProc", LoadPositionProc },
910 { "LoadNextPositionProc", LoadNextPositionProc },
911 { "LoadPrevPositionProc", LoadPrevPositionProc },
912 { "ReloadPositionProc", ReloadPositionProc },
913 { "CopyPositionProc", CopyPositionProc },
914 { "PastePositionProc", PastePositionProc },
915 { "CopyGameProc", CopyGameProc },
916 { "PasteGameProc", PasteGameProc },
917 { "SaveGameProc", SaveGameProc },
918 { "SavePositionProc", SavePositionProc },
919 { "MailMoveProc", MailMoveProc },
920 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
921 { "QuitProc", QuitProc },
922 { "MachineWhiteProc", MachineWhiteProc },
923 { "MachineBlackProc", MachineBlackProc },
924 { "AnalysisModeProc", AnalyzeModeProc },
925 { "AnalyzeFileProc", AnalyzeFileProc },
926 { "TwoMachinesProc", TwoMachinesProc },
927 { "IcsClientProc", IcsClientProc },
928 { "EditGameProc", EditGameProc },
929 { "EditPositionProc", EditPositionProc },
930 { "TrainingProc", EditPositionProc },
931 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
932 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
933 { "ShowGameListProc", ShowGameListProc },
934 { "ShowMoveListProc", HistoryShowProc},
935 { "EditTagsProc", EditCommentProc },
936 { "EditCommentProc", EditCommentProc },
937 { "IcsInputBoxProc", IcsInputBoxProc },
938 { "PauseProc", PauseProc },
939 { "AcceptProc", AcceptProc },
940 { "DeclineProc", DeclineProc },
941 { "RematchProc", RematchProc },
942 { "CallFlagProc", CallFlagProc },
943 { "DrawProc", DrawProc },
944 { "AdjournProc", AdjournProc },
945 { "AbortProc", AbortProc },
946 { "ResignProc", ResignProc },
947 { "AdjuWhiteProc", AdjuWhiteProc },
948 { "AdjuBlackProc", AdjuBlackProc },
949 { "AdjuDrawProc", AdjuDrawProc },
950 { "EnterKeyProc", EnterKeyProc },
951 { "UpKeyProc", UpKeyProc },
952 { "DownKeyProc", DownKeyProc },
953 { "StopObservingProc", StopObservingProc },
954 { "StopExaminingProc", StopExaminingProc },
955 { "UploadProc", UploadProc },
956 { "BackwardProc", BackwardProc },
957 { "ForwardProc", ForwardProc },
958 { "ToStartProc", ToStartProc },
959 { "ToEndProc", ToEndProc },
960 { "RevertProc", RevertProc },
961 { "AnnotateProc", AnnotateProc },
962 { "TruncateGameProc", TruncateGameProc },
963 { "MoveNowProc", MoveNowProc },
964 { "RetractMoveProc", RetractMoveProc },
965 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
966 { "UciMenuProc", (XtActionProc) UciMenuProc },
967 { "TimeControlProc", (XtActionProc) TimeControlProc },
968 { "FlipViewProc", FlipViewProc },
969 { "PonderNextMoveProc", PonderNextMoveProc },
970 #ifndef OPTIONSDIALOG
971 { "AlwaysQueenProc", AlwaysQueenProc },
972 { "AnimateDraggingProc", AnimateDraggingProc },
973 { "AnimateMovingProc", AnimateMovingProc },
974 { "AutoflagProc", AutoflagProc },
975 { "AutoflipProc", AutoflipProc },
976 { "BlindfoldProc", BlindfoldProc },
977 { "FlashMovesProc", FlashMovesProc },
979 { "HighlightDraggingProc", HighlightDraggingProc },
981 { "HighlightLastMoveProc", HighlightLastMoveProc },
982 // { "IcsAlarmProc", IcsAlarmProc },
983 { "MoveSoundProc", MoveSoundProc },
984 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
985 { "PopupExitMessageProc", PopupExitMessageProc },
986 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
987 // { "PremoveProc", PremoveProc },
988 { "ShowCoordsProc", ShowCoordsProc },
989 { "ShowThinkingProc", ShowThinkingProc },
990 { "HideThinkingProc", HideThinkingProc },
991 { "TestLegalityProc", TestLegalityProc },
993 { "SaveSettingsProc", SaveSettingsProc },
994 { "SaveOnExitProc", SaveOnExitProc },
995 { "InfoProc", InfoProc },
996 { "ManProc", ManProc },
997 { "HintProc", HintProc },
998 { "BookProc", BookProc },
999 { "AboutGameProc", AboutGameProc },
1000 { "AboutProc", AboutProc },
1001 { "DebugProc", DebugProc },
1002 { "NothingProc", NothingProc },
1003 { "CommentClick", (XtActionProc) CommentClick },
1004 { "CommentPopDown", (XtActionProc) CommentPopDown },
1005 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
1006 { "TagsPopDown", (XtActionProc) TagsPopDown },
1007 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
1008 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
1009 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
1010 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
1011 { "GameListPopDown", (XtActionProc) GameListPopDown },
1012 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
1013 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1014 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
1015 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1016 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1017 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
1018 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
1019 { "GenericPopDown", (XtActionProc) GenericPopDown },
1020 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1023 char globalTranslations[] =
1024 ":<Key>F9: ResignProc() \n \
1025 :Ctrl<Key>n: ResetProc() \n \
1026 :Meta<Key>V: NewVariantProc() \n \
1027 :Ctrl<Key>o: LoadGameProc() \n \
1028 :Meta<Key>Next: LoadNextGameProc() \n \
1029 :Meta<Key>Prior: LoadPrevGameProc() \n \
1030 :Ctrl<Key>s: SaveGameProc() \n \
1031 :Ctrl<Key>c: CopyGameProc() \n \
1032 :Ctrl<Key>v: PasteGameProc() \n \
1033 :Ctrl<Key>O: LoadPositionProc() \n \
1034 :Shift<Key>Next: LoadNextPositionProc() \n \
1035 :Shift<Key>Prior: LoadPrevPositionProc() \n \
1036 :Ctrl<Key>S: SavePositionProc() \n \
1037 :Ctrl<Key>C: CopyPositionProc() \n \
1038 :Ctrl<Key>V: PastePositionProc() \n \
1039 :Ctrl<Key>q: QuitProc() \n \
1040 :Ctrl<Key>w: MachineWhiteProc() \n \
1041 :Ctrl<Key>b: MachineBlackProc() \n \
1042 :Ctrl<Key>t: TwoMachinesProc() \n \
1043 :Ctrl<Key>a: AnalysisModeProc() \n \
1044 :Ctrl<Key>f: AnalyzeFileProc() \n \
1045 :Ctrl<Key>e: EditGameProc() \n \
1046 :Ctrl<Key>E: EditPositionProc() \n \
1047 :Meta<Key>O: EngineOutputProc() \n \
1048 :Meta<Key>E: EvalGraphProc() \n \
1049 :Meta<Key>G: ShowGameListProc() \n \
1050 :Meta<Key>H: ShowMoveListProc() \n \
1051 :<Key>Pause: PauseProc() \n \
1052 :<Key>F3: AcceptProc() \n \
1053 :<Key>F4: DeclineProc() \n \
1054 :<Key>F12: RematchProc() \n \
1055 :<Key>F5: CallFlagProc() \n \
1056 :<Key>F6: DrawProc() \n \
1057 :<Key>F7: AdjournProc() \n \
1058 :<Key>F8: AbortProc() \n \
1059 :<Key>F10: StopObservingProc() \n \
1060 :<Key>F11: StopExaminingProc() \n \
1061 :Meta Ctrl<Key>F12: DebugProc() \n \
1062 :Meta<Key>End: ToEndProc() \n \
1063 :Meta<Key>Right: ForwardProc() \n \
1064 :Meta<Key>Home: ToStartProc() \n \
1065 :Meta<Key>Left: BackwardProc() \n \
1066 :<Key>Home: RevertProc() \n \
1067 :<Key>End: TruncateGameProc() \n \
1068 :Ctrl<Key>m: MoveNowProc() \n \
1069 :Ctrl<Key>x: RetractMoveProc() \n \
1070 :Meta<Key>J: EngineMenuProc() \n \
1071 :Meta<Key>U: UciMenuProc() \n \
1072 :Meta<Key>T: TimeControlProc() \n \
1073 :Ctrl<Key>P: PonderNextMoveProc() \n "
1074 #ifndef OPTIONSDIALOG
1076 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1077 :Ctrl<Key>F: AutoflagProc() \n \
1078 :Ctrl<Key>A: AnimateMovingProc() \n \
1079 :Ctrl<Key>L: TestLegalityProc() \n \
1080 :Ctrl<Key>H: HideThinkingProc() \n "
1083 :<Key>-: Iconify() \n \
1084 :<Key>F1: ManProc() \n \
1085 :<Key>F2: FlipViewProc() \n \
1086 <KeyDown>.: BackwardProc() \n \
1087 <KeyUp>.: ForwardProc() \n \
1088 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1089 \"Send to chess program:\",,1) \n \
1090 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1091 \"Send to second chess program:\",,2) \n";
1093 char boardTranslations[] =
1094 "<Btn1Down>: HandleUserMove(0) \n \
1095 Shift<Btn1Up>: HandleUserMove(1) \n \
1096 <Btn1Up>: HandleUserMove(0) \n \
1097 <Btn1Motion>: AnimateUserMove() \n \
1098 <Btn3Motion>: HandlePV() \n \
1099 <Btn3Up>: PieceMenuPopup(menuB) \n \
1100 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1101 PieceMenuPopup(menuB) \n \
1102 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1103 PieceMenuPopup(menuW) \n \
1104 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1105 PieceMenuPopup(menuW) \n \
1106 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1107 PieceMenuPopup(menuB) \n";
1109 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1110 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1112 char ICSInputTranslations[] =
1113 "<Key>Up: UpKeyProc() \n "
1114 "<Key>Down: DownKeyProc() \n "
1115 "<Key>Return: EnterKeyProc() \n";
1117 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1118 // as the widget is destroyed before the up-click can call extend-end
1119 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1121 String xboardResources[] = {
1122 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1123 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1124 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1129 /* Max possible square size */
1130 #define MAXSQSIZE 256
1132 static int xpm_avail[MAXSQSIZE];
1134 #ifdef HAVE_DIR_STRUCT
1136 /* Extract piece size from filename */
1138 xpm_getsize(name, len, ext)
1149 if ((p=strchr(name, '.')) == NULL ||
1150 StrCaseCmp(p+1, ext) != 0)
1156 while (*p && isdigit(*p))
1163 /* Setup xpm_avail */
1165 xpm_getavail(dirname, ext)
1173 for (i=0; i<MAXSQSIZE; ++i)
1176 if (appData.debugMode)
1177 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1179 dir = opendir(dirname);
1182 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1183 programName, dirname);
1187 while ((ent=readdir(dir)) != NULL) {
1188 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1189 if (i > 0 && i < MAXSQSIZE)
1199 xpm_print_avail(fp, ext)
1205 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1206 for (i=1; i<MAXSQSIZE; ++i) {
1212 /* Return XPM piecesize closest to size */
1214 xpm_closest_to(dirname, size, ext)
1220 int sm_diff = MAXSQSIZE;
1224 xpm_getavail(dirname, ext);
1226 if (appData.debugMode)
1227 xpm_print_avail(stderr, ext);
1229 for (i=1; i<MAXSQSIZE; ++i) {
1232 diff = (diff<0) ? -diff : diff;
1233 if (diff < sm_diff) {
1241 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1247 #else /* !HAVE_DIR_STRUCT */
1248 /* If we are on a system without a DIR struct, we can't
1249 read the directory, so we can't collect a list of
1250 filenames, etc., so we can't do any size-fitting. */
1252 xpm_closest_to(dirname, size, ext)
1257 fprintf(stderr, _("\
1258 Warning: No DIR structure found on this system --\n\
1259 Unable to autosize for XPM/XIM pieces.\n\
1260 Please report this error to frankm@hiwaay.net.\n\
1261 Include system type & operating system in message.\n"));
1264 #endif /* HAVE_DIR_STRUCT */
1266 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1267 "magenta", "cyan", "white" };
1271 TextColors textColors[(int)NColorClasses];
1273 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1275 parse_color(str, which)
1279 char *p, buf[100], *d;
1282 if (strlen(str) > 99) /* watch bounds on buf */
1287 for (i=0; i<which; ++i) {
1294 /* Could be looking at something like:
1296 .. in which case we want to stop on a comma also */
1297 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1301 return -1; /* Use default for empty field */
1304 if (which == 2 || isdigit(*p))
1307 while (*p && isalpha(*p))
1312 for (i=0; i<8; ++i) {
1313 if (!StrCaseCmp(buf, cnames[i]))
1314 return which? (i+40) : (i+30);
1316 if (!StrCaseCmp(buf, "default")) return -1;
1318 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1323 parse_cpair(cc, str)
1327 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1328 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1333 /* bg and attr are optional */
1334 textColors[(int)cc].bg = parse_color(str, 1);
1335 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1336 textColors[(int)cc].attr = 0;
1342 /* Arrange to catch delete-window events */
1343 Atom wm_delete_window;
1345 CatchDeleteWindow(Widget w, String procname)
1348 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1349 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1350 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1357 XtSetArg(args[0], XtNiconic, False);
1358 XtSetValues(shellWidget, args, 1);
1360 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1363 //---------------------------------------------------------------------------------------------------------
1364 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1367 #define CW_USEDEFAULT (1<<31)
1368 #define ICS_TEXT_MENU_SIZE 90
1369 #define DEBUG_FILE "xboard.debug"
1370 #define SetCurrentDirectory chdir
1371 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1375 // these two must some day move to frontend.h, when they are implemented
1376 Boolean GameListIsUp();
1378 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1381 // front-end part of option handling
1383 // [HGM] This platform-dependent table provides the location for storing the color info
1384 extern char *crWhite, * crBlack;
1388 &appData.whitePieceColor,
1389 &appData.blackPieceColor,
1390 &appData.lightSquareColor,
1391 &appData.darkSquareColor,
1392 &appData.highlightSquareColor,
1393 &appData.premoveHighlightColor,
1394 &appData.lowTimeWarningColor,
1405 // [HGM] font: keep a font for each square size, even non-stndard ones
1406 #define NUM_SIZES 18
1407 #define MAX_SIZE 130
1408 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1409 char *fontTable[NUM_FONTS][MAX_SIZE];
1412 ParseFont(char *name, int number)
1413 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1415 if(sscanf(name, "size%d:", &size)) {
1416 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1417 // defer processing it until we know if it matches our board size
1418 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1419 fontTable[number][size] = strdup(strchr(name, ':')+1);
1420 fontValid[number][size] = True;
1425 case 0: // CLOCK_FONT
1426 appData.clockFont = strdup(name);
1428 case 1: // MESSAGE_FONT
1429 appData.font = strdup(name);
1431 case 2: // COORD_FONT
1432 appData.coordFont = strdup(name);
1437 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1442 { // only 2 fonts currently
1443 appData.clockFont = CLOCK_FONT_NAME;
1444 appData.coordFont = COORD_FONT_NAME;
1445 appData.font = DEFAULT_FONT_NAME;
1450 { // no-op, until we identify the code for this already in XBoard and move it here
1454 ParseColor(int n, char *name)
1455 { // in XBoard, just copy the color-name string
1456 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1460 ParseTextAttribs(ColorClass cc, char *s)
1462 (&appData.colorShout)[cc] = strdup(s);
1466 ParseBoardSize(void *addr, char *name)
1468 appData.boardSize = strdup(name);
1473 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1477 SetCommPortDefaults()
1478 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1481 // [HGM] args: these three cases taken out to stay in front-end
1483 SaveFontArg(FILE *f, ArgDescriptor *ad)
1486 int i, n = (int)(intptr_t)ad->argLoc;
1488 case 0: // CLOCK_FONT
1489 name = appData.clockFont;
1491 case 1: // MESSAGE_FONT
1492 name = appData.font;
1494 case 2: // COORD_FONT
1495 name = appData.coordFont;
1500 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1501 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1502 fontTable[n][squareSize] = strdup(name);
1503 fontValid[n][squareSize] = True;
1506 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1507 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1512 { // nothing to do, as the sounds are at all times represented by their text-string names already
1516 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1517 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1518 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
1522 SaveColor(FILE *f, ArgDescriptor *ad)
1523 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1524 if(colorVariable[(int)(intptr_t)ad->argLoc])
1525 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
1529 SaveBoardSize(FILE *f, char *name, void *addr)
1530 { // wrapper to shield back-end from BoardSize & sizeInfo
1531 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1535 ParseCommPortSettings(char *s)
1536 { // no such option in XBoard (yet)
1539 extern Widget engineOutputShell;
1540 extern Widget tagsShell, editTagsShell;
1542 GetActualPlacement(Widget wg, WindowPlacement *wp)
1552 XtSetArg(args[i], XtNx, &x); i++;
1553 XtSetArg(args[i], XtNy, &y); i++;
1554 XtSetArg(args[i], XtNwidth, &w); i++;
1555 XtSetArg(args[i], XtNheight, &h); i++;
1556 XtGetValues(wg, args, i);
1565 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1566 // In XBoard this will have to wait until awareness of window parameters is implemented
1567 GetActualPlacement(shellWidget, &wpMain);
1568 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1569 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1570 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1571 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1572 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1573 else GetActualPlacement(editShell, &wpComment);
1574 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1575 else GetActualPlacement(editTagsShell, &wpTags);
1579 PrintCommPortSettings(FILE *f, char *name)
1580 { // This option does not exist in XBoard
1584 MySearchPath(char *installDir, char *name, char *fullname)
1585 { // just append installDir and name. Perhaps ExpandPath should be used here?
1586 name = ExpandPathName(name);
1587 if(name && name[0] == '/')
1588 safeStrCpy(fullname, name, MSG_SIZ );
1590 sprintf(fullname, "%s%c%s", installDir, '/', name);
1596 MyGetFullPathName(char *name, char *fullname)
1597 { // should use ExpandPath?
1598 name = ExpandPathName(name);
1599 safeStrCpy(fullname, name, MSG_SIZ );
1604 EnsureOnScreen(int *x, int *y, int minX, int minY)
1611 { // [HGM] args: allows testing if main window is realized from back-end
1612 return xBoardWindow != 0;
1616 PopUpStartupDialog()
1617 { // start menu not implemented in XBoard
1621 ConvertToLine(int argc, char **argv)
1623 static char line[128*1024], buf[1024];
1627 for(i=1; i<argc; i++)
1629 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1630 && argv[i][0] != '{' )
1631 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1633 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1634 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1637 line[strlen(line)-1] = NULLCHAR;
1641 //--------------------------------------------------------------------------------------------
1643 extern Boolean twoBoards, partnerUp;
1646 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1648 #define BoardSize int
1649 void InitDrawingSizes(BoardSize boardSize, int flags)
1650 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1651 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1653 XtGeometryResult gres;
1656 if(!formWidget) return;
1659 * Enable shell resizing.
1661 shellArgs[0].value = (XtArgVal) &w;
1662 shellArgs[1].value = (XtArgVal) &h;
1663 XtGetValues(shellWidget, shellArgs, 2);
1665 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1666 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1667 XtSetValues(shellWidget, &shellArgs[2], 4);
1669 XtSetArg(args[0], XtNdefaultDistance, &sep);
1670 XtGetValues(formWidget, args, 1);
1672 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1673 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1674 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1676 hOffset = boardWidth + 10;
1677 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1678 secondSegments[i] = gridSegments[i];
1679 secondSegments[i].x1 += hOffset;
1680 secondSegments[i].x2 += hOffset;
1683 XtSetArg(args[0], XtNwidth, boardWidth);
1684 XtSetArg(args[1], XtNheight, boardHeight);
1685 XtSetValues(boardWidget, args, 2);
1687 timerWidth = (boardWidth - sep) / 2;
1688 XtSetArg(args[0], XtNwidth, timerWidth);
1689 XtSetValues(whiteTimerWidget, args, 1);
1690 XtSetValues(blackTimerWidget, args, 1);
1692 XawFormDoLayout(formWidget, False);
1694 if (appData.titleInWindow) {
1696 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1697 XtSetArg(args[i], XtNheight, &h); i++;
1698 XtGetValues(titleWidget, args, i);
1700 w = boardWidth - 2*bor;
1702 XtSetArg(args[0], XtNwidth, &w);
1703 XtGetValues(menuBarWidget, args, 1);
1704 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1707 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1708 if (gres != XtGeometryYes && appData.debugMode) {
1710 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1711 programName, gres, w, h, wr, hr);
1715 XawFormDoLayout(formWidget, True);
1718 * Inhibit shell resizing.
1720 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1721 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1722 shellArgs[4].value = shellArgs[2].value = w;
1723 shellArgs[5].value = shellArgs[3].value = h;
1724 XtSetValues(shellWidget, &shellArgs[0], 6);
1726 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1729 for(i=0; i<4; i++) {
1731 for(p=0; p<=(int)WhiteKing; p++)
1732 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1733 if(gameInfo.variant == VariantShogi) {
1734 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1735 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1736 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1737 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1738 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1741 if(gameInfo.variant == VariantGothic) {
1742 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1745 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1746 xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
1747 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1750 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1751 for(p=0; p<=(int)WhiteKing; p++)
1752 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1753 if(gameInfo.variant == VariantShogi) {
1754 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1755 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1756 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1757 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1758 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1761 if(gameInfo.variant == VariantGothic) {
1762 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1765 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1766 ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
1767 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1772 for(i=0; i<2; i++) {
1774 for(p=0; p<=(int)WhiteKing; p++)
1775 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1776 if(gameInfo.variant == VariantShogi) {
1777 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1778 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1779 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1780 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1781 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1784 if(gameInfo.variant == VariantGothic) {
1785 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1788 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1789 pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
1790 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1800 void ParseIcsTextColors()
1801 { // [HGM] tken out of main(), so it can be called from ICS-Options dialog
1802 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1803 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1804 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1805 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1806 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1807 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1808 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1809 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1810 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1811 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1813 if (appData.colorize) {
1815 _("%s: can't parse color names; disabling colorization\n"),
1818 appData.colorize = FALSE;
1823 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
1824 XrmValue vFrom, vTo;
1825 int forceMono = False;
1827 if (!appData.monoMode) {
1828 vFrom.addr = (caddr_t) appData.lightSquareColor;
1829 vFrom.size = strlen(appData.lightSquareColor);
1830 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1831 if (vTo.addr == NULL) {
1832 appData.monoMode = True;
1835 lightSquareColor = *(Pixel *) vTo.addr;
1838 if (!appData.monoMode) {
1839 vFrom.addr = (caddr_t) appData.darkSquareColor;
1840 vFrom.size = strlen(appData.darkSquareColor);
1841 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1842 if (vTo.addr == NULL) {
1843 appData.monoMode = True;
1846 darkSquareColor = *(Pixel *) vTo.addr;
1849 if (!appData.monoMode) {
1850 vFrom.addr = (caddr_t) appData.whitePieceColor;
1851 vFrom.size = strlen(appData.whitePieceColor);
1852 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1853 if (vTo.addr == NULL) {
1854 appData.monoMode = True;
1857 whitePieceColor = *(Pixel *) vTo.addr;
1860 if (!appData.monoMode) {
1861 vFrom.addr = (caddr_t) appData.blackPieceColor;
1862 vFrom.size = strlen(appData.blackPieceColor);
1863 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1864 if (vTo.addr == NULL) {
1865 appData.monoMode = True;
1868 blackPieceColor = *(Pixel *) vTo.addr;
1872 if (!appData.monoMode) {
1873 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1874 vFrom.size = strlen(appData.highlightSquareColor);
1875 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1876 if (vTo.addr == NULL) {
1877 appData.monoMode = True;
1880 highlightSquareColor = *(Pixel *) vTo.addr;
1884 if (!appData.monoMode) {
1885 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1886 vFrom.size = strlen(appData.premoveHighlightColor);
1887 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1888 if (vTo.addr == NULL) {
1889 appData.monoMode = True;
1892 premoveHighlightColor = *(Pixel *) vTo.addr;
1903 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1904 XSetWindowAttributes window_attributes;
1906 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1907 XrmValue vFrom, vTo;
1908 XtGeometryResult gres;
1911 int forceMono = False;
1913 srandom(time(0)); // [HGM] book: make random truly random
1915 setbuf(stdout, NULL);
1916 setbuf(stderr, NULL);
1919 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1920 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1924 programName = strrchr(argv[0], '/');
1925 if (programName == NULL)
1926 programName = argv[0];
1931 XtSetLanguageProc(NULL, NULL, NULL);
1932 bindtextdomain(PACKAGE, LOCALEDIR);
1933 textdomain(PACKAGE);
1937 XtAppInitialize(&appContext, "XBoard", shellOptions,
1938 XtNumber(shellOptions),
1939 &argc, argv, xboardResources, NULL, 0);
1940 appData.boardSize = "";
1941 InitAppData(ConvertToLine(argc, argv));
1943 if (p == NULL) p = "/tmp";
1944 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1945 gameCopyFilename = (char*) malloc(i);
1946 gamePasteFilename = (char*) malloc(i);
1947 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1948 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1950 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1951 clientResources, XtNumber(clientResources),
1954 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1955 static char buf[MSG_SIZ];
1956 EscapeExpand(buf, appData.initString);
1957 appData.initString = strdup(buf);
1958 EscapeExpand(buf, appData.secondInitString);
1959 appData.secondInitString = strdup(buf);
1960 EscapeExpand(buf, appData.firstComputerString);
1961 appData.firstComputerString = strdup(buf);
1962 EscapeExpand(buf, appData.secondComputerString);
1963 appData.secondComputerString = strdup(buf);
1966 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1969 if (chdir(chessDir) != 0) {
1970 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1976 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1977 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1978 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1979 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1982 setbuf(debugFP, NULL);
1985 /* [HGM,HR] make sure board size is acceptable */
1986 if(appData.NrFiles > BOARD_FILES ||
1987 appData.NrRanks > BOARD_RANKS )
1988 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1991 /* This feature does not work; animation needs a rewrite */
1992 appData.highlightDragging = FALSE;
1996 xDisplay = XtDisplay(shellWidget);
1997 xScreen = DefaultScreen(xDisplay);
1998 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
2000 gameInfo.variant = StringToVariant(appData.variant);
2001 InitPosition(FALSE);
2004 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
2006 if (isdigit(appData.boardSize[0])) {
2007 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
2008 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
2009 &fontPxlSize, &smallLayout, &tinyLayout);
2011 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
2012 programName, appData.boardSize);
2016 /* Find some defaults; use the nearest known size */
2017 SizeDefaults *szd, *nearest;
2018 int distance = 99999;
2019 nearest = szd = sizeDefaults;
2020 while (szd->name != NULL) {
2021 if (abs(szd->squareSize - squareSize) < distance) {
2023 distance = abs(szd->squareSize - squareSize);
2024 if (distance == 0) break;
2028 if (i < 2) lineGap = nearest->lineGap;
2029 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
2030 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
2031 if (i < 5) fontPxlSize = nearest->fontPxlSize;
2032 if (i < 6) smallLayout = nearest->smallLayout;
2033 if (i < 7) tinyLayout = nearest->tinyLayout;
2036 SizeDefaults *szd = sizeDefaults;
2037 if (*appData.boardSize == NULLCHAR) {
2038 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
2039 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
2042 if (szd->name == NULL) szd--;
2043 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
2045 while (szd->name != NULL &&
2046 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
2047 if (szd->name == NULL) {
2048 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
2049 programName, appData.boardSize);
2053 squareSize = szd->squareSize;
2054 lineGap = szd->lineGap;
2055 clockFontPxlSize = szd->clockFontPxlSize;
2056 coordFontPxlSize = szd->coordFontPxlSize;
2057 fontPxlSize = szd->fontPxlSize;
2058 smallLayout = szd->smallLayout;
2059 tinyLayout = szd->tinyLayout;
2060 // [HGM] font: use defaults from settings file if available and not overruled
2062 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
2063 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
2064 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
2065 appData.font = fontTable[MESSAGE_FONT][squareSize];
2066 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
2067 appData.coordFont = fontTable[COORD_FONT][squareSize];
2069 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
2070 if (strlen(appData.pixmapDirectory) > 0) {
2071 p = ExpandPathName(appData.pixmapDirectory);
2073 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
2074 appData.pixmapDirectory);
2077 if (appData.debugMode) {
2078 fprintf(stderr, _("\
2079 XBoard square size (hint): %d\n\
2080 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
2082 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
2083 if (appData.debugMode) {
2084 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
2087 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
2089 /* [HR] height treated separately (hacked) */
2090 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
2091 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
2092 if (appData.showJail == 1) {
2093 /* Jail on top and bottom */
2094 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2095 XtSetArg(boardArgs[2], XtNheight,
2096 boardHeight + 2*(lineGap + squareSize));
2097 } else if (appData.showJail == 2) {
2099 XtSetArg(boardArgs[1], XtNwidth,
2100 boardWidth + 2*(lineGap + squareSize));
2101 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2104 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2105 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2109 * Determine what fonts to use.
2111 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2112 clockFontID = XLoadFont(xDisplay, appData.clockFont);
2113 clockFontStruct = XQueryFont(xDisplay, clockFontID);
2114 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2115 coordFontID = XLoadFont(xDisplay, appData.coordFont);
2116 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2117 appData.font = FindFont(appData.font, fontPxlSize);
2118 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
2119 countFontStruct = XQueryFont(xDisplay, countFontID);
2120 // appData.font = FindFont(appData.font, fontPxlSize);
2122 xdb = XtDatabase(xDisplay);
2123 XrmPutStringResource(&xdb, "*font", appData.font);
2126 * Detect if there are not enough colors available and adapt.
2128 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2129 appData.monoMode = True;
2132 forceMono = MakeColors();
2135 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2138 if (appData.bitmapDirectory == NULL ||
2139 appData.bitmapDirectory[0] == NULLCHAR)
2140 appData.bitmapDirectory = DEF_BITMAP_DIR;
2143 if (appData.lowTimeWarning && !appData.monoMode) {
2144 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2145 vFrom.size = strlen(appData.lowTimeWarningColor);
2146 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2147 if (vTo.addr == NULL)
2148 appData.monoMode = True;
2150 lowTimeWarningColor = *(Pixel *) vTo.addr;
2153 if (appData.monoMode && appData.debugMode) {
2154 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2155 (unsigned long) XWhitePixel(xDisplay, xScreen),
2156 (unsigned long) XBlackPixel(xDisplay, xScreen));
2159 ParseIcsTextColors();
2160 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2161 textColors[ColorNone].attr = 0;
2163 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2169 layoutName = "tinyLayout";
2170 } else if (smallLayout) {
2171 layoutName = "smallLayout";
2173 layoutName = "normalLayout";
2175 /* Outer layoutWidget is there only to provide a name for use in
2176 resources that depend on the layout style */
2178 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2179 layoutArgs, XtNumber(layoutArgs));
2181 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2182 formArgs, XtNumber(formArgs));
2183 XtSetArg(args[0], XtNdefaultDistance, &sep);
2184 XtGetValues(formWidget, args, 1);
2187 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2188 XtSetArg(args[0], XtNtop, XtChainTop);
2189 XtSetArg(args[1], XtNbottom, XtChainTop);
2190 XtSetArg(args[2], XtNright, XtChainLeft);
2191 XtSetValues(menuBarWidget, args, 3);
2193 widgetList[j++] = whiteTimerWidget =
2194 XtCreateWidget("whiteTime", labelWidgetClass,
2195 formWidget, timerArgs, XtNumber(timerArgs));
2196 XtSetArg(args[0], XtNfont, clockFontStruct);
2197 XtSetArg(args[1], XtNtop, XtChainTop);
2198 XtSetArg(args[2], XtNbottom, XtChainTop);
2199 XtSetValues(whiteTimerWidget, args, 3);
2201 widgetList[j++] = blackTimerWidget =
2202 XtCreateWidget("blackTime", labelWidgetClass,
2203 formWidget, timerArgs, XtNumber(timerArgs));
2204 XtSetArg(args[0], XtNfont, clockFontStruct);
2205 XtSetArg(args[1], XtNtop, XtChainTop);
2206 XtSetArg(args[2], XtNbottom, XtChainTop);
2207 XtSetValues(blackTimerWidget, args, 3);
2209 if (appData.titleInWindow) {
2210 widgetList[j++] = titleWidget =
2211 XtCreateWidget("title", labelWidgetClass, formWidget,
2212 titleArgs, XtNumber(titleArgs));
2213 XtSetArg(args[0], XtNtop, XtChainTop);
2214 XtSetArg(args[1], XtNbottom, XtChainTop);
2215 XtSetValues(titleWidget, args, 2);
2218 if (appData.showButtonBar) {
2219 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2220 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2221 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2222 XtSetArg(args[2], XtNtop, XtChainTop);
2223 XtSetArg(args[3], XtNbottom, XtChainTop);
2224 XtSetValues(buttonBarWidget, args, 4);
2227 widgetList[j++] = messageWidget =
2228 XtCreateWidget("message", labelWidgetClass, formWidget,
2229 messageArgs, XtNumber(messageArgs));
2230 XtSetArg(args[0], XtNtop, XtChainTop);
2231 XtSetArg(args[1], XtNbottom, XtChainTop);
2232 XtSetValues(messageWidget, args, 2);
2234 widgetList[j++] = boardWidget =
2235 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2236 XtNumber(boardArgs));
2238 XtManageChildren(widgetList, j);
2240 timerWidth = (boardWidth - sep) / 2;
2241 XtSetArg(args[0], XtNwidth, timerWidth);
2242 XtSetValues(whiteTimerWidget, args, 1);
2243 XtSetValues(blackTimerWidget, args, 1);
2245 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2246 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2247 XtGetValues(whiteTimerWidget, args, 2);
2249 if (appData.showButtonBar) {
2250 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2251 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2252 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2256 * formWidget uses these constraints but they are stored
2260 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2261 XtSetValues(menuBarWidget, args, i);
2262 if (appData.titleInWindow) {
2265 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2266 XtSetValues(whiteTimerWidget, args, i);
2268 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2269 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2270 XtSetValues(blackTimerWidget, args, i);
2272 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2273 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2274 XtSetValues(titleWidget, args, i);
2276 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2277 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2278 XtSetValues(messageWidget, args, i);
2279 if (appData.showButtonBar) {
2281 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2282 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2283 XtSetValues(buttonBarWidget, args, i);
2287 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2288 XtSetValues(whiteTimerWidget, args, i);
2290 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2291 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2292 XtSetValues(blackTimerWidget, args, i);
2294 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2295 XtSetValues(titleWidget, args, i);
2297 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2298 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2299 XtSetValues(messageWidget, args, i);
2300 if (appData.showButtonBar) {
2302 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2303 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2304 XtSetValues(buttonBarWidget, args, i);
2309 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2310 XtSetValues(whiteTimerWidget, args, i);
2312 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2313 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2314 XtSetValues(blackTimerWidget, args, i);
2316 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2317 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2318 XtSetValues(messageWidget, args, i);
2319 if (appData.showButtonBar) {
2321 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2322 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2323 XtSetValues(buttonBarWidget, args, i);
2327 XtSetArg(args[0], XtNfromVert, messageWidget);
2328 XtSetArg(args[1], XtNtop, XtChainTop);
2329 XtSetArg(args[2], XtNbottom, XtChainBottom);
2330 XtSetArg(args[3], XtNleft, XtChainLeft);
2331 XtSetArg(args[4], XtNright, XtChainRight);
2332 XtSetValues(boardWidget, args, 5);
2334 XtRealizeWidget(shellWidget);
2337 XtSetArg(args[0], XtNx, wpMain.x);
2338 XtSetArg(args[1], XtNy, wpMain.y);
2339 XtSetValues(shellWidget, args, 2);
2343 * Correct the width of the message and title widgets.
2344 * It is not known why some systems need the extra fudge term.
2345 * The value "2" is probably larger than needed.
2347 XawFormDoLayout(formWidget, False);
2349 #define WIDTH_FUDGE 2
2351 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2352 XtSetArg(args[i], XtNheight, &h); i++;
2353 XtGetValues(messageWidget, args, i);
2354 if (appData.showButtonBar) {
2356 XtSetArg(args[i], XtNwidth, &w); i++;
2357 XtGetValues(buttonBarWidget, args, i);
2358 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2360 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2363 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2364 if (gres != XtGeometryYes && appData.debugMode) {
2365 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2366 programName, gres, w, h, wr, hr);
2369 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2370 /* The size used for the child widget in layout lags one resize behind
2371 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2373 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2374 if (gres != XtGeometryYes && appData.debugMode) {
2375 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2376 programName, gres, w, h, wr, hr);
2379 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2380 XtSetArg(args[1], XtNright, XtChainRight);
2381 XtSetValues(messageWidget, args, 2);
2383 if (appData.titleInWindow) {
2385 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2386 XtSetArg(args[i], XtNheight, &h); i++;
2387 XtGetValues(titleWidget, args, i);
2389 w = boardWidth - 2*bor;
2391 XtSetArg(args[0], XtNwidth, &w);
2392 XtGetValues(menuBarWidget, args, 1);
2393 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2396 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2397 if (gres != XtGeometryYes && appData.debugMode) {
2399 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2400 programName, gres, w, h, wr, hr);
2403 XawFormDoLayout(formWidget, True);
2405 xBoardWindow = XtWindow(boardWidget);
2407 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2408 // not need to go into InitDrawingSizes().
2412 * Create X checkmark bitmap and initialize option menu checks.
2414 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2415 checkmark_bits, checkmark_width, checkmark_height);
2416 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2417 #ifndef OPTIONSDIALOG
2418 if (appData.alwaysPromoteToQueen) {
2419 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2422 if (appData.animateDragging) {
2423 XtSetValues(XtNameToWidget(menuBarWidget,
2424 "menuOptions.Animate Dragging"),
2427 if (appData.animate) {
2428 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2431 if (appData.autoCallFlag) {
2432 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2435 if (appData.autoFlipView) {
2436 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2439 if (appData.blindfold) {
2440 XtSetValues(XtNameToWidget(menuBarWidget,
2441 "menuOptions.Blindfold"), args, 1);
2443 if (appData.flashCount > 0) {
2444 XtSetValues(XtNameToWidget(menuBarWidget,
2445 "menuOptions.Flash Moves"),
2449 if (appData.highlightDragging) {
2450 XtSetValues(XtNameToWidget(menuBarWidget,
2451 "menuOptions.Highlight Dragging"),
2455 if (appData.highlightLastMove) {
2456 XtSetValues(XtNameToWidget(menuBarWidget,
2457 "menuOptions.Highlight Last Move"),
2460 if (appData.highlightMoveWithArrow) {
2461 XtSetValues(XtNameToWidget(menuBarWidget,
2462 "menuOptions.Arrow"),
2465 // if (appData.icsAlarm) {
2466 // XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2469 if (appData.ringBellAfterMoves) {
2470 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2473 if (appData.oneClick) {
2474 XtSetValues(XtNameToWidget(menuBarWidget,
2475 "menuOptions.OneClick"), args, 1);
2477 if (appData.periodicUpdates) {
2478 XtSetValues(XtNameToWidget(menuBarWidget,
2479 "menuOptions.Periodic Updates"), args, 1);
2481 if (appData.ponderNextMove) {
2482 XtSetValues(XtNameToWidget(menuBarWidget,
2483 "menuOptions.Ponder Next Move"), args, 1);
2485 if (appData.popupExitMessage) {
2486 XtSetValues(XtNameToWidget(menuBarWidget,
2487 "menuOptions.Popup Exit Message"), args, 1);
2489 if (appData.popupMoveErrors) {
2490 XtSetValues(XtNameToWidget(menuBarWidget,
2491 "menuOptions.Popup Move Errors"), args, 1);
2493 // if (appData.premove) {
2494 // XtSetValues(XtNameToWidget(menuBarWidget,
2495 // "menuOptions.Premove"), args, 1);
2497 if (appData.showCoords) {
2498 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2501 if (appData.hideThinkingFromHuman) {
2502 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2505 if (appData.testLegality) {
2506 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2510 if (saveSettingsOnExit) {
2511 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2518 ReadBitmap(&wIconPixmap, "icon_white.bm",
2519 icon_white_bits, icon_white_width, icon_white_height);
2520 ReadBitmap(&bIconPixmap, "icon_black.bm",
2521 icon_black_bits, icon_black_width, icon_black_height);
2522 iconPixmap = wIconPixmap;
2524 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2525 XtSetValues(shellWidget, args, i);
2528 * Create a cursor for the board widget.
2530 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2531 XChangeWindowAttributes(xDisplay, xBoardWindow,
2532 CWCursor, &window_attributes);
2535 * Inhibit shell resizing.
2537 shellArgs[0].value = (XtArgVal) &w;
2538 shellArgs[1].value = (XtArgVal) &h;
2539 XtGetValues(shellWidget, shellArgs, 2);
2540 shellArgs[4].value = shellArgs[2].value = w;
2541 shellArgs[5].value = shellArgs[3].value = h;
2542 XtSetValues(shellWidget, &shellArgs[2], 4);
2543 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2544 marginH = h - boardHeight;
2546 CatchDeleteWindow(shellWidget, "QuitProc");
2551 if (appData.bitmapDirectory[0] != NULLCHAR) {
2555 CreateXPMBoard(appData.liteBackTextureFile, 1);
2556 CreateXPMBoard(appData.darkBackTextureFile, 0);
2560 /* Create regular pieces */
2561 if (!useImages) CreatePieces();
2566 if (appData.animate || appData.animateDragging)
2569 XtAugmentTranslations(formWidget,
2570 XtParseTranslationTable(globalTranslations));
2571 XtAugmentTranslations(boardWidget,
2572 XtParseTranslationTable(boardTranslations));
2573 XtAugmentTranslations(whiteTimerWidget,
2574 XtParseTranslationTable(whiteTranslations));
2575 XtAugmentTranslations(blackTimerWidget,
2576 XtParseTranslationTable(blackTranslations));
2578 /* Why is the following needed on some versions of X instead
2579 * of a translation? */
2580 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2581 (XtEventHandler) EventProc, NULL);
2584 /* [AS] Restore layout */
2585 if( wpMoveHistory.visible ) {
2589 if( wpEvalGraph.visible )
2594 if( wpEngineOutput.visible ) {
2595 EngineOutputPopUp();
2600 if (errorExitStatus == -1) {
2601 if (appData.icsActive) {
2602 /* We now wait until we see "login:" from the ICS before
2603 sending the logon script (problems with timestamp otherwise) */
2604 /*ICSInitScript();*/
2605 if (appData.icsInputBox) ICSInputBoxPopUp();
2609 signal(SIGWINCH, TermSizeSigHandler);
2611 signal(SIGINT, IntSigHandler);
2612 signal(SIGTERM, IntSigHandler);
2613 if (*appData.cmailGameName != NULLCHAR) {
2614 signal(SIGUSR1, CmailSigHandler);
2617 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2619 XtSetKeyboardFocus(shellWidget, formWidget);
2621 XtAppMainLoop(appContext);
2622 if (appData.debugMode) fclose(debugFP); // [DM] debug
2629 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2630 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2632 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2633 unlink(gameCopyFilename);
2634 unlink(gamePasteFilename);
2637 RETSIGTYPE TermSizeSigHandler(int sig)
2650 CmailSigHandler(sig)
2656 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2658 /* Activate call-back function CmailSigHandlerCallBack() */
2659 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2661 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2665 CmailSigHandlerCallBack(isr, closure, message, count, error)
2673 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2675 /**** end signal code ****/
2681 /* try to open the icsLogon script, either in the location given
2682 * or in the users HOME directory
2689 f = fopen(appData.icsLogon, "r");
2692 homedir = getenv("HOME");
2693 if (homedir != NULL)
2695 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2696 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2697 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2698 f = fopen(buf, "r");
2703 ProcessICSInitScript(f);
2705 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2714 EditCommentPopDown();
2729 if (!menuBarWidget) return;
2730 w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2732 DisplayError("menuEdit.Revert", 0);
2734 XtSetSensitive(w, !grey);
2736 w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2738 DisplayError("menuEdit.Annotate", 0);
2740 XtSetSensitive(w, !grey);
2745 SetMenuEnables(enab)
2749 if (!menuBarWidget) return;
2750 while (enab->name != NULL) {
2751 w = XtNameToWidget(menuBarWidget, enab->name);
2753 DisplayError(enab->name, 0);
2755 XtSetSensitive(w, enab->value);
2761 Enables icsEnables[] = {
2762 { "menuFile.Mail Move", False },
2763 { "menuFile.Reload CMail Message", False },
2764 { "menuMode.Machine Black", False },
2765 { "menuMode.Machine White", False },
2766 { "menuMode.Analysis Mode", False },
2767 { "menuMode.Analyze File", False },
2768 { "menuMode.Two Machines", False },
2769 { "menuMode.Machine Match", False },
2771 { "menuEngine.Hint", False },
2772 { "menuEngine.Book", False },
2773 { "menuEngine.Move Now", False },
2774 #ifndef OPTIONSDIALOG
2775 { "menuOptions.Periodic Updates", False },
2776 { "menuOptions.Hide Thinking", False },
2777 { "menuOptions.Ponder Next Move", False },
2779 { "menuEngine.Engine #1 Settings", False },
2781 { "menuEngine.Engine #2 Settings", False },
2782 { "menuEdit.Annotate", False },
2786 Enables ncpEnables[] = {
2787 { "menuFile.Mail Move", False },
2788 { "menuFile.Reload CMail Message", False },
2789 { "menuMode.Machine White", False },
2790 { "menuMode.Machine Black", False },
2791 { "menuMode.Analysis Mode", False },
2792 { "menuMode.Analyze File", False },
2793 { "menuMode.Two Machines", False },
2794 { "menuMode.Machine Match", False },
2795 { "menuMode.ICS Client", False },
2796 { "menuView.ICS Input Box", False },
2797 { "Action", False },
2798 { "menuEdit.Revert", False },
2799 { "menuEdit.Annotate", False },
2800 { "menuEngine.Engine #1 Settings", False },
2801 { "menuEngine.Engine #2 Settings", False },
2802 { "menuEngine.Move Now", False },
2803 { "menuEngine.Retract Move", False },
2804 #ifndef OPTIONSDIALOG
2805 { "menuOptions.Auto Flag", False },
2806 { "menuOptions.Auto Flip View", False },
2807 { "menuOptions.ICS", False },
2808 // { "menuOptions.ICS Alarm", False },
2809 { "menuOptions.Move Sound", False },
2810 { "menuOptions.Hide Thinking", False },
2811 { "menuOptions.Periodic Updates", False },
2812 { "menuOptions.Ponder Next Move", False },
2814 { "menuEngine.Hint", False },
2815 { "menuEngine.Book", False },
2819 Enables gnuEnables[] = {
2820 { "menuMode.ICS Client", False },
2821 { "menuView.ICS Input Box", False },
2822 { "menuAction.Accept", False },
2823 { "menuAction.Decline", False },
2824 { "menuAction.Rematch", False },
2825 { "menuAction.Adjourn", False },
2826 { "menuAction.Stop Examining", False },
2827 { "menuAction.Stop Observing", False },
2828 { "menuAction.Upload to Examine", False },
2829 { "menuEdit.Revert", False },
2830 { "menuEdit.Annotate", False },
2831 { "menuOptions.ICS", False },
2833 /* The next two options rely on SetCmailMode being called *after* */
2834 /* SetGNUMode so that when GNU is being used to give hints these */
2835 /* menu options are still available */
2837 { "menuFile.Mail Move", False },
2838 { "menuFile.Reload CMail Message", False },
2842 Enables cmailEnables[] = {
2844 { "menuAction.Call Flag", False },
2845 { "menuAction.Draw", True },
2846 { "menuAction.Adjourn", False },
2847 { "menuAction.Abort", False },
2848 { "menuAction.Stop Observing", False },
2849 { "menuAction.Stop Examining", False },
2850 { "menuFile.Mail Move", True },
2851 { "menuFile.Reload CMail Message", True },
2855 Enables trainingOnEnables[] = {
2856 { "menuMode.Edit Comment", False },
2857 { "menuMode.Pause", False },
2858 { "menuEdit.Forward", False },
2859 { "menuEdit.Backward", False },
2860 { "menuEdit.Forward to End", False },
2861 { "menuEdit.Back to Start", False },
2862 { "menuEngine.Move Now", False },
2863 { "menuEdit.Truncate Game", False },
2867 Enables trainingOffEnables[] = {
2868 { "menuMode.Edit Comment", True },
2869 { "menuMode.Pause", True },
2870 { "menuEdit.Forward", True },
2871 { "menuEdit.Backward", True },
2872 { "menuEdit.Forward to End", True },
2873 { "menuEdit.Back to Start", True },
2874 { "menuEngine.Move Now", True },
2875 { "menuEdit.Truncate Game", True },
2879 Enables machineThinkingEnables[] = {
2880 { "menuFile.Load Game", False },
2881 // { "menuFile.Load Next Game", False },
2882 // { "menuFile.Load Previous Game", False },
2883 // { "menuFile.Reload Same Game", False },
2884 { "menuEdit.Paste Game", False },
2885 { "menuFile.Load Position", False },
2886 // { "menuFile.Load Next Position", False },
2887 // { "menuFile.Load Previous Position", False },
2888 // { "menuFile.Reload Same Position", False },
2889 { "menuEdit.Paste Position", False },
2890 { "menuMode.Machine White", False },
2891 { "menuMode.Machine Black", False },
2892 { "menuMode.Two Machines", False },
2893 { "menuMode.Machine Match", False },
2894 { "menuEngine.Retract Move", False },
2898 Enables userThinkingEnables[] = {
2899 { "menuFile.Load Game", True },
2900 // { "menuFile.Load Next Game", True },
2901 // { "menuFile.Load Previous Game", True },
2902 // { "menuFile.Reload Same Game", True },
2903 { "menuEdit.Paste Game", True },
2904 { "menuFile.Load Position", True },
2905 // { "menuFile.Load Next Position", True },
2906 // { "menuFile.Load Previous Position", True },
2907 // { "menuFile.Reload Same Position", True },
2908 { "menuEdit.Paste Position", True },
2909 { "menuMode.Machine White", True },
2910 { "menuMode.Machine Black", True },
2911 { "menuMode.Two Machines", True },
2912 { "menuMode.Machine Match", True },
2913 { "menuEngine.Retract Move", True },
2919 SetMenuEnables(icsEnables);
2922 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2923 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2930 SetMenuEnables(ncpEnables);
2936 SetMenuEnables(gnuEnables);
2942 SetMenuEnables(cmailEnables);
2948 SetMenuEnables(trainingOnEnables);
2949 if (appData.showButtonBar) {
2950 XtSetSensitive(buttonBarWidget, False);
2956 SetTrainingModeOff()
2958 SetMenuEnables(trainingOffEnables);
2959 if (appData.showButtonBar) {
2960 XtSetSensitive(buttonBarWidget, True);
2965 SetUserThinkingEnables()
2967 if (appData.noChessProgram) return;
2968 SetMenuEnables(userThinkingEnables);
2972 SetMachineThinkingEnables()
2974 if (appData.noChessProgram) return;
2975 SetMenuEnables(machineThinkingEnables);
2977 case MachinePlaysBlack:
2978 case MachinePlaysWhite:
2979 case TwoMachinesPlay:
2980 XtSetSensitive(XtNameToWidget(menuBarWidget,
2981 ModeToWidgetName(gameMode)), True);
2988 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2989 #define HISTORY_SIZE 64
2990 static char *history[HISTORY_SIZE];
2991 int histIn = 0, histP = 0;
2994 SaveInHistory(char *cmd)
2996 if (history[histIn] != NULL) {
2997 free(history[histIn]);
2998 history[histIn] = NULL;
3000 if (*cmd == NULLCHAR) return;
3001 history[histIn] = StrSave(cmd);
3002 histIn = (histIn + 1) % HISTORY_SIZE;
3003 if (history[histIn] != NULL) {
3004 free(history[histIn]);
3005 history[histIn] = NULL;
3011 PrevInHistory(char *cmd)
3014 if (histP == histIn) {
3015 if (history[histIn] != NULL) free(history[histIn]);
3016 history[histIn] = StrSave(cmd);
3018 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
3019 if (newhp == histIn || history[newhp] == NULL) return NULL;
3021 return history[histP];
3027 if (histP == histIn) return NULL;
3028 histP = (histP + 1) % HISTORY_SIZE;
3029 return history[histP];
3031 // end of borrowed code
3033 #define Abs(n) ((n)<0 ? -(n) : (n))
3036 * Find a font that matches "pattern" that is as close as
3037 * possible to the targetPxlSize. Prefer fonts that are k
3038 * pixels smaller to fonts that are k pixels larger. The
3039 * pattern must be in the X Consortium standard format,
3040 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3041 * The return value should be freed with XtFree when no
3045 FindFont(pattern, targetPxlSize)
3049 char **fonts, *p, *best, *scalable, *scalableTail;
3050 int i, j, nfonts, minerr, err, pxlSize;
3053 char **missing_list;
3055 char *def_string, *base_fnt_lst, strInt[3];
3057 XFontStruct **fnt_list;
3059 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3060 snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
3061 p = strstr(pattern, "--");
3062 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3063 strcat(base_fnt_lst, strInt);
3064 strcat(base_fnt_lst, strchr(p + 2, '-'));
3066 if ((fntSet = XCreateFontSet(xDisplay,
3070 &def_string)) == NULL) {
3072 fprintf(stderr, _("Unable to create font set.\n"));
3076 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3078 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3080 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3081 programName, pattern);
3089 for (i=0; i<nfonts; i++) {
3092 if (*p != '-') continue;
3094 if (*p == NULLCHAR) break;
3095 if (*p++ == '-') j++;
3097 if (j < 7) continue;
3100 scalable = fonts[i];
3103 err = pxlSize - targetPxlSize;
3104 if (Abs(err) < Abs(minerr) ||
3105 (minerr > 0 && err < 0 && -err == minerr)) {
3111 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3112 /* If the error is too big and there is a scalable font,
3113 use the scalable font. */
3114 int headlen = scalableTail - scalable;
3115 p = (char *) XtMalloc(strlen(scalable) + 10);
3116 while (isdigit(*scalableTail)) scalableTail++;
3117 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3119 p = (char *) XtMalloc(strlen(best) + 2);
3120 safeStrCpy(p, best, strlen(best)+1 );
3122 if (appData.debugMode) {
3123 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3124 pattern, targetPxlSize, p);
3127 if (missing_count > 0)
3128 XFreeStringList(missing_list);
3129 XFreeFontSet(xDisplay, fntSet);
3131 XFreeFontNames(fonts);
3137 { // [HGM] deletes GCs that are to be remade, to prevent resource leak;
3138 // must be called before all non-first callse to CreateGCs()
3139 XtReleaseGC(shellWidget, highlineGC);
3140 XtReleaseGC(shellWidget, lightSquareGC);
3141 XtReleaseGC(shellWidget, darkSquareGC);
3142 if (appData.monoMode) {
3143 if (DefaultDepth(xDisplay, xScreen) == 1) {
3144 XtReleaseGC(shellWidget, wbPieceGC);
3146 XtReleaseGC(shellWidget, bwPieceGC);
3149 XtReleaseGC(shellWidget, prelineGC);
3150 XtReleaseGC(shellWidget, jailSquareGC);
3151 XtReleaseGC(shellWidget, wdPieceGC);
3152 XtReleaseGC(shellWidget, wlPieceGC);
3153 XtReleaseGC(shellWidget, wjPieceGC);
3154 XtReleaseGC(shellWidget, bdPieceGC);
3155 XtReleaseGC(shellWidget, blPieceGC);
3156 XtReleaseGC(shellWidget, bjPieceGC);
3160 void CreateGCs(int redo)
3162 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3163 | GCBackground | GCFunction | GCPlaneMask;
3164 XGCValues gc_values;
3167 gc_values.plane_mask = AllPlanes;
3168 gc_values.line_width = lineGap;
3169 gc_values.line_style = LineSolid;
3170 gc_values.function = GXcopy;
3173 DeleteGCs(); // called a second time; clean up old GCs first
3174 } else { // [HGM] grid and font GCs created on first call only
3175 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3176 gc_values.background = XBlackPixel(xDisplay, xScreen);
3177 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3179 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3180 gc_values.background = XWhitePixel(xDisplay, xScreen);
3181 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3182 XSetFont(xDisplay, coordGC, coordFontID);
3184 // [HGM] make font for holdings counts (white on black)
3185 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3186 gc_values.background = XBlackPixel(xDisplay, xScreen);
3187 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3188 XSetFont(xDisplay, countGC, countFontID);
3190 if (appData.monoMode) {
3191 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3192 gc_values.background = XWhitePixel(xDisplay, xScreen);
3193 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3195 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3196 gc_values.background = XBlackPixel(xDisplay, xScreen);
3197 lightSquareGC = wbPieceGC
3198 = XtGetGC(shellWidget, value_mask, &gc_values);
3200 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3201 gc_values.background = XWhitePixel(xDisplay, xScreen);
3202 darkSquareGC = bwPieceGC
3203 = XtGetGC(shellWidget, value_mask, &gc_values);
3205 if (DefaultDepth(xDisplay, xScreen) == 1) {
3206 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3207 gc_values.function = GXcopyInverted;
3208 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3209 gc_values.function = GXcopy;
3210 if (XBlackPixel(xDisplay, xScreen) == 1) {
3211 bwPieceGC = darkSquareGC;
3212 wbPieceGC = copyInvertedGC;
3214 bwPieceGC = copyInvertedGC;
3215 wbPieceGC = lightSquareGC;
3219 gc_values.foreground = highlightSquareColor;
3220 gc_values.background = highlightSquareColor;
3221 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3223 gc_values.foreground = premoveHighlightColor;
3224 gc_values.background = premoveHighlightColor;
3225 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3227 gc_values.foreground = lightSquareColor;
3228 gc_values.background = darkSquareColor;
3229 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3231 gc_values.foreground = darkSquareColor;
3232 gc_values.background = lightSquareColor;
3233 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3235 gc_values.foreground = jailSquareColor;
3236 gc_values.background = jailSquareColor;
3237 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3239 gc_values.foreground = whitePieceColor;
3240 gc_values.background = darkSquareColor;
3241 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3243 gc_values.foreground = whitePieceColor;
3244 gc_values.background = lightSquareColor;
3245 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3247 gc_values.foreground = whitePieceColor;
3248 gc_values.background = jailSquareColor;
3249 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3251 gc_values.foreground = blackPieceColor;
3252 gc_values.background = darkSquareColor;
3253 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3255 gc_values.foreground = blackPieceColor;
3256 gc_values.background = lightSquareColor;
3257 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3259 gc_values.foreground = blackPieceColor;
3260 gc_values.background = jailSquareColor;
3261 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3265 void loadXIM(xim, xmask, filename, dest, mask)
3278 fp = fopen(filename, "rb");
3280 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3287 for (y=0; y<h; ++y) {
3288 for (x=0; x<h; ++x) {
3293 XPutPixel(xim, x, y, blackPieceColor);
3295 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3298 XPutPixel(xim, x, y, darkSquareColor);
3300 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3303 XPutPixel(xim, x, y, whitePieceColor);
3305 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3308 XPutPixel(xim, x, y, lightSquareColor);
3310 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3318 /* create Pixmap of piece */
3319 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3321 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3324 /* create Pixmap of clipmask
3325 Note: We assume the white/black pieces have the same
3326 outline, so we make only 6 masks. This is okay
3327 since the XPM clipmask routines do the same. */
3329 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3331 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3334 /* now create the 1-bit version */
3335 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3338 values.foreground = 1;
3339 values.background = 0;
3341 /* Don't use XtGetGC, not read only */
3342 maskGC = XCreateGC(xDisplay, *mask,
3343 GCForeground | GCBackground, &values);
3344 XCopyPlane(xDisplay, temp, *mask, maskGC,
3345 0, 0, squareSize, squareSize, 0, 0, 1);
3346 XFreePixmap(xDisplay, temp);
3351 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3353 void CreateXIMPieces()
3358 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3363 /* The XSynchronize calls were copied from CreatePieces.
3364 Not sure if needed, but can't hurt */
3365 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3368 /* temp needed by loadXIM() */
3369 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3370 0, 0, ss, ss, AllPlanes, XYPixmap);
3372 if (strlen(appData.pixmapDirectory) == 0) {
3376 if (appData.monoMode) {
3377 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3381 fprintf(stderr, _("\nLoading XIMs...\n"));
3383 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3384 fprintf(stderr, "%d", piece+1);
3385 for (kind=0; kind<4; kind++) {
3386 fprintf(stderr, ".");
3387 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3388 ExpandPathName(appData.pixmapDirectory),
3389 piece <= (int) WhiteKing ? "" : "w",
3390 pieceBitmapNames[piece],
3392 ximPieceBitmap[kind][piece] =
3393 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3394 0, 0, ss, ss, AllPlanes, XYPixmap);
3395 if (appData.debugMode)
3396 fprintf(stderr, _("(File:%s:) "), buf);
3397 loadXIM(ximPieceBitmap[kind][piece],
3399 &(xpmPieceBitmap2[kind][piece]),
3400 &(ximMaskPm2[piece]));
3401 if(piece <= (int)WhiteKing)
3402 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3404 fprintf(stderr," ");
3406 /* Load light and dark squares */
3407 /* If the LSQ and DSQ pieces don't exist, we will
3408 draw them with solid squares. */
3409 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3410 if (access(buf, 0) != 0) {
3414 fprintf(stderr, _("light square "));
3416 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3417 0, 0, ss, ss, AllPlanes, XYPixmap);
3418 if (appData.debugMode)
3419 fprintf(stderr, _("(File:%s:) "), buf);
3421 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3422 fprintf(stderr, _("dark square "));
3423 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3424 ExpandPathName(appData.pixmapDirectory), ss);
3425 if (appData.debugMode)
3426 fprintf(stderr, _("(File:%s:) "), buf);
3428 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3429 0, 0, ss, ss, AllPlanes, XYPixmap);
3430 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3431 xpmJailSquare = xpmLightSquare;
3433 fprintf(stderr, _("Done.\n"));
3435 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3439 void CreateXPMBoard(char *s, int kind)
3443 if(s == NULL || *s == 0 || *s == '*') { useTexture &= ~(kind+1); return; }
3444 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3445 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3449 void FreeXPMPieces()
3450 { // [HGM] to prevent resoucre leak on calling CreaeXPMPieces() a second time,
3451 // thisroutine has to be called t free the old piece pixmaps
3453 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++)
3454 for (kind=0; kind<4; kind++) XFreePixmap(xDisplay, xpmPieceBitmap2[kind][piece]);
3456 XFreePixmap(xDisplay, xpmLightSquare);
3457 XFreePixmap(xDisplay, xpmDarkSquare);
3461 void CreateXPMPieces()
3465 u_int ss = squareSize;
3467 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3468 XpmColorSymbol symbols[4];
3469 static int redo = False;
3471 if(redo) FreeXPMPieces(); else redo = 1;
3473 /* The XSynchronize calls were copied from CreatePieces.
3474 Not sure if needed, but can't hurt */
3475 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3477 /* Setup translations so piece colors match square colors */
3478 symbols[0].name = "light_piece";
3479 symbols[0].value = appData.whitePieceColor;
3480 symbols[1].name = "dark_piece";
3481 symbols[1].value = appData.blackPieceColor;
3482 symbols[2].name = "light_square";
3483 symbols[2].value = appData.lightSquareColor;
3484 symbols[3].name = "dark_square";
3485 symbols[3].value = appData.darkSquareColor;
3487 attr.valuemask = XpmColorSymbols;
3488 attr.colorsymbols = symbols;
3489 attr.numsymbols = 4;
3491 if (appData.monoMode) {
3492 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3496 if (strlen(appData.pixmapDirectory) == 0) {
3497 XpmPieces* pieces = builtInXpms;
3500 while (pieces->size != squareSize && pieces->size) pieces++;
3501 if (!pieces->size) {
3502 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3505 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3506 for (kind=0; kind<4; kind++) {
3508 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3509 pieces->xpm[piece][kind],
3510 &(xpmPieceBitmap2[kind][piece]),
3511 NULL, &attr)) != 0) {
3512 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3516 if(piece <= (int) WhiteKing)
3517 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3521 xpmJailSquare = xpmLightSquare;
3525 fprintf(stderr, _("\nLoading XPMs...\n"));
3528 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3529 fprintf(stderr, "%d ", piece+1);
3530 for (kind=0; kind<4; kind++) {
3531 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3532 ExpandPathName(appData.pixmapDirectory),
3533 piece > (int) WhiteKing ? "w" : "",
3534 pieceBitmapNames[piece],
3536 if (appData.debugMode) {
3537 fprintf(stderr, _("(File:%s:) "), buf);
3539 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3540 &(xpmPieceBitmap2[kind][piece]),
3541 NULL, &attr)) != 0) {
3542 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3543 // [HGM] missing: read of unorthodox piece failed; substitute King.
3544 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3545 ExpandPathName(appData.pixmapDirectory),
3547 if (appData.debugMode) {
3548 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3550 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3551 &(xpmPieceBitmap2[kind][piece]),
3555 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3560 if(piece <= (int) WhiteKing)
3561 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3564 /* Load light and dark squares */
3565 /* If the LSQ and DSQ pieces don't exist, we will
3566 draw them with solid squares. */
3567 fprintf(stderr, _("light square "));
3568 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3569 if (access(buf, 0) != 0) {
3573 if (appData.debugMode)
3574 fprintf(stderr, _("(File:%s:) "), buf);
3576 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3577 &xpmLightSquare, NULL, &attr)) != 0) {
3578 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3581 fprintf(stderr, _("dark square "));
3582 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3583 ExpandPathName(appData.pixmapDirectory), ss);
3584 if (appData.debugMode) {
3585 fprintf(stderr, _("(File:%s:) "), buf);
3587 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3588 &xpmDarkSquare, NULL, &attr)) != 0) {
3589 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3593 xpmJailSquare = xpmLightSquare;
3594 fprintf(stderr, _("Done.\n"));
3596 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3599 #endif /* HAVE_LIBXPM */
3602 /* No built-in bitmaps */
3607 u_int ss = squareSize;
3609 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3612 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3613 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3614 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3615 pieceBitmapNames[piece],
3616 ss, kind == SOLID ? 's' : 'o');
3617 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3618 if(piece <= (int)WhiteKing)
3619 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3623 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3627 /* With built-in bitmaps */
3630 BuiltInBits* bib = builtInBits;
3633 u_int ss = squareSize;
3635 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3638 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3640 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3641 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3642 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3643 pieceBitmapNames[piece],
3644 ss, kind == SOLID ? 's' : 'o');
3645 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3646 bib->bits[kind][piece], ss, ss);
3647 if(piece <= (int)WhiteKing)
3648 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3652 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3657 void ReadBitmap(pm, name, bits, wreq, hreq)
3660 unsigned char bits[];
3666 char msg[MSG_SIZ], fullname[MSG_SIZ];
3668 if (*appData.bitmapDirectory != NULLCHAR) {
3669 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3670 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3671 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3672 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3673 &w, &h, pm, &x_hot, &y_hot);
3674 fprintf(stderr, "load %s\n", name);
3675 if (errcode != BitmapSuccess) {
3677 case BitmapOpenFailed:
3678 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3680 case BitmapFileInvalid:
3681 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3683 case BitmapNoMemory:
3684 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3688 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3692 fprintf(stderr, _("%s: %s...using built-in\n"),
3694 } else if (w != wreq || h != hreq) {
3696 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3697 programName, fullname, w, h, wreq, hreq);
3703 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3712 if (lineGap == 0) return;
3714 /* [HR] Split this into 2 loops for non-square boards. */
3716 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3717 gridSegments[i].x1 = 0;
3718 gridSegments[i].x2 =
3719 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3720 gridSegments[i].y1 = gridSegments[i].y2
3721 = lineGap / 2 + (i * (squareSize + lineGap));
3724 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3725 gridSegments[j + i].y1 = 0;
3726 gridSegments[j + i].y2 =
3727 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3728 gridSegments[j + i].x1 = gridSegments[j + i].x2
3729 = lineGap / 2 + (j * (squareSize + lineGap));
3733 static void MenuBarSelect(w, addr, index)
3738 XtActionProc proc = (XtActionProc) addr;
3740 (proc)(NULL, NULL, NULL, NULL);
3743 void CreateMenuBarPopup(parent, name, mb)
3753 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3756 XtSetArg(args[j], XtNleftMargin, 20); j++;
3757 XtSetArg(args[j], XtNrightMargin, 20); j++;
3759 while (mi->string != NULL) {
3760 if (strcmp(mi->string, "----") == 0) {
3761 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3764 XtSetArg(args[j], XtNlabel, XtNewString(mi->string));
3765 entry = XtCreateManagedWidget(mi->ref, smeBSBObjectClass,
3767 XtAddCallback(entry, XtNcallback,
3768 (XtCallbackProc) MenuBarSelect,
3769 (caddr_t) mi->proc);
3775 Widget CreateMenuBar(mb)
3779 Widget anchor, menuBar;
3781 char menuName[MSG_SIZ];
3784 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3785 XtSetArg(args[j], XtNvSpace, 0); j++;
3786 XtSetArg(args[j], XtNborderWidth, 0); j++;
3787 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3788 formWidget, args, j);
3790 while (mb->name != NULL) {
3791 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3792 strncat(menuName, mb->ref, MSG_SIZ - strlen(menuName) - 1);
3794 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3797 shortName[0] = mb->name[0];
3798 shortName[1] = NULLCHAR;
3799 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3802 XtSetArg(args[j], XtNlabel, XtNewString(mb->name)); j++;
3805 XtSetArg(args[j], XtNborderWidth, 0); j++;
3806 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3808 CreateMenuBarPopup(menuBar, menuName, mb);
3814 Widget CreateButtonBar(mi)
3818 Widget button, buttonBar;
3822 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3824 XtSetArg(args[j], XtNhSpace, 0); j++;
3826 XtSetArg(args[j], XtNborderWidth, 0); j++;
3827 XtSetArg(args[j], XtNvSpace, 0); j++;
3828 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3829 formWidget, args, j);
3831 while (mi->string != NULL) {
3834 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3835 XtSetArg(args[j], XtNborderWidth, 0); j++;
3837 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3838 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3839 buttonBar, args, j);
3840 XtAddCallback(button, XtNcallback,
3841 (XtCallbackProc) MenuBarSelect,
3842 (caddr_t) mi->proc);
3849 CreatePieceMenu(name, color)
3856 ChessSquare selection;
3858 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3859 boardWidget, args, 0);
3861 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3862 String item = pieceMenuStrings[color][i];
3864 if (strcmp(item, "----") == 0) {
3865 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3868 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3869 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3871 selection = pieceMenuTranslation[color][i];
3872 XtAddCallback(entry, XtNcallback,
3873 (XtCallbackProc) PieceMenuSelect,
3874 (caddr_t) selection);
3875 if (selection == WhitePawn || selection == BlackPawn) {
3876 XtSetArg(args[0], XtNpopupOnEntry, entry);
3877 XtSetValues(menu, args, 1);
3890 ChessSquare selection;
3892 whitePieceMenu = CreatePieceMenu("menuW", 0);
3893 blackPieceMenu = CreatePieceMenu("menuB", 1);
3895 XtRegisterGrabAction(PieceMenuPopup, True,
3896 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3897 GrabModeAsync, GrabModeAsync);
3899 XtSetArg(args[0], XtNlabel, _("Drop"));
3900 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3901 boardWidget, args, 1);
3902 for (i = 0; i < DROP_MENU_SIZE; i++) {
3903 String item = dropMenuStrings[i];
3905 if (strcmp(item, "----") == 0) {
3906 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3909 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3910 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3912 selection = dropMenuTranslation[i];
3913 XtAddCallback(entry, XtNcallback,
3914 (XtCallbackProc) DropMenuSelect,
3915 (caddr_t) selection);
3920 void SetupDropMenu()
3928 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3929 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3930 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3931 dmEnables[i].piece);
3932 XtSetSensitive(entry, p != NULL || !appData.testLegality
3933 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3934 && !appData.icsActive));
3936 while (p && *p++ == dmEnables[i].piece) count++;
3937 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3939 XtSetArg(args[j], XtNlabel, label); j++;
3940 XtSetValues(entry, args, j);
3944 void PieceMenuPopup(w, event, params, num_params)
3948 Cardinal *num_params;
3950 String whichMenu; int menuNr;
3951 if (event->type == ButtonRelease)
3952 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3953 else if (event->type == ButtonPress)
3954 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3956 case 0: whichMenu = params[0]; break;
3957 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3959 case -1: if (errorUp) ErrorPopDown();
3962 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3965 static void PieceMenuSelect(w, piece, junk)
3970 if (pmFromX < 0 || pmFromY < 0) return;
3971 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3974 static void DropMenuSelect(w, piece, junk)
3979 if (pmFromX < 0 || pmFromY < 0) return;
3980 DropMenuEvent(piece, pmFromX, pmFromY);
3983 void WhiteClock(w, event, prms, nprms)
3992 void BlackClock(w, event, prms, nprms)
4003 * If the user selects on a border boundary, return -1; if off the board,
4004 * return -2. Otherwise map the event coordinate to the square.
4006 int EventToSquare(x, limit)
4014 if ((x % (squareSize + lineGap)) >= squareSize)
4016 x /= (squareSize + lineGap);
4022 static void do_flash_delay(msec)
4028 static void drawHighlight(file, rank, gc)
4034 if (lineGap == 0) return;
4037 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
4038 (squareSize + lineGap);
4039 y = lineGap/2 + rank * (squareSize + lineGap);
4041 x = lineGap/2 + file * (squareSize + lineGap);
4042 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
4043 (squareSize + lineGap);
4046 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
4047 squareSize+lineGap, squareSize+lineGap);
4050 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
4051 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4054 SetHighlights(fromX, fromY, toX, toY)
4055 int fromX, fromY, toX, toY;
4057 if (hi1X != fromX || hi1Y != fromY) {
4058 if (hi1X >= 0 && hi1Y >= 0) {
4059 drawHighlight(hi1X, hi1Y, lineGC);
4061 } // [HGM] first erase both, then draw new!
4062 if (hi2X != toX || hi2Y != toY) {
4063 if (hi2X >= 0 && hi2Y >= 0) {
4064 drawHighlight(hi2X, hi2Y, lineGC);
4067 if (hi1X != fromX || hi1Y != fromY) {
4068 if (fromX >= 0 && fromY >= 0) {
4069 drawHighlight(fromX, fromY, highlineGC);
4072 if (hi2X != toX || hi2Y != toY) {
4073 if (toX >= 0 && toY >= 0) {
4074 drawHighlight(toX, toY, highlineGC);
4086 SetHighlights(-1, -1, -1, -1);
4091 SetPremoveHighlights(fromX, fromY, toX, toY)
4092 int fromX, fromY, toX, toY;
4094 if (pm1X != fromX || pm1Y != fromY) {
4095 if (pm1X >= 0 && pm1Y >= 0) {
4096 drawHighlight(pm1X, pm1Y, lineGC);
4098 if (fromX >= 0 && fromY >= 0) {
4099 drawHighlight(fromX, fromY, prelineGC);
4102 if (pm2X != toX || pm2Y != toY) {
4103 if (pm2X >= 0 && pm2Y >= 0) {
4104 drawHighlight(pm2X, pm2Y, lineGC);
4106 if (toX >= 0 && toY >= 0) {
4107 drawHighlight(toX, toY, prelineGC);
4117 ClearPremoveHighlights()
4119 SetPremoveHighlights(-1, -1, -1, -1);
4122 static int CutOutSquare(x, y, x0, y0, kind)
4123 int x, y, *x0, *y0, kind;
4125 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
4126 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
4128 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
4129 if(textureW[kind] < W*squareSize)
4130 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
4132 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
4133 if(textureH[kind] < H*squareSize)
4134 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
4136 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
4140 static void BlankSquare(x, y, color, piece, dest, fac)
4141 int x, y, color, fac;
4144 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
4146 if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
4147 XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
4148 squareSize, squareSize, x*fac, y*fac);
4150 if (useImages && useImageSqs) {
4154 pm = xpmLightSquare;
4159 case 2: /* neutral */
4164 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4165 squareSize, squareSize, x*fac, y*fac);
4175 case 2: /* neutral */
4180 XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
4185 I split out the routines to draw a piece so that I could
4186 make a generic flash routine.
4188 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4190 int square_color, x, y;
4193 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4194 switch (square_color) {
4196 case 2: /* neutral */
4198 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4199 ? *pieceToOutline(piece)
4200 : *pieceToSolid(piece),
4201 dest, bwPieceGC, 0, 0,
4202 squareSize, squareSize, x, y);
4205 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4206 ? *pieceToSolid(piece)
4207 : *pieceToOutline(piece),
4208 dest, wbPieceGC, 0, 0,
4209 squareSize, squareSize, x, y);
4214 static void monoDrawPiece(piece, square_color, x, y, dest)
4216 int square_color, x, y;
4219 switch (square_color) {
4221 case 2: /* neutral */
4223 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4224 ? *pieceToOutline(piece)
4225 : *pieceToSolid(piece),
4226 dest, bwPieceGC, 0, 0,
4227 squareSize, squareSize, x, y, 1);
4230 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4231 ? *pieceToSolid(piece)
4232 : *pieceToOutline(piece),
4233 dest, wbPieceGC, 0, 0,
4234 squareSize, squareSize, x, y, 1);
4239 static void colorDrawPiece(piece, square_color, x, y, dest)
4241 int square_color, x, y;
4244 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4245 switch (square_color) {
4247 XCopyPlane(xDisplay, *pieceToSolid(piece),
4248 dest, (int) piece < (int) BlackPawn
4249 ? wlPieceGC : blPieceGC, 0, 0,
4250 squareSize, squareSize, x, y, 1);
4253 XCopyPlane(xDisplay, *pieceToSolid(piece),
4254 dest, (int) piece < (int) BlackPawn
4255 ? wdPieceGC : bdPieceGC, 0, 0,
4256 squareSize, squareSize, x, y, 1);
4258 case 2: /* neutral */
4260 XCopyPlane(xDisplay, *pieceToSolid(piece),
4261 dest, (int) piece < (int) BlackPawn
4262 ? wjPieceGC : bjPieceGC, 0, 0,
4263 squareSize, squareSize, x, y, 1);
4268 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4270 int square_color, x, y;
4273 int kind, p = piece;
4275 switch (square_color) {
4277 case 2: /* neutral */
4279 if ((int)piece < (int) BlackPawn) {
4287 if ((int)piece < (int) BlackPawn) {
4295 if(appData.upsideDown && flipView) { kind ^= 2; p += p < BlackPawn ? BlackPawn : -BlackPawn; }// swap white and black pieces
4296 if(useTexture & square_color+1) {
4297 BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
4298 XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
4299 XSetClipOrigin(xDisplay, wlPieceGC, x, y);
4300 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);
4301 XSetClipMask(xDisplay, wlPieceGC, None);
4302 XSetClipOrigin(xDisplay, wlPieceGC, 0, 0);
4304 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4305 dest, wlPieceGC, 0, 0,
4306 squareSize, squareSize, x, y);
4309 typedef void (*DrawFunc)();
4311 DrawFunc ChooseDrawFunc()
4313 if (appData.monoMode) {
4314 if (DefaultDepth(xDisplay, xScreen) == 1) {
4315 return monoDrawPiece_1bit;
4317 return monoDrawPiece;
4321 return colorDrawPieceImage;
4323 return colorDrawPiece;
4327 /* [HR] determine square color depending on chess variant. */
4328 static int SquareColor(row, column)
4333 if (gameInfo.variant == VariantXiangqi) {
4334 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4336 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4338 } else if (row <= 4) {
4344 square_color = ((column + row) % 2) == 1;
4347 /* [hgm] holdings: next line makes all holdings squares light */
4348 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4350 return square_color;
4353 void DrawSquare(row, column, piece, do_flash)
4354 int row, column, do_flash;
4357 int square_color, x, y, direction, font_ascent, font_descent;
4360 XCharStruct overall;
4364 /* Calculate delay in milliseconds (2-delays per complete flash) */
4365 flash_delay = 500 / appData.flashRate;
4368 x = lineGap + ((BOARD_WIDTH-1)-column) *
4369 (squareSize + lineGap);
4370 y = lineGap + row * (squareSize + lineGap);
4372 x = lineGap + column * (squareSize + lineGap);
4373 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4374 (squareSize + lineGap);
4377 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4379 square_color = SquareColor(row, column);
4381 if ( // [HGM] holdings: blank out area between board and holdings
4382 column == BOARD_LEFT-1 || column == BOARD_RGHT
4383 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4384 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4385 BlankSquare(x, y, 2, EmptySquare, xBoardWindow, 1);
4387 // [HGM] print piece counts next to holdings
4388 string[1] = NULLCHAR;
4389 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4390 string[0] = '0' + piece;
4391 XTextExtents(countFontStruct, string, 1, &direction,
4392 &font_ascent, &font_descent, &overall);
4393 if (appData.monoMode) {
4394 XDrawImageString(xDisplay, xBoardWindow, countGC,
4395 x + squareSize - overall.width - 2,
4396 y + font_ascent + 1, string, 1);
4398 XDrawString(xDisplay, xBoardWindow, countGC,
4399 x + squareSize - overall.width - 2,
4400 y + font_ascent + 1, string, 1);
4403 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4404 string[0] = '0' + piece;
4405 XTextExtents(countFontStruct, string, 1, &direction,
4406 &font_ascent, &font_descent, &overall);
4407 if (appData.monoMode) {
4408 XDrawImageString(xDisplay, xBoardWindow, countGC,
4409 x + 2, y + font_ascent + 1, string, 1);
4411 XDrawString(xDisplay, xBoardWindow, countGC,
4412 x + 2, y + font_ascent + 1, string, 1);
4416 if (piece == EmptySquare || appData.blindfold) {
4417 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4419 drawfunc = ChooseDrawFunc();
4421 if (do_flash && appData.flashCount > 0) {
4422 for (i=0; i<appData.flashCount; ++i) {
4423 drawfunc(piece, square_color, x, y, xBoardWindow);
4424 XSync(xDisplay, False);
4425 do_flash_delay(flash_delay);
4427 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4428 XSync(xDisplay, False);
4429 do_flash_delay(flash_delay);
4432 drawfunc(piece, square_color, x, y, xBoardWindow);
4436 string[1] = NULLCHAR;
4437 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4438 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4439 string[0] = 'a' + column - BOARD_LEFT;
4440 XTextExtents(coordFontStruct, string, 1, &direction,
4441 &font_ascent, &font_descent, &overall);
4442 if (appData.monoMode) {
4443 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4444 x + squareSize - overall.width - 2,
4445 y + squareSize - font_descent - 1, string, 1);
4447 XDrawString(xDisplay, xBoardWindow, coordGC,
4448 x + squareSize - overall.width - 2,
4449 y + squareSize - font_descent - 1, string, 1);
4452 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4453 string[0] = ONE + row;
4454 XTextExtents(coordFontStruct, string, 1, &direction,
4455 &font_ascent, &font_descent, &overall);
4456 if (appData.monoMode) {
4457 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4458 x + 2, y + font_ascent + 1, string, 1);
4460 XDrawString(xDisplay, xBoardWindow, coordGC,
4461 x + 2, y + font_ascent + 1, string, 1);
4464 if(!partnerUp && marker[row][column]) {
4465 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4466 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4471 /* Why is this needed on some versions of X? */
4472 void EventProc(widget, unused, event)
4477 if (!XtIsRealized(widget))
4480 switch (event->type) {
4482 if (event->xexpose.count > 0) return; /* no clipping is done */
4483 XDrawPosition(widget, True, NULL);
4484 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4485 flipView = !flipView; partnerUp = !partnerUp;
4486 XDrawPosition(widget, True, NULL);
4487 flipView = !flipView; partnerUp = !partnerUp;
4491 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
4498 void DrawPosition(fullRedraw, board)
4499 /*Boolean*/int fullRedraw;
4502 XDrawPosition(boardWidget, fullRedraw, board);
4505 /* Returns 1 if there are "too many" differences between b1 and b2
4506 (i.e. more than 1 move was made) */
4507 static int too_many_diffs(b1, b2)
4513 for (i=0; i<BOARD_HEIGHT; ++i) {
4514 for (j=0; j<BOARD_WIDTH; ++j) {
4515 if (b1[i][j] != b2[i][j]) {
4516 if (++c > 4) /* Castling causes 4 diffs */
4524 /* Matrix describing castling maneuvers */
4525 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4526 static int castling_matrix[4][5] = {
4527 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4528 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4529 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4530 { 7, 7, 4, 5, 6 } /* 0-0, black */
4533 /* Checks whether castling occurred. If it did, *rrow and *rcol
4534 are set to the destination (row,col) of the rook that moved.
4536 Returns 1 if castling occurred, 0 if not.
4538 Note: Only handles a max of 1 castling move, so be sure
4539 to call too_many_diffs() first.
4541 static int check_castle_draw(newb, oldb, rrow, rcol)
4548 /* For each type of castling... */
4549 for (i=0; i<4; ++i) {
4550 r = castling_matrix[i];
4552 /* Check the 4 squares involved in the castling move */
4554 for (j=1; j<=4; ++j) {
4555 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4562 /* All 4 changed, so it must be a castling move */
4571 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4572 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4574 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4577 void DrawSeekBackground( int left, int top, int right, int bottom )
4579 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4582 void DrawSeekText(char *buf, int x, int y)
4584 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4587 void DrawSeekDot(int x, int y, int colorNr)
4589 int square = colorNr & 0x80;
4592 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4594 XFillRectangle(xDisplay, xBoardWindow, color,
4595 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4597 XFillArc(xDisplay, xBoardWindow, color,
4598 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4601 static int damage[2][BOARD_RANKS][BOARD_FILES];
4604 * event handler for redrawing the board
4606 void XDrawPosition(w, repaint, board)
4608 /*Boolean*/int repaint;
4612 static int lastFlipView = 0;
4613 static int lastBoardValid[2] = {0, 0};
4614 static Board lastBoard[2];
4617 int nr = twoBoards*partnerUp;
4619 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4621 if (board == NULL) {
4622 if (!lastBoardValid[nr]) return;
4623 board = lastBoard[nr];
4625 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4626 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4627 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Flip View"),
4632 * It would be simpler to clear the window with XClearWindow()
4633 * but this causes a very distracting flicker.
4636 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4638 if ( lineGap && IsDrawArrowEnabled())
4639 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4640 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4642 /* If too much changes (begin observing new game, etc.), don't
4644 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4646 /* Special check for castling so we don't flash both the king
4647 and the rook (just flash the king). */
4649 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4650 /* Draw rook with NO flashing. King will be drawn flashing later */
4651 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4652 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4656 /* First pass -- Draw (newly) empty squares and repair damage.
4657 This prevents you from having a piece show up twice while it
4658 is flashing on its new square */
4659 for (i = 0; i < BOARD_HEIGHT; i++)
4660 for (j = 0; j < BOARD_WIDTH; j++)
4661 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4662 || damage[nr][i][j]) {
4663 DrawSquare(i, j, board[i][j], 0);
4664 damage[nr][i][j] = False;
4667 /* Second pass -- Draw piece(s) in new position and flash them */
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]) {
4671 DrawSquare(i, j, board[i][j], do_flash);
4675 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4676 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4677 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4679 for (i = 0; i < BOARD_HEIGHT; i++)
4680 for (j = 0; j < BOARD_WIDTH; j++) {
4681 DrawSquare(i, j, board[i][j], 0);
4682 damage[nr][i][j] = False;
4686 CopyBoard(lastBoard[nr], board);
4687 lastBoardValid[nr] = 1;
4688 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4689 lastFlipView = flipView;
4691 /* Draw highlights */
4692 if (pm1X >= 0 && pm1Y >= 0) {
4693 drawHighlight(pm1X, pm1Y, prelineGC);
4695 if (pm2X >= 0 && pm2Y >= 0) {
4696 drawHighlight(pm2X, pm2Y, prelineGC);
4698 if (hi1X >= 0 && hi1Y >= 0) {
4699 drawHighlight(hi1X, hi1Y, highlineGC);
4701 if (hi2X >= 0 && hi2Y >= 0) {
4702 drawHighlight(hi2X, hi2Y, highlineGC);
4704 DrawArrowHighlight(hi1X, hi1Y, hi2X, hi2Y);
4706 /* If piece being dragged around board, must redraw that too */
4709 XSync(xDisplay, False);
4714 * event handler for redrawing the board
4716 void DrawPositionProc(w, event, prms, nprms)
4722 XDrawPosition(w, True, NULL);
4727 * event handler for parsing user moves
4729 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4730 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4731 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4732 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4733 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4734 // and at the end FinishMove() to perform the move after optional promotion popups.
4735 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4736 void HandleUserMove(w, event, prms, nprms)
4742 if (w != boardWidget || errorExitStatus != -1) return;
4743 if(nprms) shiftKey = !strcmp(prms[0], "1");
4746 if (event->type == ButtonPress) {
4747 XtPopdown(promotionShell);
4748 XtDestroyWidget(promotionShell);
4749 promotionUp = False;
4757 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4758 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4759 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4762 void AnimateUserMove (Widget w, XEvent * event,
4763 String * params, Cardinal * nParams)
4765 DragPieceMove(event->xmotion.x, event->xmotion.y);
4768 void HandlePV (Widget w, XEvent * event,
4769 String * params, Cardinal * nParams)
4770 { // [HGM] pv: walk PV
4771 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4774 Widget CommentCreate(name, text, mutable, callback, lines)
4776 int /*Boolean*/ mutable;
4777 XtCallbackProc callback;
4781 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4786 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4787 XtGetValues(boardWidget, args, j);
4790 XtSetArg(args[j], XtNresizable, True); j++;
4793 XtCreatePopupShell(name, topLevelShellWidgetClass,
4794 shellWidget, args, j);
4797 XtCreatePopupShell(name, transientShellWidgetClass,
4798 shellWidget, args, j);
4801 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4802 layoutArgs, XtNumber(layoutArgs));
4804 XtCreateManagedWidget("form", formWidgetClass, layout,
4805 formArgs, XtNumber(formArgs));
4809 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4810 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4812 XtSetArg(args[j], XtNstring, text); j++;
4813 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4814 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4815 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4816 XtSetArg(args[j], XtNright, XtChainRight); j++;
4817 XtSetArg(args[j], XtNresizable, True); j++;
4818 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4819 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4820 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4821 XtSetArg(args[j], XtNautoFill, True); j++;
4822 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4824 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4825 XtOverrideTranslations(edit, XtParseTranslationTable(commentTranslations));
4829 XtSetArg(args[j], XtNfromVert, edit); j++;
4830 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4831 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4832 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4833 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4835 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4836 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4839 XtSetArg(args[j], XtNfromVert, edit); j++;
4840 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4841 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4842 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4843 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4844 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4846 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4847 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4850 XtSetArg(args[j], XtNfromVert, edit); j++;
4851 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4852 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4853 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4854 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4855 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4857 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4858 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4861 XtSetArg(args[j], XtNfromVert, edit); j++;
4862 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4863 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4864 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4865 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4867 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4868 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4871 XtSetArg(args[j], XtNfromVert, edit); j++;
4872 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4873 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4874 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4875 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4876 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4878 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4879 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4882 XtRealizeWidget(shell);
4884 if (commentX == -1) {
4887 Dimension pw_height;
4888 Dimension ew_height;
4891 XtSetArg(args[j], XtNheight, &ew_height); j++;
4892 XtGetValues(edit, args, j);
4895 XtSetArg(args[j], XtNheight, &pw_height); j++;
4896 XtGetValues(shell, args, j);
4897 commentH = pw_height + (lines - 1) * ew_height;
4898 commentW = bw_width - 16;
4900 XSync(xDisplay, False);
4902 /* This code seems to tickle an X bug if it is executed too soon
4903 after xboard starts up. The coordinates get transformed as if
4904 the main window was positioned at (0, 0).
4906 XtTranslateCoords(shellWidget,
4907 (bw_width - commentW) / 2, 0 - commentH / 2,
4908 &commentX, &commentY);
4910 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4911 RootWindowOfScreen(XtScreen(shellWidget)),
4912 (bw_width - commentW) / 2, 0 - commentH / 2,
4917 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4920 if(wpComment.width > 0) {
4921 commentX = wpComment.x;
4922 commentY = wpComment.y;
4923 commentW = wpComment.width;
4924 commentH = wpComment.height;
4928 XtSetArg(args[j], XtNheight, commentH); j++;
4929 XtSetArg(args[j], XtNwidth, commentW); j++;
4930 XtSetArg(args[j], XtNx, commentX); j++;
4931 XtSetArg(args[j], XtNy, commentY); j++;
4932 XtSetValues(shell, args, j);
4933 XtSetKeyboardFocus(shell, edit);
4938 static int savedIndex; /* gross that this is global */
4940 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
4943 XawTextPosition index, dummy;
4946 XawTextGetSelectionPos(w, &index, &dummy);
4947 XtSetArg(arg, XtNstring, &val);
4948 XtGetValues(w, &arg, 1);
4949 ReplaceComment(savedIndex, val);
4950 if(savedIndex != currentMove) ToNrEvent(savedIndex);
4951 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
4954 void EditCommentPopUp(index, title, text)
4963 if (text == NULL) text = "";
4965 if (editShell == NULL) {
4967 CommentCreate(title, text, True, EditCommentCallback, 4);
4968 XtRealizeWidget(editShell);
4969 CatchDeleteWindow(editShell, "EditCommentPopDown");
4971 edit = XtNameToWidget(editShell, "*form.text");
4973 XtSetArg(args[j], XtNstring, text); j++;
4974 XtSetValues(edit, args, j);
4976 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4977 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4978 XtSetValues(editShell, args, j);
4981 XtPopup(editShell, XtGrabNone);
4985 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4986 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"),
4988 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"),
4992 void EditCommentCallback(w, client_data, call_data)
4994 XtPointer client_data, call_data;
5002 XtSetArg(args[j], XtNlabel, &name); j++;
5003 XtGetValues(w, args, j);
5005 if (strcmp(name, _("ok")) == 0) {
5006 edit = XtNameToWidget(editShell, "*form.text");
5008 XtSetArg(args[j], XtNstring, &val); j++;
5009 XtGetValues(edit, args, j);
5010 ReplaceComment(savedIndex, val);
5011 EditCommentPopDown();
5012 } else if (strcmp(name, _("cancel")) == 0) {
5013 EditCommentPopDown();
5014 } else if (strcmp(name, _("clear")) == 0) {
5015 edit = XtNameToWidget(editShell, "*form.text");
5016 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5017 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5021 void EditCommentPopDown()
5026 if (!editUp) return;
5028 XtSetArg(args[j], XtNx, &commentX); j++;
5029 XtSetArg(args[j], XtNy, &commentY); j++;
5030 XtSetArg(args[j], XtNheight, &commentH); j++;
5031 XtSetArg(args[j], XtNwidth, &commentW); j++;
5032 XtGetValues(editShell, args, j);
5033 XtPopdown(editShell);
5036 XtSetArg(args[j], XtNleftBitmap, None); j++;
5037 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"),
5039 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"),
5043 void ICSInputBoxPopUp()
5048 extern Option boxOptions[];
5050 void ICSInputSendText()
5057 edit = boxOptions[0].handle;
5059 XtSetArg(args[j], XtNstring, &val); j++;
5060 XtGetValues(edit, args, j);
5062 SendMultiLineToICS(val);
5063 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5064 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5067 void ICSInputBoxPopDown()
5072 void CommentPopUp(title, text)
5079 savedIndex = currentMove; // [HGM] vari
5080 if (commentShell == NULL) {
5082 CommentCreate(title, text, False, CommentCallback, 4);
5083 XtRealizeWidget(commentShell);
5084 CatchDeleteWindow(commentShell, "CommentPopDown");
5086 edit = XtNameToWidget(commentShell, "*form.text");
5088 XtSetArg(args[j], XtNstring, text); j++;
5089 XtSetValues(edit, args, j);
5091 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5092 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5093 XtSetValues(commentShell, args, j);
5096 XtPopup(commentShell, XtGrabNone);
5097 XSync(xDisplay, False);
5102 void CommentCallback(w, client_data, call_data)
5104 XtPointer client_data, call_data;
5111 XtSetArg(args[j], XtNlabel, &name); j++;
5112 XtGetValues(w, args, j);
5114 if (strcmp(name, _("close")) == 0) {
5116 } else if (strcmp(name, _("edit")) == 0) {
5123 void CommentPopDown()
5128 if (!commentUp) return;
5130 XtSetArg(args[j], XtNx, &commentX); j++;
5131 XtSetArg(args[j], XtNy, &commentY); j++;
5132 XtSetArg(args[j], XtNwidth, &commentW); j++;
5133 XtSetArg(args[j], XtNheight, &commentH); j++;
5134 XtGetValues(commentShell, args, j);
5135 XtPopdown(commentShell);
5136 XSync(xDisplay, False);
5140 void FileNamePopUp(label, def, proc, openMode)
5146 fileProc = proc; /* I can't see a way not */
5147 fileOpenMode = openMode; /* to use globals here */
5148 { // [HGM] use file-selector dialog stolen from Ghostview
5150 int index; // this is not supported yet
5152 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5153 def, openMode, NULL, &name))
5154 (void) (*fileProc)(f, index=0, name);
5158 void FileNamePopDown()
5160 if (!filenameUp) return;
5161 XtPopdown(fileNameShell);
5162 XtDestroyWidget(fileNameShell);
5167 void FileNameCallback(w, client_data, call_data)
5169 XtPointer client_data, call_data;
5174 XtSetArg(args[0], XtNlabel, &name);
5175 XtGetValues(w, args, 1);
5177 if (strcmp(name, _("cancel")) == 0) {
5182 FileNameAction(w, NULL, NULL, NULL);
5185 void FileNameAction(w, event, prms, nprms)
5197 name = XawDialogGetValueString(w = XtParent(w));
5199 if ((name != NULL) && (*name != NULLCHAR)) {
5200 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
5201 XtPopdown(w = XtParent(XtParent(w)));
5205 p = strrchr(buf, ' ');
5212 fullname = ExpandPathName(buf);
5214 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5217 f = fopen(fullname, fileOpenMode);
5219 DisplayError(_("Failed to open file"), errno);
5221 (void) (*fileProc)(f, index, buf);
5228 XtPopdown(w = XtParent(XtParent(w)));
5234 void PromotionPopUp()
5237 Widget dialog, layout;
5239 Dimension bw_width, pw_width;
5243 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5244 XtGetValues(boardWidget, args, j);
5247 XtSetArg(args[j], XtNresizable, True); j++;
5248 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5250 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5251 shellWidget, args, j);
5253 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5254 layoutArgs, XtNumber(layoutArgs));
5257 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5258 XtSetArg(args[j], XtNborderWidth, 0); j++;
5259 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5262 if(gameInfo.variant != VariantShogi) {
5263 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) {
5264 XawDialogAddButton(dialog, _("Warlord"), PromotionCallback,
5265 (XtPointer) dialog);
5266 XawDialogAddButton(dialog, _("General"), PromotionCallback,
5267 (XtPointer) dialog);
5268 XawDialogAddButton(dialog, _("Lieutenant"), PromotionCallback,
5269 (XtPointer) dialog);
5270 XawDialogAddButton(dialog, _("Captain"), PromotionCallback,
5271 (XtPointer) dialog);
5273 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5274 (XtPointer) dialog);
5275 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5276 (XtPointer) dialog);
5277 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5278 (XtPointer) dialog);
5279 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5280 (XtPointer) dialog);
5282 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5283 gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
\r
5284 gameInfo.variant == VariantGiveaway) {
5285 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5286 (XtPointer) dialog);
5288 if(gameInfo.variant == VariantCapablanca ||
5289 gameInfo.variant == VariantGothic ||
5290 gameInfo.variant == VariantCapaRandom) {
5291 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5292 (XtPointer) dialog);
5293 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5294 (XtPointer) dialog);
5296 } else // [HGM] shogi
5298 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5299 (XtPointer) dialog);
5300 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5301 (XtPointer) dialog);
5303 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5304 (XtPointer) dialog);
5306 XtRealizeWidget(promotionShell);
5307 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5310 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5311 XtGetValues(promotionShell, args, j);
5313 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5314 lineGap + squareSize/3 +
5315 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5316 0 : 6*(squareSize + lineGap)), &x, &y);
5319 XtSetArg(args[j], XtNx, x); j++;
5320 XtSetArg(args[j], XtNy, y); j++;
5321 XtSetValues(promotionShell, args, j);
5323 XtPopup(promotionShell, XtGrabNone);
5328 void PromotionPopDown()
5330 if (!promotionUp) return;
5331 XtPopdown(promotionShell);
5332 XtDestroyWidget(promotionShell);
5333 promotionUp = False;
5336 void PromotionCallback(w, client_data, call_data)
5338 XtPointer client_data, call_data;
5344 XtSetArg(args[0], XtNlabel, &name);
5345 XtGetValues(w, args, 1);
5349 if (fromX == -1) return;
5351 if (strcmp(name, _("cancel")) == 0) {
5355 } else if (strcmp(name, _("Knight")) == 0) {
5357 } else if (strcmp(name, _("Promote")) == 0) {
5359 } else if (strcmp(name, _("Defer")) == 0) {
5362 promoChar = ToLower(name[0]);
5365 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5367 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5368 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5373 void ErrorCallback(w, client_data, call_data)
5375 XtPointer client_data, call_data;
5378 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5380 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5386 if (!errorUp) return;
5388 XtPopdown(errorShell);
5389 XtDestroyWidget(errorShell);
5390 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5393 void ErrorPopUp(title, label, modal)
5394 char *title, *label;
5398 Widget dialog, layout;
5402 Dimension bw_width, pw_width;
5403 Dimension pw_height;
5407 XtSetArg(args[i], XtNresizable, True); i++;
5408 XtSetArg(args[i], XtNtitle, title); i++;
5410 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5411 shellWidget, args, i);
5413 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5414 layoutArgs, XtNumber(layoutArgs));
5417 XtSetArg(args[i], XtNlabel, label); i++;
5418 XtSetArg(args[i], XtNborderWidth, 0); i++;
5419 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5422 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5424 XtRealizeWidget(errorShell);
5425 CatchDeleteWindow(errorShell, "ErrorPopDown");
5428 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5429 XtGetValues(boardWidget, args, i);
5431 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5432 XtSetArg(args[i], XtNheight, &pw_height); i++;
5433 XtGetValues(errorShell, args, i);
5436 /* This code seems to tickle an X bug if it is executed too soon
5437 after xboard starts up. The coordinates get transformed as if
5438 the main window was positioned at (0, 0).
5440 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5441 0 - pw_height + squareSize / 3, &x, &y);
5443 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5444 RootWindowOfScreen(XtScreen(boardWidget)),
5445 (bw_width - pw_width) / 2,
5446 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5450 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5453 XtSetArg(args[i], XtNx, x); i++;
5454 XtSetArg(args[i], XtNy, y); i++;
5455 XtSetValues(errorShell, args, i);
5458 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5461 /* Disable all user input other than deleting the window */
5462 static int frozen = 0;
5466 /* Grab by a widget that doesn't accept input */
5467 XtAddGrab(messageWidget, TRUE, FALSE);
5471 /* Undo a FreezeUI */
5474 if (!frozen) return;
5475 XtRemoveGrab(messageWidget);
5479 char *ModeToWidgetName(mode)
5483 case BeginningOfGame:
5484 if (appData.icsActive)
5485 return "menuMode.ICS Client";
5486 else if (appData.noChessProgram ||
5487 *appData.cmailGameName != NULLCHAR)
5488 return "menuMode.Edit Game";
5490 return "menuMode.Machine Black";
5491 case MachinePlaysBlack:
5492 return "menuMode.Machine Black";
5493 case MachinePlaysWhite:
5494 return "menuMode.Machine White";
5496 return "menuMode.Analysis Mode";
5498 return "menuMode.Analyze File";
5499 case TwoMachinesPlay:
5500 return "menuMode.Two Machines";
5502 return "menuMode.Edit Game";
5503 case PlayFromGameFile:
5504 return "menuFile.Load Game";
5506 return "menuMode.Edit Position";
5508 return "menuMode.Training";
5509 case IcsPlayingWhite:
5510 case IcsPlayingBlack:
5514 return "menuMode.ICS Client";
5521 void ModeHighlight()
5524 static int oldPausing = FALSE;
5525 static GameMode oldmode = (GameMode) -1;
5528 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5530 if (pausing != oldPausing) {
5531 oldPausing = pausing;
5533 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5535 XtSetArg(args[0], XtNleftBitmap, None);
5537 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5540 if (appData.showButtonBar) {
5541 /* Always toggle, don't set. Previous code messes up when
5542 invoked while the button is pressed, as releasing it
5543 toggles the state again. */
5546 XtSetArg(args[0], XtNbackground, &oldbg);
5547 XtSetArg(args[1], XtNforeground, &oldfg);
5548 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5550 XtSetArg(args[0], XtNbackground, oldfg);
5551 XtSetArg(args[1], XtNforeground, oldbg);
5553 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5557 wname = ModeToWidgetName(oldmode);
5558 if (wname != NULL) {
5559 XtSetArg(args[0], XtNleftBitmap, None);
5560 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5562 wname = ModeToWidgetName(gameMode);
5563 if (wname != NULL) {
5564 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5565 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5569 /* Maybe all the enables should be handled here, not just this one */
5570 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5571 gameMode == Training || gameMode == PlayFromGameFile);
5576 * Button/menu procedures
5578 void ResetProc(w, event, prms, nprms)
5587 int LoadGamePopUp(f, gameNumber, title)
5592 cmailMsgLoaded = FALSE;
5593 if (gameNumber == 0) {
5594 int error = GameListBuild(f);
5596 DisplayError(_("Cannot build game list"), error);
5597 } else if (!ListEmpty(&gameList) &&
5598 ((ListGame *) gameList.tailPred)->number > 1) {
5599 GameListPopUp(f, title);
5605 return LoadGame(f, gameNumber, title, FALSE);
5608 void LoadGameProc(w, event, prms, nprms)
5614 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5617 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5620 void LoadNextGameProc(w, event, prms, nprms)
5629 void LoadPrevGameProc(w, event, prms, nprms)
5638 void ReloadGameProc(w, event, prms, nprms)
5647 void LoadNextPositionProc(w, event, prms, nprms)
5656 void LoadPrevPositionProc(w, event, prms, nprms)
5665 void ReloadPositionProc(w, event, prms, nprms)
5674 void LoadPositionProc(w, event, prms, nprms)
5680 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5683 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5686 void SaveGameProc(w, event, prms, nprms)
5692 FileNamePopUp(_("Save game file name?"),
5693 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5697 void SavePositionProc(w, event, prms, nprms)
5703 FileNamePopUp(_("Save position file name?"),
5704 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5708 void ReloadCmailMsgProc(w, event, prms, nprms)
5714 ReloadCmailMsgEvent(FALSE);
5717 void MailMoveProc(w, event, prms, nprms)
5726 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5727 char *selected_fen_position=NULL;
5730 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5731 Atom *type_return, XtPointer *value_return,
5732 unsigned long *length_return, int *format_return)
5734 char *selection_tmp;
5736 if (!selected_fen_position) return False; /* should never happen */
5737 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5738 /* note: since no XtSelectionDoneProc was registered, Xt will
5739 * automatically call XtFree on the value returned. So have to
5740 * make a copy of it allocated with XtMalloc */
5741 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5742 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
5744 *value_return=selection_tmp;
5745 *length_return=strlen(selection_tmp);
5746 *type_return=*target;
5747 *format_return = 8; /* bits per byte */
5749 } else if (*target == XA_TARGETS(xDisplay)) {
5750 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5751 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5752 targets_tmp[1] = XA_STRING;
5753 *value_return = targets_tmp;
5754 *type_return = XA_ATOM;
5756 *format_return = 8 * sizeof(Atom);
5757 if (*format_return > 32) {
5758 *length_return *= *format_return / 32;
5759 *format_return = 32;
5767 /* note: when called from menu all parameters are NULL, so no clue what the
5768 * Widget which was clicked on was, or what the click event was
5770 void CopyPositionProc(w, event, prms, nprms)
5777 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5778 * have a notion of a position that is selected but not copied.
5779 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5781 if(gameMode == EditPosition) EditPositionDone(TRUE);
5782 if (selected_fen_position) free(selected_fen_position);
5783 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5784 if (!selected_fen_position) return;
5785 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5787 SendPositionSelection,
5788 NULL/* lose_ownership_proc */ ,
5789 NULL/* transfer_done_proc */);
5790 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5792 SendPositionSelection,
5793 NULL/* lose_ownership_proc */ ,
5794 NULL/* transfer_done_proc */);
5797 /* function called when the data to Paste is ready */
5799 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5800 Atom *type, XtPointer value, unsigned long *len, int *format)
5803 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5804 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5805 EditPositionPasteFEN(fenstr);
5809 /* called when Paste Position button is pressed,
5810 * all parameters will be NULL */
5811 void PastePositionProc(w, event, prms, nprms)
5817 XtGetSelectionValue(menuBarWidget,
5818 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5819 /* (XtSelectionCallbackProc) */ PastePositionCB,
5820 NULL, /* client_data passed to PastePositionCB */
5822 /* better to use the time field from the event that triggered the
5823 * call to this function, but that isn't trivial to get
5831 SendGameSelection(Widget w, Atom *selection, Atom *target,
5832 Atom *type_return, XtPointer *value_return,
5833 unsigned long *length_return, int *format_return)
5835 char *selection_tmp;
5837 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5838 FILE* f = fopen(gameCopyFilename, "r");
5841 if (f == NULL) return False;
5845 selection_tmp = XtMalloc(len + 1);
5846 count = fread(selection_tmp, 1, len, f);
5849 XtFree(selection_tmp);
5852 selection_tmp[len] = NULLCHAR;
5853 *value_return = selection_tmp;
5854 *length_return = len;
5855 *type_return = *target;
5856 *format_return = 8; /* bits per byte */
5858 } else if (*target == XA_TARGETS(xDisplay)) {
5859 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5860 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5861 targets_tmp[1] = XA_STRING;
5862 *value_return = targets_tmp;
5863 *type_return = XA_ATOM;
5865 *format_return = 8 * sizeof(Atom);
5866 if (*format_return > 32) {
5867 *length_return *= *format_return / 32;
5868 *format_return = 32;
5876 /* note: when called from menu all parameters are NULL, so no clue what the
5877 * Widget which was clicked on was, or what the click event was
5879 void CopyGameProc(w, event, prms, nprms)
5887 ret = SaveGameToFile(gameCopyFilename, FALSE);
5891 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5892 * have a notion of a game that is selected but not copied.
5893 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5895 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5898 NULL/* lose_ownership_proc */ ,
5899 NULL/* transfer_done_proc */);
5900 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5903 NULL/* lose_ownership_proc */ ,
5904 NULL/* transfer_done_proc */);
5907 /* function called when the data to Paste is ready */
5909 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5910 Atom *type, XtPointer value, unsigned long *len, int *format)
5913 if (value == NULL || *len == 0) {
5914 return; /* nothing had been selected to copy */
5916 f = fopen(gamePasteFilename, "w");
5918 DisplayError(_("Can't open temp file"), errno);
5921 fwrite(value, 1, *len, f);
5924 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5927 /* called when Paste Game button is pressed,
5928 * all parameters will be NULL */
5929 void PasteGameProc(w, event, prms, nprms)
5935 XtGetSelectionValue(menuBarWidget,
5936 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5937 /* (XtSelectionCallbackProc) */ PasteGameCB,
5938 NULL, /* client_data passed to PasteGameCB */
5940 /* better to use the time field from the event that triggered the
5941 * call to this function, but that isn't trivial to get
5951 SaveGameProc(NULL, NULL, NULL, NULL);
5955 void QuitProc(w, event, prms, nprms)
5964 void PauseProc(w, event, prms, nprms)
5974 void MachineBlackProc(w, event, prms, nprms)
5980 MachineBlackEvent();
5983 void MachineWhiteProc(w, event, prms, nprms)
5989 MachineWhiteEvent();
5992 void AnalyzeModeProc(w, event, prms, nprms)
6000 if (!first.analysisSupport) {
6001 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6002 DisplayError(buf, 0);
6005 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
6006 if (appData.icsActive) {
6007 if (gameMode != IcsObserving) {
6008 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
6009 DisplayError(buf, 0);
6011 if (appData.icsEngineAnalyze) {
6012 if (appData.debugMode)
6013 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
6019 /* if enable, use want disable icsEngineAnalyze */
6020 if (appData.icsEngineAnalyze) {
6025 appData.icsEngineAnalyze = TRUE;
6026 if (appData.debugMode)
6027 fprintf(debugFP, _("ICS engine analyze starting... \n"));
6029 #ifndef OPTIONSDIALOG
6030 if (!appData.showThinking)
6031 ShowThinkingProc(w,event,prms,nprms);
6037 void AnalyzeFileProc(w, event, prms, nprms)
6043 if (!first.analysisSupport) {
6045 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6046 DisplayError(buf, 0);
6050 #ifndef OPTIONSDIALOG
6051 if (!appData.showThinking)
6052 ShowThinkingProc(w,event,prms,nprms);
6055 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
6056 AnalysisPeriodicEvent(1);
6059 void TwoMachinesProc(w, event, prms, nprms)
6068 void MatchProc(w, event, prms, nprms)
6074 if(gameMode != BeginningOfGame) { DisplayError(_("You can only start a match from the initial position."), 0); return; }
6075 matchMode = 2; // This is back-end, really
\r
6076 appData.matchGames = appData.defaultMatchGames;
\r
6078 first.matchWins = second.matchWins = 0;
\r
6082 void IcsClientProc(w, event, prms, nprms)
6091 void EditGameProc(w, event, prms, nprms)
6100 void EditPositionProc(w, event, prms, nprms)
6106 EditPositionEvent();
6109 void TrainingProc(w, event, prms, nprms)
6118 void EditCommentProc(w, event, prms, nprms)
6125 EditCommentPopDown();
6131 void IcsInputBoxProc(w, event, prms, nprms)
6137 if (!PopDown(4)) ICSInputBoxPopUp();
6140 void AcceptProc(w, event, prms, nprms)
6149 void DeclineProc(w, event, prms, nprms)
6158 void RematchProc(w, event, prms, nprms)
6167 void CallFlagProc(w, event, prms, nprms)
6176 void DrawProc(w, event, prms, nprms)
6185 void AbortProc(w, event, prms, nprms)
6194 void AdjournProc(w, event, prms, nprms)
6203 void ResignProc(w, event, prms, nprms)
6212 void AdjuWhiteProc(w, event, prms, nprms)
6218 UserAdjudicationEvent(+1);
6221 void AdjuBlackProc(w, event, prms, nprms)
6227 UserAdjudicationEvent(-1);
6230 void AdjuDrawProc(w, event, prms, nprms)
6236 UserAdjudicationEvent(0);
6239 void EnterKeyProc(w, event, prms, nprms)
6245 if (shellUp[4] == True)
6249 void UpKeyProc(w, event, prms, nprms)
6254 { // [HGM] input: let up-arrow recall previous line from history
6261 if (!shellUp[4]) return;
6262 edit = boxOptions[0].handle;
6264 XtSetArg(args[j], XtNstring, &val); j++;
6265 XtGetValues(edit, args, j);
6266 val = PrevInHistory(val);
6267 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6268 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6270 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6271 XawTextReplace(edit, 0, 0, &t);
6272 XawTextSetInsertionPoint(edit, 9999);
6276 void DownKeyProc(w, event, prms, nprms)
6281 { // [HGM] input: let down-arrow recall next line from history
6286 if (!shellUp[4]) return;
6287 edit = boxOptions[0].handle;
6288 val = NextInHistory();
6289 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6290 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6292 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6293 XawTextReplace(edit, 0, 0, &t);
6294 XawTextSetInsertionPoint(edit, 9999);
6298 void StopObservingProc(w, event, prms, nprms)
6304 StopObservingEvent();
6307 void StopExaminingProc(w, event, prms, nprms)
6313 StopExaminingEvent();
6316 void UploadProc(w, event, prms, nprms)
6326 void ForwardProc(w, event, prms, nprms)
6336 void BackwardProc(w, event, prms, nprms)
6345 void ToStartProc(w, event, prms, nprms)
6354 void ToEndProc(w, event, prms, nprms)
6363 void RevertProc(w, event, prms, nprms)
6372 void AnnotateProc(w, event, prms, nprms)
6381 void TruncateGameProc(w, event, prms, nprms)
6387 TruncateGameEvent();
6389 void RetractMoveProc(w, event, prms, nprms)
6398 void MoveNowProc(w, event, prms, nprms)
6407 void FlipViewProc(w, event, prms, nprms)
6413 flipView = !flipView;
6414 DrawPosition(True, NULL);
6417 void PonderNextMoveProc(w, event, prms, nprms)
6425 PonderNextMoveEvent(!appData.ponderNextMove);
6426 #ifndef OPTIONSDIALOG
6427 if (appData.ponderNextMove) {
6428 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6430 XtSetArg(args[0], XtNleftBitmap, None);
6432 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6437 #ifndef OPTIONSDIALOG
6438 void AlwaysQueenProc(w, event, prms, nprms)
6446 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6448 if (appData.alwaysPromoteToQueen) {
6449 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6451 XtSetArg(args[0], XtNleftBitmap, None);
6453 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6457 void AnimateDraggingProc(w, event, prms, nprms)
6465 appData.animateDragging = !appData.animateDragging;
6467 if (appData.animateDragging) {
6468 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6471 XtSetArg(args[0], XtNleftBitmap, None);
6473 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6477 void AnimateMovingProc(w, event, prms, nprms)
6485 appData.animate = !appData.animate;
6487 if (appData.animate) {
6488 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6491 XtSetArg(args[0], XtNleftBitmap, None);
6493 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6497 void AutoflagProc(w, event, prms, nprms)
6505 appData.autoCallFlag = !appData.autoCallFlag;
6507 if (appData.autoCallFlag) {
6508 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6510 XtSetArg(args[0], XtNleftBitmap, None);
6512 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6516 void AutoflipProc(w, event, prms, nprms)
6524 appData.autoFlipView = !appData.autoFlipView;
6526 if (appData.autoFlipView) {
6527 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6529 XtSetArg(args[0], XtNleftBitmap, None);
6531 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6535 void BlindfoldProc(w, event, prms, nprms)
6543 appData.blindfold = !appData.blindfold;
6545 if (appData.blindfold) {
6546 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6548 XtSetArg(args[0], XtNleftBitmap, None);
6550 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6553 DrawPosition(True, NULL);
6556 void TestLegalityProc(w, event, prms, nprms)
6564 appData.testLegality = !appData.testLegality;
6566 if (appData.testLegality) {
6567 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6569 XtSetArg(args[0], XtNleftBitmap, None);
6571 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6576 void FlashMovesProc(w, event, prms, nprms)
6584 if (appData.flashCount == 0) {
6585 appData.flashCount = 3;
6587 appData.flashCount = -appData.flashCount;
6590 if (appData.flashCount > 0) {
6591 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6593 XtSetArg(args[0], XtNleftBitmap, None);
6595 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6600 void HighlightDraggingProc(w, event, prms, nprms)
6608 appData.highlightDragging = !appData.highlightDragging;
6610 if (appData.highlightDragging) {
6611 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6613 XtSetArg(args[0], XtNleftBitmap, None);
6615 XtSetValues(XtNameToWidget(menuBarWidget,
6616 "menuOptions.Highlight Dragging"), args, 1);
6620 void HighlightLastMoveProc(w, event, prms, nprms)
6628 appData.highlightLastMove = !appData.highlightLastMove;
6630 if (appData.highlightLastMove) {
6631 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6633 XtSetArg(args[0], XtNleftBitmap, None);
6635 XtSetValues(XtNameToWidget(menuBarWidget,
6636 "menuOptions.Highlight Last Move"), args, 1);
6639 void HighlightArrowProc(w, event, prms, nprms)
6647 appData.highlightMoveWithArrow = !appData.highlightMoveWithArrow;
6649 if (appData.highlightMoveWithArrow) {
6650 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6652 XtSetArg(args[0], XtNleftBitmap, None);
6654 XtSetValues(XtNameToWidget(menuBarWidget,
6655 "menuOptions.Arrow"), args, 1);
6659 void IcsAlarmProc(w, event, prms, nprms)
6667 appData.icsAlarm = !appData.icsAlarm;
6669 if (appData.icsAlarm) {
6670 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6672 XtSetArg(args[0], XtNleftBitmap, None);
6674 XtSetValues(XtNameToWidget(menuBarWidget,
6675 "menuOptions.ICS Alarm"), args, 1);
6679 void MoveSoundProc(w, event, prms, nprms)
6687 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6689 if (appData.ringBellAfterMoves) {
6690 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6692 XtSetArg(args[0], XtNleftBitmap, None);
6694 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6698 void OneClickProc(w, event, prms, nprms)
6706 appData.oneClick = !appData.oneClick;
6708 if (appData.oneClick) {
6709 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6711 XtSetArg(args[0], XtNleftBitmap, None);
6713 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.OneClick"),
6717 void PeriodicUpdatesProc(w, event, prms, nprms)
6725 PeriodicUpdatesEvent(!appData.periodicUpdates);
6727 if (appData.periodicUpdates) {
6728 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6730 XtSetArg(args[0], XtNleftBitmap, None);
6732 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6736 void PopupExitMessageProc(w, event, prms, nprms)
6744 appData.popupExitMessage = !appData.popupExitMessage;
6746 if (appData.popupExitMessage) {
6747 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6749 XtSetArg(args[0], XtNleftBitmap, None);
6751 XtSetValues(XtNameToWidget(menuBarWidget,
6752 "menuOptions.Popup Exit Message"), args, 1);
6755 void PopupMoveErrorsProc(w, event, prms, nprms)
6763 appData.popupMoveErrors = !appData.popupMoveErrors;
6765 if (appData.popupMoveErrors) {
6766 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6768 XtSetArg(args[0], XtNleftBitmap, None);
6770 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6775 void PremoveProc(w, event, prms, nprms)
6783 appData.premove = !appData.premove;
6785 if (appData.premove) {
6786 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6788 XtSetArg(args[0], XtNleftBitmap, None);
6790 XtSetValues(XtNameToWidget(menuBarWidget,
6791 "menuOptions.Premove"), args, 1);
6795 void ShowCoordsProc(w, event, prms, nprms)
6803 appData.showCoords = !appData.showCoords;
6805 if (appData.showCoords) {
6806 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6808 XtSetArg(args[0], XtNleftBitmap, None);
6810 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6813 DrawPosition(True, NULL);
6816 void ShowThinkingProc(w, event, prms, nprms)
6822 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6823 ShowThinkingEvent();
6826 void HideThinkingProc(w, event, prms, nprms)
6834 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6835 ShowThinkingEvent();
6837 if (appData.hideThinkingFromHuman) {
6838 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6840 XtSetArg(args[0], XtNleftBitmap, None);
6842 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6847 void SaveOnExitProc(w, event, prms, nprms)
6855 saveSettingsOnExit = !saveSettingsOnExit;
6857 if (saveSettingsOnExit) {
6858 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6860 XtSetArg(args[0], XtNleftBitmap, None);
6862 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6866 void SaveSettingsProc(w, event, prms, nprms)
6872 SaveSettings(settingsFileName);
6875 void InfoProc(w, event, prms, nprms)
6882 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6887 void ManProc(w, event, prms, nprms)
6895 if (nprms && *nprms > 0)
6899 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6903 void HintProc(w, event, prms, nprms)
6912 void BookProc(w, event, prms, nprms)
6921 void AboutProc(w, event, prms, nprms)
6929 char *zippy = " (with Zippy code)";
6933 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6934 programVersion, zippy,
6935 "Copyright 1991 Digital Equipment Corporation",
6936 "Enhancements Copyright 1992-2009 Free Software Foundation",
6937 "Enhancements Copyright 2005 Alessandro Scotti",
6938 PACKAGE, " is free software and carries NO WARRANTY;",
6939 "see the file COPYING for more information.");
6940 ErrorPopUp(_("About XBoard"), buf, FALSE);
6943 void DebugProc(w, event, prms, nprms)
6949 appData.debugMode = !appData.debugMode;
6952 void AboutGameProc(w, event, prms, nprms)
6961 void NothingProc(w, event, prms, nprms)
6970 void Iconify(w, event, prms, nprms)
6979 XtSetArg(args[0], XtNiconic, True);
6980 XtSetValues(shellWidget, args, 1);
6983 void DisplayMessage(message, extMessage)
6984 char *message, *extMessage;
6986 /* display a message in the message widget */
6995 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
7000 message = extMessage;
7004 /* need to test if messageWidget already exists, since this function
7005 can also be called during the startup, if for example a Xresource
7006 is not set up correctly */
7009 XtSetArg(arg, XtNlabel, message);
7010 XtSetValues(messageWidget, &arg, 1);
7016 void DisplayTitle(text)
7021 char title[MSG_SIZ];
7024 if (text == NULL) text = "";
7026 if (appData.titleInWindow) {
7028 XtSetArg(args[i], XtNlabel, text); i++;
7029 XtSetValues(titleWidget, args, i);
7032 if (*text != NULLCHAR) {
7033 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
7034 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
7035 } else if (appData.icsActive) {
7036 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7037 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7038 } else if (appData.cmailGameName[0] != NULLCHAR) {
7039 snprintf(icon, sizeof(icon), "%s", "CMail");
7040 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7042 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7043 } else if (gameInfo.variant == VariantGothic) {
7044 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7045 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
7048 } else if (gameInfo.variant == VariantFalcon) {
7049 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7050 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
7052 } else if (appData.noChessProgram) {
7053 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7054 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
7056 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
7057 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7060 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7061 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7062 XtSetValues(shellWidget, args, i);
7067 DisplayError(message, error)
7074 if (appData.debugMode || appData.matchMode) {
7075 fprintf(stderr, "%s: %s\n", programName, message);
7078 if (appData.debugMode || appData.matchMode) {
7079 fprintf(stderr, "%s: %s: %s\n",
7080 programName, message, strerror(error));
7082 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7085 ErrorPopUp(_("Error"), message, FALSE);
7089 void DisplayMoveError(message)
7094 DrawPosition(FALSE, NULL);
7095 if (appData.debugMode || appData.matchMode) {
7096 fprintf(stderr, "%s: %s\n", programName, message);
7098 if (appData.popupMoveErrors) {
7099 ErrorPopUp(_("Error"), message, FALSE);
7101 DisplayMessage(message, "");
7106 void DisplayFatalError(message, error, status)
7112 errorExitStatus = status;
7114 fprintf(stderr, "%s: %s\n", programName, message);
7116 fprintf(stderr, "%s: %s: %s\n",
7117 programName, message, strerror(error));
7118 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7121 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7122 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7128 void DisplayInformation(message)
7132 ErrorPopUp(_("Information"), message, TRUE);
7135 void DisplayNote(message)
7139 ErrorPopUp(_("Note"), message, FALSE);
7143 NullXErrorCheck(dpy, error_event)
7145 XErrorEvent *error_event;
7150 void DisplayIcsInteractionTitle(message)
7153 if (oldICSInteractionTitle == NULL) {
7154 /* Magic to find the old window title, adapted from vim */
7155 char *wina = getenv("WINDOWID");
7157 Window win = (Window) atoi(wina);
7158 Window root, parent, *children;
7159 unsigned int nchildren;
7160 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7162 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7163 if (!XQueryTree(xDisplay, win, &root, &parent,
7164 &children, &nchildren)) break;
7165 if (children) XFree((void *)children);
7166 if (parent == root || parent == 0) break;
7169 XSetErrorHandler(oldHandler);
7171 if (oldICSInteractionTitle == NULL) {
7172 oldICSInteractionTitle = "xterm";
7175 printf("\033]0;%s\007", message);
7179 char pendingReplyPrefix[MSG_SIZ];
7180 ProcRef pendingReplyPR;
7182 void AskQuestionProc(w, event, prms, nprms)
7189 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7193 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7196 void AskQuestionPopDown()
7198 if (!askQuestionUp) return;
7199 XtPopdown(askQuestionShell);
7200 XtDestroyWidget(askQuestionShell);
7201 askQuestionUp = False;
7204 void AskQuestionReplyAction(w, event, prms, nprms)
7214 reply = XawDialogGetValueString(w = XtParent(w));
7215 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
7216 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
7217 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
7218 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
7219 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7220 AskQuestionPopDown();
7222 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7225 void AskQuestionCallback(w, client_data, call_data)
7227 XtPointer client_data, call_data;
7232 XtSetArg(args[0], XtNlabel, &name);
7233 XtGetValues(w, args, 1);
7235 if (strcmp(name, _("cancel")) == 0) {
7236 AskQuestionPopDown();
7238 AskQuestionReplyAction(w, NULL, NULL, NULL);
7242 void AskQuestion(title, question, replyPrefix, pr)
7243 char *title, *question, *replyPrefix;
7247 Widget popup, layout, dialog, edit;
7253 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
7254 pendingReplyPR = pr;
7257 XtSetArg(args[i], XtNresizable, True); i++;
7258 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7259 askQuestionShell = popup =
7260 XtCreatePopupShell(title, transientShellWidgetClass,
7261 shellWidget, args, i);
7264 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7265 layoutArgs, XtNumber(layoutArgs));
7268 XtSetArg(args[i], XtNlabel, question); i++;
7269 XtSetArg(args[i], XtNvalue, ""); i++;
7270 XtSetArg(args[i], XtNborderWidth, 0); i++;
7271 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7274 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7275 (XtPointer) dialog);
7276 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7277 (XtPointer) dialog);
7279 XtRealizeWidget(popup);
7280 CatchDeleteWindow(popup, "AskQuestionPopDown");
7282 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7283 &x, &y, &win_x, &win_y, &mask);
7285 XtSetArg(args[0], XtNx, x - 10);
7286 XtSetArg(args[1], XtNy, y - 30);
7287 XtSetValues(popup, args, 2);
7289 XtPopup(popup, XtGrabExclusive);
7290 askQuestionUp = True;
7292 edit = XtNameToWidget(dialog, "*value");
7293 XtSetKeyboardFocus(popup, edit);
7301 if (*name == NULLCHAR) {
7303 } else if (strcmp(name, "$") == 0) {
7304 putc(BELLCHAR, stderr);
7307 char *prefix = "", *sep = "";
7308 if(!strchr(name, '/')) { prefix = appData.soundDirectory; sep = "/"; }
7309 snprintf(buf, sizeof(buf), "%s '%s%s%s' &", appData.soundProgram, prefix, sep, name);
7317 PlaySound(appData.soundMove);
7323 PlaySound(appData.soundIcsWin);
7329 PlaySound(appData.soundIcsLoss);
7335 PlaySound(appData.soundIcsDraw);
7339 PlayIcsUnfinishedSound()
7341 PlaySound(appData.soundIcsUnfinished);
7347 PlaySound(appData.soundIcsAlarm);
7353 system("stty echo");
7359 system("stty -echo");
7363 Colorize(cc, continuation)
7368 int count, outCount, error;
7370 if (textColors[(int)cc].bg > 0) {
7371 if (textColors[(int)cc].fg > 0) {
7372 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7373 textColors[(int)cc].fg, textColors[(int)cc].bg);
7375 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7376 textColors[(int)cc].bg);
7379 if (textColors[(int)cc].fg > 0) {
7380 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7381 textColors[(int)cc].fg);
7383 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7386 count = strlen(buf);
7387 outCount = OutputToProcess(NoProc, buf, count, &error);
7388 if (outCount < count) {
7389 DisplayFatalError(_("Error writing to display"), error, 1);
7392 if (continuation) return;
7395 PlaySound(appData.soundShout);
7398 PlaySound(appData.soundSShout);
7401 PlaySound(appData.soundChannel1);
7404 PlaySound(appData.soundChannel);
7407 PlaySound(appData.soundKibitz);
7410 PlaySound(appData.soundTell);
7412 case ColorChallenge:
7413 PlaySound(appData.soundChallenge);
7416 PlaySound(appData.soundRequest);
7419 PlaySound(appData.soundSeek);
7430 return getpwuid(getuid())->pw_name;
7434 ExpandPathName(path)
7437 static char static_buf[4*MSG_SIZ];
7438 char *d, *s, buf[4*MSG_SIZ];
7444 while (*s && isspace(*s))
7453 if (*(s+1) == '/') {
7454 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7458 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7459 { char *p; if(p = strchr(buf, '/')) *p = 0; }
7460 pwd = getpwnam(buf);
7463 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7467 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7468 strcat(d, strchr(s+1, '/'));
7472 safeStrCpy(d, s, 4*MSG_SIZ );
7479 static char host_name[MSG_SIZ];
7481 #if HAVE_GETHOSTNAME
7482 gethostname(host_name, MSG_SIZ);
7484 #else /* not HAVE_GETHOSTNAME */
7485 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7486 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7488 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7490 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7491 #endif /* not HAVE_GETHOSTNAME */
7494 XtIntervalId delayedEventTimerXID = 0;
7495 DelayedEventCallback delayedEventCallback = 0;
7500 delayedEventTimerXID = 0;
7501 delayedEventCallback();
7505 ScheduleDelayedEvent(cb, millisec)
7506 DelayedEventCallback cb; long millisec;
7508 if(delayedEventTimerXID && delayedEventCallback == cb)
7509 // [HGM] alive: replace, rather than add or flush identical event
7510 XtRemoveTimeOut(delayedEventTimerXID);
7511 delayedEventCallback = cb;
7512 delayedEventTimerXID =
7513 XtAppAddTimeOut(appContext, millisec,
7514 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7517 DelayedEventCallback
7520 if (delayedEventTimerXID) {
7521 return delayedEventCallback;
7528 CancelDelayedEvent()
7530 if (delayedEventTimerXID) {
7531 XtRemoveTimeOut(delayedEventTimerXID);
7532 delayedEventTimerXID = 0;
7536 XtIntervalId loadGameTimerXID = 0;
7538 int LoadGameTimerRunning()
7540 return loadGameTimerXID != 0;
7543 int StopLoadGameTimer()
7545 if (loadGameTimerXID != 0) {
7546 XtRemoveTimeOut(loadGameTimerXID);
7547 loadGameTimerXID = 0;
7555 LoadGameTimerCallback(arg, id)
7559 loadGameTimerXID = 0;
7564 StartLoadGameTimer(millisec)
7568 XtAppAddTimeOut(appContext, millisec,
7569 (XtTimerCallbackProc) LoadGameTimerCallback,
7573 XtIntervalId analysisClockXID = 0;
7576 AnalysisClockCallback(arg, id)
7580 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7581 || appData.icsEngineAnalyze) { // [DM]
7582 AnalysisPeriodicEvent(0);
7583 StartAnalysisClock();
7588 StartAnalysisClock()
7591 XtAppAddTimeOut(appContext, 2000,
7592 (XtTimerCallbackProc) AnalysisClockCallback,
7596 XtIntervalId clockTimerXID = 0;
7598 int ClockTimerRunning()
7600 return clockTimerXID != 0;
7603 int StopClockTimer()
7605 if (clockTimerXID != 0) {
7606 XtRemoveTimeOut(clockTimerXID);
7615 ClockTimerCallback(arg, id)
7624 StartClockTimer(millisec)
7628 XtAppAddTimeOut(appContext, millisec,
7629 (XtTimerCallbackProc) ClockTimerCallback,
7634 DisplayTimerLabel(w, color, timer, highlight)
7643 /* check for low time warning */
7644 Pixel foregroundOrWarningColor = timerForegroundPixel;
7647 appData.lowTimeWarning &&
7648 (timer / 1000) < appData.icsAlarmTime)
7649 foregroundOrWarningColor = lowTimeWarningColor;
7651 if (appData.clockMode) {
7652 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7653 XtSetArg(args[0], XtNlabel, buf);
7655 snprintf(buf, MSG_SIZ, "%s ", color);
7656 XtSetArg(args[0], XtNlabel, buf);
7661 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7662 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7664 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7665 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7668 XtSetValues(w, args, 3);
7672 DisplayWhiteClock(timeRemaining, highlight)
7678 if(appData.noGUI) return;
7679 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7680 if (highlight && iconPixmap == bIconPixmap) {
7681 iconPixmap = wIconPixmap;
7682 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7683 XtSetValues(shellWidget, args, 1);
7688 DisplayBlackClock(timeRemaining, highlight)
7694 if(appData.noGUI) return;
7695 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7696 if (highlight && iconPixmap == wIconPixmap) {
7697 iconPixmap = bIconPixmap;
7698 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7699 XtSetValues(shellWidget, args, 1);
7717 int StartChildProcess(cmdLine, dir, pr)
7724 int to_prog[2], from_prog[2];
7728 if (appData.debugMode) {
7729 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7732 /* We do NOT feed the cmdLine to the shell; we just
7733 parse it into blank-separated arguments in the
7734 most simple-minded way possible.
7737 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7740 while(*p == ' ') p++;
7742 if(*p == '"' || *p == '\'')
7743 p = strchr(++argv[i-1], *p);
7744 else p = strchr(p, ' ');
7745 if (p == NULL) break;
7750 SetUpChildIO(to_prog, from_prog);
7752 if ((pid = fork()) == 0) {
7754 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7755 close(to_prog[1]); // first close the unused pipe ends
7756 close(from_prog[0]);
7757 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7758 dup2(from_prog[1], 1);
7759 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7760 close(from_prog[1]); // and closing again loses one of the pipes!
7761 if(fileno(stderr) >= 2) // better safe than sorry...
7762 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7764 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7769 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7771 execvp(argv[0], argv);
7773 /* If we get here, exec failed */
7778 /* Parent process */
7780 close(from_prog[1]);
7782 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7785 cp->fdFrom = from_prog[0];
7786 cp->fdTo = to_prog[1];
7791 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7792 static RETSIGTYPE AlarmCallBack(int n)
7798 DestroyChildProcess(pr, signalType)
7802 ChildProc *cp = (ChildProc *) pr;
7804 if (cp->kind != CPReal) return;
7806 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7807 signal(SIGALRM, AlarmCallBack);
7809 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7810 kill(cp->pid, SIGKILL); // kill it forcefully
7811 wait((int *) 0); // and wait again
7815 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7817 /* Process is exiting either because of the kill or because of
7818 a quit command sent by the backend; either way, wait for it to die.
7827 InterruptChildProcess(pr)
7830 ChildProc *cp = (ChildProc *) pr;
7832 if (cp->kind != CPReal) return;
7833 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7836 int OpenTelnet(host, port, pr)
7841 char cmdLine[MSG_SIZ];
7843 if (port[0] == NULLCHAR) {
7844 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7846 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7848 return StartChildProcess(cmdLine, "", pr);
7851 int OpenTCP(host, port, pr)
7857 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7858 #else /* !OMIT_SOCKETS */
7860 struct sockaddr_in sa;
7862 unsigned short uport;
7865 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7869 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7870 sa.sin_family = AF_INET;
7871 sa.sin_addr.s_addr = INADDR_ANY;
7872 uport = (unsigned short) 0;
7873 sa.sin_port = htons(uport);
7874 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7878 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7879 if (!(hp = gethostbyname(host))) {
7881 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7882 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7883 hp->h_addrtype = AF_INET;
7885 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7886 hp->h_addr_list[0] = (char *) malloc(4);
7887 hp->h_addr_list[0][0] = b0;
7888 hp->h_addr_list[0][1] = b1;
7889 hp->h_addr_list[0][2] = b2;
7890 hp->h_addr_list[0][3] = b3;
7895 sa.sin_family = hp->h_addrtype;
7896 uport = (unsigned short) atoi(port);
7897 sa.sin_port = htons(uport);
7898 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7900 if (connect(s, (struct sockaddr *) &sa,
7901 sizeof(struct sockaddr_in)) < 0) {
7905 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7912 #endif /* !OMIT_SOCKETS */
7917 int OpenCommPort(name, pr)
7924 fd = open(name, 2, 0);
7925 if (fd < 0) return errno;
7927 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7937 int OpenLoopback(pr)
7943 SetUpChildIO(to, from);
7945 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7948 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7955 int OpenRcmd(host, user, cmd, pr)
7956 char *host, *user, *cmd;
7959 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7963 #define INPUT_SOURCE_BUF_SIZE 8192
7972 char buf[INPUT_SOURCE_BUF_SIZE];
7977 DoInputCallback(closure, source, xid)
7982 InputSource *is = (InputSource *) closure;
7987 if (is->lineByLine) {
7988 count = read(is->fd, is->unused,
7989 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7991 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7994 is->unused += count;
7996 while (p < is->unused) {
7997 q = memchr(p, '\n', is->unused - p);
7998 if (q == NULL) break;
8000 (is->func)(is, is->closure, p, q - p, 0);
8004 while (p < is->unused) {
8009 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8014 (is->func)(is, is->closure, is->buf, count, error);
8018 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8025 ChildProc *cp = (ChildProc *) pr;
8027 is = (InputSource *) calloc(1, sizeof(InputSource));
8028 is->lineByLine = lineByLine;
8032 is->fd = fileno(stdin);
8034 is->kind = cp->kind;
8035 is->fd = cp->fdFrom;
8038 is->unused = is->buf;
8041 is->xid = XtAppAddInput(appContext, is->fd,
8042 (XtPointer) (XtInputReadMask),
8043 (XtInputCallbackProc) DoInputCallback,
8045 is->closure = closure;
8046 return (InputSourceRef) is;
8050 RemoveInputSource(isr)
8053 InputSource *is = (InputSource *) isr;
8055 if (is->xid == 0) return;
8056 XtRemoveInput(is->xid);
8060 int OutputToProcess(pr, message, count, outError)
8066 static int line = 0;
8067 ChildProc *cp = (ChildProc *) pr;
8072 if (appData.noJoin || !appData.useInternalWrap)
8073 outCount = fwrite(message, 1, count, stdout);
8076 int width = get_term_width();
8077 int len = wrap(NULL, message, count, width, &line);
8078 char *msg = malloc(len);
8082 outCount = fwrite(message, 1, count, stdout);
8085 dbgchk = wrap(msg, message, count, width, &line);
8086 if (dbgchk != len && appData.debugMode)
8087 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8088 outCount = fwrite(msg, 1, dbgchk, stdout);
8094 outCount = write(cp->fdTo, message, count);
8104 /* Output message to process, with "ms" milliseconds of delay
8105 between each character. This is needed when sending the logon
8106 script to ICC, which for some reason doesn't like the
8107 instantaneous send. */
8108 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8115 ChildProc *cp = (ChildProc *) pr;
8120 r = write(cp->fdTo, message++, 1);
8133 /**** Animation code by Hugh Fisher, DCS, ANU.
8135 Known problem: if a window overlapping the board is
8136 moved away while a piece is being animated underneath,
8137 the newly exposed area won't be updated properly.
8138 I can live with this.
8140 Known problem: if you look carefully at the animation
8141 of pieces in mono mode, they are being drawn as solid
8142 shapes without interior detail while moving. Fixing
8143 this would be a major complication for minimal return.
8146 /* Masks for XPM pieces. Black and white pieces can have
8147 different shapes, but in the interest of retaining my
8148 sanity pieces must have the same outline on both light
8149 and dark squares, and all pieces must use the same
8150 background square colors/images. */
8152 static int xpmDone = 0;
8155 CreateAnimMasks (pieceDepth)
8162 unsigned long plane;
8165 /* Need a bitmap just to get a GC with right depth */
8166 buf = XCreatePixmap(xDisplay, xBoardWindow,
8168 values.foreground = 1;
8169 values.background = 0;
8170 /* Don't use XtGetGC, not read only */
8171 maskGC = XCreateGC(xDisplay, buf,
8172 GCForeground | GCBackground, &values);
8173 XFreePixmap(xDisplay, buf);
8175 buf = XCreatePixmap(xDisplay, xBoardWindow,
8176 squareSize, squareSize, pieceDepth);
8177 values.foreground = XBlackPixel(xDisplay, xScreen);
8178 values.background = XWhitePixel(xDisplay, xScreen);
8179 bufGC = XCreateGC(xDisplay, buf,
8180 GCForeground | GCBackground, &values);
8182 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8183 /* Begin with empty mask */
8184 if(!xpmDone) // [HGM] pieces: keep using existing
8185 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8186 squareSize, squareSize, 1);
8187 XSetFunction(xDisplay, maskGC, GXclear);
8188 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8189 0, 0, squareSize, squareSize);
8191 /* Take a copy of the piece */
8196 XSetFunction(xDisplay, bufGC, GXcopy);
8197 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8199 0, 0, squareSize, squareSize, 0, 0);
8201 /* XOR the background (light) over the piece */
8202 XSetFunction(xDisplay, bufGC, GXxor);
8204 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8205 0, 0, squareSize, squareSize, 0, 0);
8207 XSetForeground(xDisplay, bufGC, lightSquareColor);
8208 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8211 /* We now have an inverted piece image with the background
8212 erased. Construct mask by just selecting all the non-zero
8213 pixels - no need to reconstruct the original image. */
8214 XSetFunction(xDisplay, maskGC, GXor);
8216 /* Might be quicker to download an XImage and create bitmap
8217 data from it rather than this N copies per piece, but it
8218 only takes a fraction of a second and there is a much
8219 longer delay for loading the pieces. */
8220 for (n = 0; n < pieceDepth; n ++) {
8221 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8222 0, 0, squareSize, squareSize,
8228 XFreePixmap(xDisplay, buf);
8229 XFreeGC(xDisplay, bufGC);
8230 XFreeGC(xDisplay, maskGC);
8234 InitAnimState (anim, info)
8236 XWindowAttributes * info;
8241 /* Each buffer is square size, same depth as window */
8242 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8243 squareSize, squareSize, info->depth);
8244 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8245 squareSize, squareSize, info->depth);
8247 /* Create a plain GC for blitting */
8248 mask = GCForeground | GCBackground | GCFunction |
8249 GCPlaneMask | GCGraphicsExposures;
8250 values.foreground = XBlackPixel(xDisplay, xScreen);
8251 values.background = XWhitePixel(xDisplay, xScreen);
8252 values.function = GXcopy;
8253 values.plane_mask = AllPlanes;
8254 values.graphics_exposures = False;
8255 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8257 /* Piece will be copied from an existing context at
8258 the start of each new animation/drag. */
8259 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8261 /* Outline will be a read-only copy of an existing */
8262 anim->outlineGC = None;
8268 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8269 XWindowAttributes info;
8271 if (xpmDone && gameInfo.variant == old) return;
8272 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8273 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8275 InitAnimState(&game, &info);
8276 InitAnimState(&player, &info);
8278 /* For XPM pieces, we need bitmaps to use as masks. */
8280 CreateAnimMasks(info.depth);
8286 static Boolean frameWaiting;
8288 static RETSIGTYPE FrameAlarm (sig)
8291 frameWaiting = False;
8292 /* In case System-V style signals. Needed?? */
8293 signal(SIGALRM, FrameAlarm);
8300 struct itimerval delay;
8302 XSync(xDisplay, False);
8305 frameWaiting = True;
8306 signal(SIGALRM, FrameAlarm);
8307 delay.it_interval.tv_sec =
8308 delay.it_value.tv_sec = time / 1000;
8309 delay.it_interval.tv_usec =
8310 delay.it_value.tv_usec = (time % 1000) * 1000;
8311 setitimer(ITIMER_REAL, &delay, NULL);
8312 while (frameWaiting) pause();
8313 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8314 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8315 setitimer(ITIMER_REAL, &delay, NULL);
8325 XSync(xDisplay, False);
8327 usleep(time * 1000);
8332 /* Convert board position to corner of screen rect and color */
8335 ScreenSquare(column, row, pt, color)
8336 int column; int row; XPoint * pt; int * color;
8339 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8340 pt->y = lineGap + row * (squareSize + lineGap);
8342 pt->x = lineGap + column * (squareSize + lineGap);
8343 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8345 *color = SquareColor(row, column);
8348 /* Convert window coords to square */
8351 BoardSquare(x, y, column, row)
8352 int x; int y; int * column; int * row;
8354 *column = EventToSquare(x, BOARD_WIDTH);
8355 if (flipView && *column >= 0)
8356 *column = BOARD_WIDTH - 1 - *column;
8357 *row = EventToSquare(y, BOARD_HEIGHT);
8358 if (!flipView && *row >= 0)
8359 *row = BOARD_HEIGHT - 1 - *row;
8364 #undef Max /* just in case */
8366 #define Max(a, b) ((a) > (b) ? (a) : (b))
8367 #define Min(a, b) ((a) < (b) ? (a) : (b))
8370 SetRect(rect, x, y, width, height)
8371 XRectangle * rect; int x; int y; int width; int height;
8375 rect->width = width;
8376 rect->height = height;
8379 /* Test if two frames overlap. If they do, return
8380 intersection rect within old and location of
8381 that rect within new. */
8384 Intersect(old, new, size, area, pt)
8385 XPoint * old; XPoint * new;
8386 int size; XRectangle * area; XPoint * pt;
8388 if (old->x > new->x + size || new->x > old->x + size ||
8389 old->y > new->y + size || new->y > old->y + size) {
8392 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8393 size - abs(old->x - new->x), size - abs(old->y - new->y));
8394 pt->x = Max(old->x - new->x, 0);
8395 pt->y = Max(old->y - new->y, 0);
8400 /* For two overlapping frames, return the rect(s)
8401 in the old that do not intersect with the new. */
8404 CalcUpdateRects(old, new, size, update, nUpdates)
8405 XPoint * old; XPoint * new; int size;
8406 XRectangle update[]; int * nUpdates;
8410 /* If old = new (shouldn't happen) then nothing to draw */
8411 if (old->x == new->x && old->y == new->y) {
8415 /* Work out what bits overlap. Since we know the rects
8416 are the same size we don't need a full intersect calc. */
8418 /* Top or bottom edge? */
8419 if (new->y > old->y) {
8420 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8422 } else if (old->y > new->y) {
8423 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8424 size, old->y - new->y);
8427 /* Left or right edge - don't overlap any update calculated above. */
8428 if (new->x > old->x) {
8429 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8430 new->x - old->x, size - abs(new->y - old->y));
8432 } else if (old->x > new->x) {
8433 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8434 old->x - new->x, size - abs(new->y - old->y));
8441 /* Generate a series of frame coords from start->mid->finish.
8442 The movement rate doubles until the half way point is
8443 reached, then halves back down to the final destination,
8444 which gives a nice slow in/out effect. The algorithmn
8445 may seem to generate too many intermediates for short
8446 moves, but remember that the purpose is to attract the
8447 viewers attention to the piece about to be moved and
8448 then to where it ends up. Too few frames would be less
8452 Tween(start, mid, finish, factor, frames, nFrames)
8453 XPoint * start; XPoint * mid;
8454 XPoint * finish; int factor;
8455 XPoint frames[]; int * nFrames;
8457 int fraction, n, count;
8461 /* Slow in, stepping 1/16th, then 1/8th, ... */
8463 for (n = 0; n < factor; n++)
8465 for (n = 0; n < factor; n++) {
8466 frames[count].x = start->x + (mid->x - start->x) / fraction;
8467 frames[count].y = start->y + (mid->y - start->y) / fraction;
8469 fraction = fraction / 2;
8473 frames[count] = *mid;
8476 /* Slow out, stepping 1/2, then 1/4, ... */
8478 for (n = 0; n < factor; n++) {
8479 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8480 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8482 fraction = fraction * 2;
8487 /* Draw a piece on the screen without disturbing what's there */
8490 SelectGCMask(piece, clip, outline, mask)
8491 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8495 /* Bitmap for piece being moved. */
8496 if (appData.monoMode) {
8497 *mask = *pieceToSolid(piece);
8498 } else if (useImages) {
8500 *mask = xpmMask[piece];
8502 *mask = ximMaskPm[piece];
8505 *mask = *pieceToSolid(piece);
8508 /* GC for piece being moved. Square color doesn't matter, but
8509 since it gets modified we make a copy of the original. */
8511 if (appData.monoMode)
8516 if (appData.monoMode)
8521 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8523 /* Outline only used in mono mode and is not modified */
8525 *outline = bwPieceGC;
8527 *outline = wbPieceGC;
8531 OverlayPiece(piece, clip, outline, dest)
8532 ChessSquare piece; GC clip; GC outline; Drawable dest;
8537 /* Draw solid rectangle which will be clipped to shape of piece */
8538 XFillRectangle(xDisplay, dest, clip,
8539 0, 0, squareSize, squareSize);
8540 if (appData.monoMode)
8541 /* Also draw outline in contrasting color for black
8542 on black / white on white cases */
8543 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8544 0, 0, squareSize, squareSize, 0, 0, 1);
8546 /* Copy the piece */
8551 if(appData.upsideDown && flipView) kind ^= 2;
8552 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8554 0, 0, squareSize, squareSize,
8559 /* Animate the movement of a single piece */
8562 BeginAnimation(anim, piece, startColor, start)
8570 if(appData.upsideDown && flipView) piece += piece < BlackPawn ? BlackPawn : -BlackPawn;
8571 /* The old buffer is initialised with the start square (empty) */
8572 BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0);
8573 anim->prevFrame = *start;
8575 /* The piece will be drawn using its own bitmap as a matte */
8576 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8577 XSetClipMask(xDisplay, anim->pieceGC, mask);
8581 AnimationFrame(anim, frame, piece)
8586 XRectangle updates[4];
8591 /* Save what we are about to draw into the new buffer */
8592 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8593 frame->x, frame->y, squareSize, squareSize,
8596 /* Erase bits of the previous frame */
8597 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8598 /* Where the new frame overlapped the previous,
8599 the contents in newBuf are wrong. */
8600 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8601 overlap.x, overlap.y,
8602 overlap.width, overlap.height,
8604 /* Repaint the areas in the old that don't overlap new */
8605 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8606 for (i = 0; i < count; i++)
8607 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8608 updates[i].x - anim->prevFrame.x,
8609 updates[i].y - anim->prevFrame.y,
8610 updates[i].width, updates[i].height,
8611 updates[i].x, updates[i].y);
8613 /* Easy when no overlap */
8614 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8615 0, 0, squareSize, squareSize,
8616 anim->prevFrame.x, anim->prevFrame.y);
8619 /* Save this frame for next time round */
8620 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8621 0, 0, squareSize, squareSize,
8623 anim->prevFrame = *frame;
8625 /* Draw piece over original screen contents, not current,
8626 and copy entire rect. Wipes out overlapping piece images. */
8627 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8628 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8629 0, 0, squareSize, squareSize,
8630 frame->x, frame->y);
8634 EndAnimation (anim, finish)
8638 XRectangle updates[4];
8643 /* The main code will redraw the final square, so we
8644 only need to erase the bits that don't overlap. */
8645 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8646 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8647 for (i = 0; i < count; i++)
8648 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8649 updates[i].x - anim->prevFrame.x,
8650 updates[i].y - anim->prevFrame.y,
8651 updates[i].width, updates[i].height,
8652 updates[i].x, updates[i].y);
8654 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8655 0, 0, squareSize, squareSize,
8656 anim->prevFrame.x, anim->prevFrame.y);
8661 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8663 ChessSquare piece; int startColor;
8664 XPoint * start; XPoint * finish;
8665 XPoint frames[]; int nFrames;
8669 BeginAnimation(anim, piece, startColor, start);
8670 for (n = 0; n < nFrames; n++) {
8671 AnimationFrame(anim, &(frames[n]), piece);
8672 FrameDelay(appData.animSpeed);
8674 EndAnimation(anim, finish);
8678 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
8681 ChessSquare piece = board[fromY][toY];
8682 board[fromY][toY] = EmptySquare;
8683 DrawPosition(FALSE, board);
8685 x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap);
8686 y = lineGap + toY * (squareSize + lineGap);
8688 x = lineGap + toX * (squareSize + lineGap);
8689 y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap);
8691 for(i=1; i<4*kFactor; i++) {
8692 int r = squareSize * 9 * i/(20*kFactor - 5);
8693 XFillArc(xDisplay, xBoardWindow, highlineGC,
8694 x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360);
8695 FrameDelay(appData.animSpeed);
8697 board[fromY][toY] = piece;
8700 /* Main control logic for deciding what to animate and how */
8703 AnimateMove(board, fromX, fromY, toX, toY)
8712 XPoint start, finish, mid;
8713 XPoint frames[kFactor * 2 + 1];
8714 int nFrames, startColor, endColor;
8716 /* Are we animating? */
8717 if (!appData.animate || appData.blindfold)
8720 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8721 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8722 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8724 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8725 piece = board[fromY][fromX];
8726 if (piece >= EmptySquare) return;
8731 hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1;
8734 if (appData.debugMode) {
8735 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8736 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8737 piece, fromX, fromY, toX, toY); }
8739 ScreenSquare(fromX, fromY, &start, &startColor);
8740 ScreenSquare(toX, toY, &finish, &endColor);
8743 /* Knight: make straight movement then diagonal */
8744 if (abs(toY - fromY) < abs(toX - fromX)) {
8745 mid.x = start.x + (finish.x - start.x) / 2;
8749 mid.y = start.y + (finish.y - start.y) / 2;
8752 mid.x = start.x + (finish.x - start.x) / 2;
8753 mid.y = start.y + (finish.y - start.y) / 2;
8756 /* Don't use as many frames for very short moves */
8757 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8758 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8760 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8761 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8762 if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
8764 for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
8765 if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
8768 /* Be sure end square is redrawn */
8769 damage[0][toY][toX] = True;
8773 DragPieceBegin(x, y)
8776 int boardX, boardY, color;
8779 /* Are we animating? */
8780 if (!appData.animateDragging || appData.blindfold)
8783 /* Figure out which square we start in and the
8784 mouse position relative to top left corner. */
8785 BoardSquare(x, y, &boardX, &boardY);
8786 player.startBoardX = boardX;
8787 player.startBoardY = boardY;
8788 ScreenSquare(boardX, boardY, &corner, &color);
8789 player.startSquare = corner;
8790 player.startColor = color;
8791 /* As soon as we start dragging, the piece will jump slightly to
8792 be centered over the mouse pointer. */
8793 player.mouseDelta.x = squareSize/2;
8794 player.mouseDelta.y = squareSize/2;
8795 /* Initialise animation */
8796 player.dragPiece = PieceForSquare(boardX, boardY);
8798 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8799 player.dragActive = True;
8800 BeginAnimation(&player, player.dragPiece, color, &corner);
8801 /* Mark this square as needing to be redrawn. Note that
8802 we don't remove the piece though, since logically (ie
8803 as seen by opponent) the move hasn't been made yet. */
8804 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8805 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8806 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8807 corner.x, corner.y, squareSize, squareSize,
8808 0, 0); // [HGM] zh: unstack in stead of grab
8809 if(gatingPiece != EmptySquare) {
8810 /* Kludge alert: When gating we want the introduced
8811 piece to appear on the from square. To generate an
8812 image of it, we draw it on the board, copy the image,
8813 and draw the original piece again. */
8814 ChessSquare piece = boards[currentMove][boardY][boardX];
8815 DrawSquare(boardY, boardX, gatingPiece, 0);
8816 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8817 corner.x, corner.y, squareSize, squareSize, 0, 0);
8818 DrawSquare(boardY, boardX, piece, 0);
8820 damage[0][boardY][boardX] = True;
8822 player.dragActive = False;
8832 /* Are we animating? */
8833 if (!appData.animateDragging || appData.blindfold)
8837 if (! player.dragActive)
8839 /* Move piece, maintaining same relative position
8840 of mouse within square */
8841 corner.x = x - player.mouseDelta.x;
8842 corner.y = y - player.mouseDelta.y;
8843 AnimationFrame(&player, &corner, player.dragPiece);
8845 if (appData.highlightDragging) {
8847 BoardSquare(x, y, &boardX, &boardY);
8848 SetHighlights(fromX, fromY, boardX, boardY);
8857 int boardX, boardY, color;
8860 /* Are we animating? */
8861 if (!appData.animateDragging || appData.blindfold)
8865 if (! player.dragActive)
8867 /* Last frame in sequence is square piece is
8868 placed on, which may not match mouse exactly. */
8869 BoardSquare(x, y, &boardX, &boardY);
8870 ScreenSquare(boardX, boardY, &corner, &color);
8871 EndAnimation(&player, &corner);
8873 /* Be sure end square is redrawn */
8874 damage[0][boardY][boardX] = True;
8876 /* This prevents weird things happening with fast successive
8877 clicks which on my Sun at least can cause motion events
8878 without corresponding press/release. */
8879 player.dragActive = False;
8882 /* Handle expose event while piece being dragged */
8887 if (!player.dragActive || appData.blindfold)
8890 /* What we're doing: logically, the move hasn't been made yet,
8891 so the piece is still in it's original square. But visually
8892 it's being dragged around the board. So we erase the square
8893 that the piece is on and draw it at the last known drag point. */
8894 BlankSquare(player.startSquare.x, player.startSquare.y,
8895 player.startColor, EmptySquare, xBoardWindow, 1);
8896 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8897 damage[0][player.startBoardY][player.startBoardX] = TRUE;
8900 #include <sys/ioctl.h>
8901 int get_term_width()
8903 int fd, default_width;
8906 default_width = 79; // this is FICS default anyway...
8908 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8910 if (!ioctl(fd, TIOCGSIZE, &win))
8911 default_width = win.ts_cols;
8912 #elif defined(TIOCGWINSZ)
8914 if (!ioctl(fd, TIOCGWINSZ, &win))
8915 default_width = win.ws_col;
8917 return default_width;
8923 static int old_width = 0;
8924 int new_width = get_term_width();
8926 if (old_width != new_width)
8927 ics_printf("set width %d\n", new_width);
8928 old_width = new_width;
8931 void NotifyFrontendLogin()
8936 /* [AS] Arrow highlighting support */
8938 static double A_WIDTH = 5; /* Width of arrow body */
8940 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
8941 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
8943 static double Sqr( double x )
8948 static int Round( double x )
8950 return (int) (x + 0.5);
8953 void SquareToPos(int rank, int file, int *x, int *y)
8956 *x = lineGap + ((BOARD_WIDTH-1)-file) * (squareSize + lineGap);
8957 *y = lineGap + rank * (squareSize + lineGap);
8959 *x = lineGap + file * (squareSize + lineGap);
8960 *y = lineGap + ((BOARD_HEIGHT-1)-rank) * (squareSize + lineGap);
8964 /* Draw an arrow between two points using current settings */
8965 void DrawArrowBetweenPoints( int s_x, int s_y, int d_x, int d_y )
8968 double dx, dy, j, k, x, y;
8971 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
8973 arrow[0].x = s_x + A_WIDTH + 0.5;
8976 arrow[1].x = s_x + A_WIDTH + 0.5;
8977 arrow[1].y = d_y - h;
8979 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8980 arrow[2].y = d_y - h;
8985 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
8986 arrow[5].y = d_y - h;
8988 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8989 arrow[4].y = d_y - h;
8991 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
8994 else if( d_y == s_y ) {
8995 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
8998 arrow[0].y = s_y + A_WIDTH + 0.5;
9000 arrow[1].x = d_x - w;
9001 arrow[1].y = s_y + A_WIDTH + 0.5;
9003 arrow[2].x = d_x - w;
9004 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9009 arrow[5].x = d_x - w;
9010 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
9012 arrow[4].x = d_x - w;
9013 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9016 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
9019 /* [AS] Needed a lot of paper for this! :-) */
9020 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
9021 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
9023 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
9025 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
9030 arrow[0].x = Round(x - j);
9031 arrow[0].y = Round(y + j*dx);
9033 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
9034 arrow[1].y = Round(arrow[0].y - 2*j*dx);
9037 x = (double) d_x - k;
9038 y = (double) d_y - k*dy;
9041 x = (double) d_x + k;
9042 y = (double) d_y + k*dy;
9045 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
9047 arrow[6].x = Round(x - j);
9048 arrow[6].y = Round(y + j*dx);
9050 arrow[2].x = Round(arrow[6].x + 2*j);
9051 arrow[2].y = Round(arrow[6].y - 2*j*dx);
9053 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
9054 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
9059 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
9060 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
9063 XFillPolygon(xDisplay, xBoardWindow, highlineGC, arrow, 7, Nonconvex, CoordModeOrigin);
9064 // Polygon( hdc, arrow, 7 );
9067 /* [AS] Draw an arrow between two squares */
9068 void DrawArrowBetweenSquares( int s_col, int s_row, int d_col, int d_row )
9070 int s_x, s_y, d_x, d_y, hor, vert, i;
9072 if( s_col == d_col && s_row == d_row ) {
9076 /* Get source and destination points */
9077 SquareToPos( s_row, s_col, &s_x, &s_y);
9078 SquareToPos( d_row, d_col, &d_x, &d_y);
9081 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
9083 else if( d_y < s_y ) {
9084 d_y += squareSize / 2 + squareSize / 4;
9087 d_y += squareSize / 2;
9091 d_x += squareSize / 2 - squareSize / 4;
9093 else if( d_x < s_x ) {
9094 d_x += squareSize / 2 + squareSize / 4;
9097 d_x += squareSize / 2;
9100 s_x += squareSize / 2;
9101 s_y += squareSize / 2;
9104 A_WIDTH = squareSize / 14.; //[HGM] make float
9106 DrawArrowBetweenPoints( s_x, s_y, d_x, d_y );
9108 hor = 64*s_col + 32; vert = 64*s_row + 32;
9109 for(i=0; i<= 64; i++) {
9110 damage[0][vert+6>>6][hor+6>>6] = True;
9111 damage[0][vert-6>>6][hor+6>>6] = True;
9112 damage[0][vert+6>>6][hor-6>>6] = True;
9113 damage[0][vert-6>>6][hor-6>>6] = True;
9114 hor += d_col - s_col; vert += d_row - s_row;
9118 Boolean IsDrawArrowEnabled()
9120 return appData.highlightMoveWithArrow && squareSize >= 32;
9123 void DrawArrowHighlight(int fromX, int fromY, int toX,int toY)
9125 if( IsDrawArrowEnabled() && fromX >= 0 && fromY >= 0 && toX >= 0 && toY >= 0)
9126 DrawArrowBetweenSquares(fromX, fromY, toX, toY);