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 *filter, 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, char *filter,
291 FileProc proc, char *openMode));
292 void FileNamePopDown P((void));
293 void FileNameCallback P((Widget w, XtPointer client_data,
294 XtPointer call_data));
295 void FileNameAction P((Widget w, XEvent *event,
296 String *prms, Cardinal *nprms));
297 void AskQuestionReplyAction P((Widget w, XEvent *event,
298 String *prms, Cardinal *nprms));
299 void AskQuestionProc P((Widget w, XEvent *event,
300 String *prms, Cardinal *nprms));
301 void AskQuestionPopDown P((void));
302 void PromotionPopDown P((void));
303 void PromotionCallback P((Widget w, XtPointer client_data,
304 XtPointer call_data));
305 void EditCommentPopDown P((void));
306 void EditCommentCallback P((Widget w, XtPointer client_data,
307 XtPointer call_data));
308 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
309 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
310 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
311 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
313 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
315 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
317 void LoadPositionProc P((Widget w, XEvent *event,
318 String *prms, Cardinal *nprms));
319 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
321 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
323 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
325 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
327 void PastePositionProc P((Widget w, XEvent *event, String *prms,
329 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
330 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
331 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
332 void SavePositionProc P((Widget w, XEvent *event,
333 String *prms, Cardinal *nprms));
334 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
335 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
337 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
338 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
339 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
341 void MachineWhiteProc P((Widget w, XEvent *event,
342 String *prms, Cardinal *nprms));
343 void AnalyzeModeProc P((Widget w, XEvent *event,
344 String *prms, Cardinal *nprms));
345 void AnalyzeFileProc P((Widget w, XEvent *event,
346 String *prms, Cardinal *nprms));
347 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
349 void MatchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
350 void MatchOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
351 void IcsClientProc P((Widget w, XEvent *event, String *prms,
353 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
354 void EditPositionProc P((Widget w, XEvent *event,
355 String *prms, Cardinal *nprms));
356 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
357 void EditCommentProc P((Widget w, XEvent *event,
358 String *prms, Cardinal *nprms));
359 void IcsInputBoxProc P((Widget w, XEvent *event,
360 String *prms, Cardinal *nprms));
361 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
365 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
370 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
371 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
372 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
373 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
374 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
375 void StopObservingProc P((Widget w, XEvent *event, String *prms,
377 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
379 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
380 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
384 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
385 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
386 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
388 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
390 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
391 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
393 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
395 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
397 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
398 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
399 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
400 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
402 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
403 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
405 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
407 void HighlightArrowProc P((Widget w, XEvent *event, String *prms,
409 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
410 //void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
411 void OneClickProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
412 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
414 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
416 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
418 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
420 //void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
421 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
423 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
425 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
427 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
429 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
430 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
431 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
432 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
433 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
434 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
435 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
436 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void DisplayMove P((int moveNumber));
441 void DisplayTitle P((char *title));
442 void ICSInitScript P((void));
443 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
444 void ErrorPopUp P((char *title, char *text, int modal));
445 void ErrorPopDown P((void));
446 static char *ExpandPathName P((char *path));
447 static void CreateAnimVars P((void));
448 static void DragPieceMove P((int x, int y));
449 static void DrawDragPiece P((void));
450 char *ModeToWidgetName P((GameMode mode));
451 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
452 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
453 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
454 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
455 void OptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
456 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
457 void IcsTextProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
458 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
459 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
460 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
461 void IcsOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
462 void SoundOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
463 void BoardOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
464 void LoadOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
465 void SaveOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
466 void GameListOptionsPopDown P(());
467 void ShufflePopDown P(());
468 void TimeControlPopDown P(());
469 void GenericPopDown P(());
470 void update_ics_width P(());
471 int get_term_width P(());
472 int CopyMemoProc P(());
473 void DrawArrowHighlight P((int fromX, int fromY, int toX,int toY));
474 Boolean IsDrawArrowEnabled P(());
477 * XBoard depends on Xt R4 or higher
479 int xtVersion = XtSpecificationRelease;
484 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
485 jailSquareColor, highlightSquareColor, premoveHighlightColor;
486 Pixel lowTimeWarningColor;
487 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
488 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
489 wjPieceGC, bjPieceGC, prelineGC, countGC;
490 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
491 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
492 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
493 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
494 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
495 ICSInputShell, fileNameShell, askQuestionShell;
496 Widget historyShell, evalGraphShell, gameListShell;
497 int hOffset; // [HGM] dual
498 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
499 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
500 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
501 Font clockFontID, coordFontID, countFontID;
502 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
503 XtAppContext appContext;
505 char *oldICSInteractionTitle;
509 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
511 Position commentX = -1, commentY = -1;
512 Dimension commentW, commentH;
513 typedef unsigned int BoardSize;
515 Boolean chessProgram;
517 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
518 int squareSize, smallLayout = 0, tinyLayout = 0,
519 marginW, marginH, // [HGM] for run-time resizing
520 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
521 ICSInputBoxUp = False, askQuestionUp = False,
522 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
523 editUp = False, errorUp = False, errorExitStatus = -1, lineGap, defaultLineGap;
524 Pixel timerForegroundPixel, timerBackgroundPixel;
525 Pixel buttonForegroundPixel, buttonBackgroundPixel;
526 char *chessDir, *programName, *programVersion,
527 *gameCopyFilename, *gamePasteFilename;
528 Boolean alwaysOnTop = False;
529 Boolean saveSettingsOnExit;
530 char *settingsFileName;
531 char *icsTextMenuString;
533 char *firstChessProgramNames;
534 char *secondChessProgramNames;
536 WindowPlacement wpMain;
537 WindowPlacement wpConsole;
538 WindowPlacement wpComment;
539 WindowPlacement wpMoveHistory;
540 WindowPlacement wpEvalGraph;
541 WindowPlacement wpEngineOutput;
542 WindowPlacement wpGameList;
543 WindowPlacement wpTags;
547 Pixmap pieceBitmap[2][(int)BlackPawn];
548 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
549 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
550 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
551 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
552 Pixmap xpmBoardBitmap[2];
553 int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
554 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
555 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
556 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
557 XImage *ximLightSquare, *ximDarkSquare;
560 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
561 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
563 #define White(piece) ((int)(piece) < (int)BlackPawn)
565 /* Variables for doing smooth animation. This whole thing
566 would be much easier if the board was double-buffered,
567 but that would require a fairly major rewrite. */
572 GC blitGC, pieceGC, outlineGC;
573 XPoint startSquare, prevFrame, mouseDelta;
577 int startBoardX, startBoardY;
580 /* There can be two pieces being animated at once: a player
581 can begin dragging a piece before the remote opponent has moved. */
583 static AnimState game, player;
585 /* Bitmaps for use as masks when drawing XPM pieces.
586 Need one for each black and white piece. */
587 static Pixmap xpmMask[BlackKing + 1];
589 /* This magic number is the number of intermediate frames used
590 in each half of the animation. For short moves it's reduced
591 by 1. The total number of frames will be factor * 2 + 1. */
594 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
596 MenuItem fileMenu[] = {
597 {N_("New Game Ctrl+N"), "New Game", ResetProc},
598 {N_("New Shuffle Game ..."), "New Shuffle Game", ShuffleMenuProc},
599 {N_("New Variant ... Alt+Shift+V"), "New Variant", NewVariantProc}, // [HGM] variant: not functional yet
600 {"----", NULL, NothingProc},
601 {N_("Load Game Ctrl+O"), "Load Game", LoadGameProc},
602 {N_("Load Position Ctrl+Shift+O"), "Load Position", LoadPositionProc},
603 // {N_("Load Next Game"), "Load Next Game", LoadNextGameProc},
604 // {N_("Load Previous Game"), "Load Previous Game", LoadPrevGameProc},
605 // {N_("Reload Same Game"), "Reload Same Game", ReloadGameProc},
606 {N_("Next Position Shift+PgDn"), "Load Next Position", LoadNextPositionProc},
607 {N_("Prev Position Shift+PgUp"), "Load Previous Position", LoadPrevPositionProc},
608 {"----", NULL, NothingProc},
609 // {N_("Reload Same Position"), "Reload Same Position", ReloadPositionProc},
610 {N_("Save Game Ctrl+S"), "Save Game", SaveGameProc},
611 {N_("Save Position Ctrl+Shift+S"), "Save Position", SavePositionProc},
612 {"----", NULL, NothingProc},
613 {N_("Mail Move"), "Mail Move", MailMoveProc},
614 {N_("Reload CMail Message"), "Reload CMail Message", ReloadCmailMsgProc},
615 {"----", NULL, NothingProc},
616 {N_("Quit Ctr+Q"), "Exit", QuitProc},
620 MenuItem editMenu[] = {
621 {N_("Copy Game Ctrl+C"), "Copy Game", CopyGameProc},
622 {N_("Copy Position Ctrl+Shift+C"), "Copy Position", CopyPositionProc},
623 {"----", NULL, NothingProc},
624 {N_("Paste Game Ctrl+V"), "Paste Game", PasteGameProc},
625 {N_("Paste Position Ctrl+Shift+V"), "Paste Position", PastePositionProc},
626 {"----", NULL, NothingProc},
627 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
628 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
629 {N_("Edit Tags"), "Edit Tags", EditTagsProc},
630 {N_("Edit Comment"), "Edit Comment", EditCommentProc},
631 {"----", NULL, NothingProc},
632 {N_("Revert Home"), "Revert", RevertProc},
633 {N_("Annotate"), "Annotate", AnnotateProc},
634 {N_("Truncate Game End"), "Truncate Game", TruncateGameProc},
635 {"----", NULL, NothingProc},
636 {N_("Backward Alt+Left"), "Backward", BackwardProc},
637 {N_("Forward Alt+Right"), "Forward", ForwardProc},
638 {N_("Back to Start Alt+Home"), "Back to Start", ToStartProc},
639 {N_("Forward to End Alt+End"), "Forward to End", ToEndProc},
643 MenuItem viewMenu[] = {
644 {N_("Flip View F2"), "Flip View", FlipViewProc},
645 {"----", NULL, NothingProc},
646 {N_("Engine Output Alt+Shift+O"), "Show Engine Output", EngineOutputProc},
647 {N_("Move History Alt+Shift+H"), "Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
648 {N_("Evaluation Graph Alt+Shift+E"), "Show Evaluation Graph", EvalGraphProc},
649 {N_("Game List Alt+Shift+G"), "Show Game List", ShowGameListProc},
650 {N_("ICS text menu"), "ICStex", IcsTextProc},
651 {"----", NULL, NothingProc},
652 {N_("Tags"), "Show Tags", EditTagsProc},
653 {N_("Comments"), "Show Comments", EditCommentProc},
654 {N_("ICS Input Box"), "ICS Input Box", IcsInputBoxProc},
655 {"----", NULL, NothingProc},
656 {N_("Board..."), "Board Options", BoardOptionsProc},
657 {N_("Game List Tags..."), "Game List", GameListOptionsPopUp},
661 MenuItem modeMenu[] = {
662 {N_("Machine White Ctrl+W"), "Machine White", MachineWhiteProc},
663 {N_("Machine Black Ctrl+B"), "Machine Black", MachineBlackProc},
664 {N_("Two Machines Ctrl+T"), "Two Machines", TwoMachinesProc},
665 {N_("Analysis Mode Ctrl+A"), "Analysis Mode", AnalyzeModeProc},
666 {N_("Analyze File Ctrl+F"), "Analyze File", AnalyzeFileProc },
667 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
668 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
669 {N_("Training"), "Training", TrainingProc},
670 {N_("ICS Client"), "ICS Client", IcsClientProc},
671 {"----", NULL, NothingProc},
672 {N_("Machine Match"), "Machine Match", MatchProc},
673 {N_("Pause Pause"), "Pause", PauseProc},
677 MenuItem actionMenu[] = {
678 {N_("Accept F3"), "Accept", AcceptProc},
679 {N_("Decline F4"), "Decline", DeclineProc},
680 {N_("Rematch F12"), "Rematch", RematchProc},
681 {"----", NULL, NothingProc},
682 {N_("Call Flag F5"), "Call Flag", CallFlagProc},
683 {N_("Draw F6"), "Draw", DrawProc},
684 {N_("Adjourn F7"), "Adjourn", AdjournProc},
685 {N_("Abort F8"),"Abort", AbortProc},
686 {N_("Resign F9"), "Resign", ResignProc},
687 {"----", NULL, NothingProc},
688 {N_("Stop Observing F10"), "Stop Observing", StopObservingProc},
689 {N_("Stop Examining F11"), "Stop Examining", StopExaminingProc},
690 {N_("Upload to Examine"), "Upload to Examine", UploadProc},
691 {"----", NULL, NothingProc},
692 {N_("Adjudicate to White"), "Adjudicate to White", AdjuWhiteProc},
693 {N_("Adjudicate to Black"), "Adjudicate to Black", AdjuBlackProc},
694 {N_("Adjudicate Draw"), "Adjudicate Draw", AdjuDrawProc},
698 MenuItem engineMenu[] = {
699 {N_("Engine #1 Settings ..."), "Engine #1 Settings", FirstSettingsProc},
700 {N_("Engine #2 Settings ..."), "Engine #2 Settings", SecondSettingsProc},
701 {"----", NULL, NothingProc},
702 {N_("Hint"), "Hint", HintProc},
703 {N_("Book"), "Book", BookProc},
704 {"----", NULL, NothingProc},
705 {N_("Move Now Ctrl+M"), "Move Now", MoveNowProc},
706 {N_("Retract Move Ctrl+X"), "Retract Move", RetractMoveProc},
710 MenuItem optionsMenu[] = {
711 #define OPTIONSDIALOG
713 {N_("General ..."), "General", OptionsProc},
715 {N_("Time Control ... Alt+Shift+T"), "Time Control", TimeControlProc},
716 {N_("Common Engine ... Alt+Shift+U"), "Common Engine", UciMenuProc},
717 {N_("Adjudications ... Alt+Shift+J"), "Adjudications", EngineMenuProc},
718 {N_("ICS ..."), "ICS", IcsOptionsProc},
719 {N_("Match ..."), "Match", MatchOptionsProc},
720 {N_("Load Game ..."), "Load Game", LoadOptionsProc},
721 {N_("Save Game ..."), "Save Game", SaveOptionsProc},
722 // {N_(" ..."), "", OptionsProc},
723 {N_("Game List ..."), "Game List", GameListOptionsPopUp},
724 {N_("Sounds ..."), "Sounds", SoundOptionsProc},
725 {"----", NULL, NothingProc},
726 #ifndef OPTIONSDIALOG
727 {N_("Always Queen Ctrl+Shift+Q"), "Always Queen", AlwaysQueenProc},
728 {N_("Animate Dragging"), "Animate Dragging", AnimateDraggingProc},
729 {N_("Animate Moving Ctrl+Shift+A"), "Animate Moving", AnimateMovingProc},
730 {N_("Auto Flag Ctrl+Shift+F"), "Auto Flag", AutoflagProc},
731 {N_("Auto Flip View"), "Auto Flip View", AutoflipProc},
732 {N_("Blindfold"), "Blindfold", BlindfoldProc},
733 {N_("Flash Moves"), "Flash Moves", FlashMovesProc},
735 {N_("Highlight Dragging"), "Highlight Dragging", HighlightDraggingProc},
737 {N_("Highlight Last Move"), "Highlight Last Move", HighlightLastMoveProc},
738 {N_("Highlight With Arrow"), "Arrow", HighlightArrowProc},
739 {N_("Move Sound"), "Move Sound", MoveSoundProc},
740 // {N_("ICS Alarm"), "ICS Alarm", IcsAlarmProc},
741 {N_("One-Click Moving"), "OneClick", OneClickProc},
742 {N_("Periodic Updates"), "Periodic Updates", PeriodicUpdatesProc},
743 {N_("Ponder Next Move Ctrl+Shift+P"), "Ponder Next Move", PonderNextMoveProc},
744 {N_("Popup Exit Message"), "Popup Exit Message", PopupExitMessageProc},
745 {N_("Popup Move Errors"), "Popup Move Errors", PopupMoveErrorsProc},
746 // {N_("Premove"), "Premove", PremoveProc},
747 {N_("Show Coords"), "Show Coords", ShowCoordsProc},
748 {N_("Hide Thinking Ctrl+Shift+H"), "Hide Thinking", HideThinkingProc},
749 {N_("Test Legality Ctrl+Shift+L"), "Test Legality", TestLegalityProc},
750 {"----", NULL, NothingProc},
752 {N_("Save Settings Now"), "Save Settings Now", SaveSettingsProc},
753 {N_("Save Settings on Exit"), "Save Settings on Exit", SaveOnExitProc},
757 MenuItem helpMenu[] = {
758 {N_("Info XBoard"), "Info XBoard", InfoProc},
759 {N_("Man XBoard F1"), "Man XBoard", ManProc},
760 {"----", NULL, NothingProc},
761 {N_("About XBoard"), "About XBoard", AboutProc},
766 {N_("File"), "File", fileMenu},
767 {N_("Edit"), "Edit", editMenu},
768 {N_("View"), "View", viewMenu},
769 {N_("Mode"), "Mode", modeMenu},
770 {N_("Action"), "Action", actionMenu},
771 {N_("Engine"), "Engine", engineMenu},
772 {N_("Options"), "Options", optionsMenu},
773 {N_("Help"), "Help", helpMenu},
777 #define PAUSE_BUTTON "P"
778 MenuItem buttonBar[] = {
779 {"<<", "<<", ToStartProc},
780 {"<", "<", BackwardProc},
781 {PAUSE_BUTTON, PAUSE_BUTTON, PauseProc},
782 {">", ">", ForwardProc},
783 {">>", ">>", ToEndProc},
787 #define PIECE_MENU_SIZE 18
788 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
789 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
790 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
791 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
792 N_("Empty square"), N_("Clear board") },
793 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
794 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
795 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
796 N_("Empty square"), N_("Clear board") }
798 /* must be in same order as PieceMenuStrings! */
799 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
800 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
801 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
802 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
803 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
804 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
805 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
806 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
807 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
810 #define DROP_MENU_SIZE 6
811 String dropMenuStrings[DROP_MENU_SIZE] = {
812 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
814 /* must be in same order as PieceMenuStrings! */
815 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
816 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
817 WhiteRook, WhiteQueen
825 DropMenuEnables dmEnables[] = {
843 { XtNborderWidth, 0 },
844 { XtNdefaultDistance, 0 },
848 { XtNborderWidth, 0 },
849 { XtNresizable, (XtArgVal) True },
853 { XtNborderWidth, 0 },
859 { XtNjustify, (XtArgVal) XtJustifyRight },
860 { XtNlabel, (XtArgVal) "..." },
861 { XtNresizable, (XtArgVal) True },
862 { XtNresize, (XtArgVal) False }
865 Arg messageArgs[] = {
866 { XtNjustify, (XtArgVal) XtJustifyLeft },
867 { XtNlabel, (XtArgVal) "..." },
868 { XtNresizable, (XtArgVal) True },
869 { XtNresize, (XtArgVal) False }
873 { XtNborderWidth, 0 },
874 { XtNjustify, (XtArgVal) XtJustifyLeft }
877 XtResource clientResources[] = {
878 { "flashCount", "flashCount", XtRInt, sizeof(int),
879 XtOffset(AppDataPtr, flashCount), XtRImmediate,
880 (XtPointer) FLASH_COUNT },
883 XrmOptionDescRec shellOptions[] = {
884 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
885 { "-flash", "flashCount", XrmoptionNoArg, "3" },
886 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
889 XtActionsRec boardActions[] = {
890 { "DrawPosition", DrawPositionProc },
891 { "HandleUserMove", HandleUserMove },
892 { "AnimateUserMove", AnimateUserMove },
893 { "HandlePV", HandlePV },
894 { "SelectPV", SelectPV },
895 { "StopPV", StopPV },
896 { "FileNameAction", FileNameAction },
897 { "AskQuestionProc", AskQuestionProc },
898 { "AskQuestionReplyAction", AskQuestionReplyAction },
899 { "PieceMenuPopup", PieceMenuPopup },
900 { "WhiteClock", WhiteClock },
901 { "BlackClock", BlackClock },
902 { "Iconify", Iconify },
903 { "ResetProc", ResetProc },
904 { "NewVariantProc", NewVariantProc },
905 { "LoadGameProc", LoadGameProc },
906 { "LoadNextGameProc", LoadNextGameProc },
907 { "LoadPrevGameProc", LoadPrevGameProc },
908 { "LoadSelectedProc", LoadSelectedProc },
909 { "SetFilterProc", SetFilterProc },
910 { "ReloadGameProc", ReloadGameProc },
911 { "LoadPositionProc", LoadPositionProc },
912 { "LoadNextPositionProc", LoadNextPositionProc },
913 { "LoadPrevPositionProc", LoadPrevPositionProc },
914 { "ReloadPositionProc", ReloadPositionProc },
915 { "CopyPositionProc", CopyPositionProc },
916 { "PastePositionProc", PastePositionProc },
917 { "CopyGameProc", CopyGameProc },
918 { "PasteGameProc", PasteGameProc },
919 { "SaveGameProc", SaveGameProc },
920 { "SavePositionProc", SavePositionProc },
921 { "MailMoveProc", MailMoveProc },
922 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
923 { "QuitProc", QuitProc },
924 { "MachineWhiteProc", MachineWhiteProc },
925 { "MachineBlackProc", MachineBlackProc },
926 { "AnalysisModeProc", AnalyzeModeProc },
927 { "AnalyzeFileProc", AnalyzeFileProc },
928 { "TwoMachinesProc", TwoMachinesProc },
929 { "IcsClientProc", IcsClientProc },
930 { "EditGameProc", EditGameProc },
931 { "EditPositionProc", EditPositionProc },
932 { "TrainingProc", EditPositionProc },
933 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
934 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
935 { "ShowGameListProc", ShowGameListProc },
936 { "ShowMoveListProc", HistoryShowProc},
937 { "EditTagsProc", EditCommentProc },
938 { "EditCommentProc", EditCommentProc },
939 { "IcsInputBoxProc", IcsInputBoxProc },
940 { "PauseProc", PauseProc },
941 { "AcceptProc", AcceptProc },
942 { "DeclineProc", DeclineProc },
943 { "RematchProc", RematchProc },
944 { "CallFlagProc", CallFlagProc },
945 { "DrawProc", DrawProc },
946 { "AdjournProc", AdjournProc },
947 { "AbortProc", AbortProc },
948 { "ResignProc", ResignProc },
949 { "AdjuWhiteProc", AdjuWhiteProc },
950 { "AdjuBlackProc", AdjuBlackProc },
951 { "AdjuDrawProc", AdjuDrawProc },
952 { "EnterKeyProc", EnterKeyProc },
953 { "UpKeyProc", UpKeyProc },
954 { "DownKeyProc", DownKeyProc },
955 { "StopObservingProc", StopObservingProc },
956 { "StopExaminingProc", StopExaminingProc },
957 { "UploadProc", UploadProc },
958 { "BackwardProc", BackwardProc },
959 { "ForwardProc", ForwardProc },
960 { "ToStartProc", ToStartProc },
961 { "ToEndProc", ToEndProc },
962 { "RevertProc", RevertProc },
963 { "AnnotateProc", AnnotateProc },
964 { "TruncateGameProc", TruncateGameProc },
965 { "MoveNowProc", MoveNowProc },
966 { "RetractMoveProc", RetractMoveProc },
967 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
968 { "UciMenuProc", (XtActionProc) UciMenuProc },
969 { "TimeControlProc", (XtActionProc) TimeControlProc },
970 { "FlipViewProc", FlipViewProc },
971 { "PonderNextMoveProc", PonderNextMoveProc },
972 #ifndef OPTIONSDIALOG
973 { "AlwaysQueenProc", AlwaysQueenProc },
974 { "AnimateDraggingProc", AnimateDraggingProc },
975 { "AnimateMovingProc", AnimateMovingProc },
976 { "AutoflagProc", AutoflagProc },
977 { "AutoflipProc", AutoflipProc },
978 { "BlindfoldProc", BlindfoldProc },
979 { "FlashMovesProc", FlashMovesProc },
981 { "HighlightDraggingProc", HighlightDraggingProc },
983 { "HighlightLastMoveProc", HighlightLastMoveProc },
984 // { "IcsAlarmProc", IcsAlarmProc },
985 { "MoveSoundProc", MoveSoundProc },
986 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
987 { "PopupExitMessageProc", PopupExitMessageProc },
988 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
989 // { "PremoveProc", PremoveProc },
990 { "ShowCoordsProc", ShowCoordsProc },
991 { "ShowThinkingProc", ShowThinkingProc },
992 { "HideThinkingProc", HideThinkingProc },
993 { "TestLegalityProc", TestLegalityProc },
995 { "SaveSettingsProc", SaveSettingsProc },
996 { "SaveOnExitProc", SaveOnExitProc },
997 { "InfoProc", InfoProc },
998 { "ManProc", ManProc },
999 { "HintProc", HintProc },
1000 { "BookProc", BookProc },
1001 { "AboutGameProc", AboutGameProc },
1002 { "AboutProc", AboutProc },
1003 { "DebugProc", DebugProc },
1004 { "NothingProc", NothingProc },
1005 { "CommentClick", (XtActionProc) CommentClick },
1006 { "CommentPopDown", (XtActionProc) CommentPopDown },
1007 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
1008 { "TagsPopDown", (XtActionProc) TagsPopDown },
1009 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
1010 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
1011 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
1012 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
1013 { "GameListPopDown", (XtActionProc) GameListPopDown },
1014 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
1015 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1016 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
1017 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1018 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1019 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
1020 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
1021 { "GenericPopDown", (XtActionProc) GenericPopDown },
1022 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1025 char globalTranslations[] =
1026 ":<Key>F9: ResignProc() \n \
1027 :Ctrl<Key>n: ResetProc() \n \
1028 :Meta<Key>V: NewVariantProc() \n \
1029 :Ctrl<Key>o: LoadGameProc() \n \
1030 :Meta<Key>Next: LoadNextGameProc() \n \
1031 :Meta<Key>Prior: LoadPrevGameProc() \n \
1032 :Ctrl<Key>s: SaveGameProc() \n \
1033 :Ctrl<Key>c: CopyGameProc() \n \
1034 :Ctrl<Key>v: PasteGameProc() \n \
1035 :Ctrl<Key>O: LoadPositionProc() \n \
1036 :Shift<Key>Next: LoadNextPositionProc() \n \
1037 :Shift<Key>Prior: LoadPrevPositionProc() \n \
1038 :Ctrl<Key>S: SavePositionProc() \n \
1039 :Ctrl<Key>C: CopyPositionProc() \n \
1040 :Ctrl<Key>V: PastePositionProc() \n \
1041 :Ctrl<Key>q: QuitProc() \n \
1042 :Ctrl<Key>w: MachineWhiteProc() \n \
1043 :Ctrl<Key>b: MachineBlackProc() \n \
1044 :Ctrl<Key>t: TwoMachinesProc() \n \
1045 :Ctrl<Key>a: AnalysisModeProc() \n \
1046 :Ctrl<Key>f: AnalyzeFileProc() \n \
1047 :Ctrl<Key>e: EditGameProc() \n \
1048 :Ctrl<Key>E: EditPositionProc() \n \
1049 :Meta<Key>O: EngineOutputProc() \n \
1050 :Meta<Key>E: EvalGraphProc() \n \
1051 :Meta<Key>G: ShowGameListProc() \n \
1052 :Meta<Key>H: ShowMoveListProc() \n \
1053 :<Key>Pause: PauseProc() \n \
1054 :<Key>F3: AcceptProc() \n \
1055 :<Key>F4: DeclineProc() \n \
1056 :<Key>F12: RematchProc() \n \
1057 :<Key>F5: CallFlagProc() \n \
1058 :<Key>F6: DrawProc() \n \
1059 :<Key>F7: AdjournProc() \n \
1060 :<Key>F8: AbortProc() \n \
1061 :<Key>F10: StopObservingProc() \n \
1062 :<Key>F11: StopExaminingProc() \n \
1063 :Meta Ctrl<Key>F12: DebugProc() \n \
1064 :Meta<Key>End: ToEndProc() \n \
1065 :Meta<Key>Right: ForwardProc() \n \
1066 :Meta<Key>Home: ToStartProc() \n \
1067 :Meta<Key>Left: BackwardProc() \n \
1068 :<Key>Home: RevertProc() \n \
1069 :<Key>End: TruncateGameProc() \n \
1070 :Ctrl<Key>m: MoveNowProc() \n \
1071 :Ctrl<Key>x: RetractMoveProc() \n \
1072 :Meta<Key>J: EngineMenuProc() \n \
1073 :Meta<Key>U: UciMenuProc() \n \
1074 :Meta<Key>T: TimeControlProc() \n \
1075 :Ctrl<Key>P: PonderNextMoveProc() \n "
1076 #ifndef OPTIONSDIALOG
1078 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1079 :Ctrl<Key>F: AutoflagProc() \n \
1080 :Ctrl<Key>A: AnimateMovingProc() \n \
1081 :Ctrl<Key>L: TestLegalityProc() \n \
1082 :Ctrl<Key>H: HideThinkingProc() \n "
1085 :<Key>-: Iconify() \n \
1086 :<Key>F1: ManProc() \n \
1087 :<Key>F2: FlipViewProc() \n \
1088 <KeyDown>.: BackwardProc() \n \
1089 <KeyUp>.: ForwardProc() \n \
1090 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1091 \"Send to chess program:\",,1) \n \
1092 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1093 \"Send to second chess program:\",,2) \n";
1095 char boardTranslations[] =
1096 "<Btn1Down>: HandleUserMove(0) \n \
1097 Shift<Btn1Up>: HandleUserMove(1) \n \
1098 <Btn1Up>: HandleUserMove(0) \n \
1099 <Btn1Motion>: AnimateUserMove() \n \
1100 <Btn3Motion>: HandlePV() \n \
1101 <Btn3Up>: PieceMenuPopup(menuB) \n \
1102 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1103 PieceMenuPopup(menuB) \n \
1104 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1105 PieceMenuPopup(menuW) \n \
1106 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1107 PieceMenuPopup(menuW) \n \
1108 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1109 PieceMenuPopup(menuB) \n";
1111 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1112 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1114 char ICSInputTranslations[] =
1115 "<Key>Up: UpKeyProc() \n "
1116 "<Key>Down: DownKeyProc() \n "
1117 "<Key>Return: EnterKeyProc() \n";
1119 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1120 // as the widget is destroyed before the up-click can call extend-end
1121 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1123 String xboardResources[] = {
1124 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1125 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1126 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1131 /* Max possible square size */
1132 #define MAXSQSIZE 256
1134 static int xpm_avail[MAXSQSIZE];
1136 #ifdef HAVE_DIR_STRUCT
1138 /* Extract piece size from filename */
1140 xpm_getsize(name, len, ext)
1151 if ((p=strchr(name, '.')) == NULL ||
1152 StrCaseCmp(p+1, ext) != 0)
1158 while (*p && isdigit(*p))
1165 /* Setup xpm_avail */
1167 xpm_getavail(dirname, ext)
1175 for (i=0; i<MAXSQSIZE; ++i)
1178 if (appData.debugMode)
1179 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1181 dir = opendir(dirname);
1184 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1185 programName, dirname);
1189 while ((ent=readdir(dir)) != NULL) {
1190 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1191 if (i > 0 && i < MAXSQSIZE)
1201 xpm_print_avail(fp, ext)
1207 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1208 for (i=1; i<MAXSQSIZE; ++i) {
1214 /* Return XPM piecesize closest to size */
1216 xpm_closest_to(dirname, size, ext)
1222 int sm_diff = MAXSQSIZE;
1226 xpm_getavail(dirname, ext);
1228 if (appData.debugMode)
1229 xpm_print_avail(stderr, ext);
1231 for (i=1; i<MAXSQSIZE; ++i) {
1234 diff = (diff<0) ? -diff : diff;
1235 if (diff < sm_diff) {
1243 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1249 #else /* !HAVE_DIR_STRUCT */
1250 /* If we are on a system without a DIR struct, we can't
1251 read the directory, so we can't collect a list of
1252 filenames, etc., so we can't do any size-fitting. */
1254 xpm_closest_to(dirname, size, ext)
1259 fprintf(stderr, _("\
1260 Warning: No DIR structure found on this system --\n\
1261 Unable to autosize for XPM/XIM pieces.\n\
1262 Please report this error to frankm@hiwaay.net.\n\
1263 Include system type & operating system in message.\n"));
1266 #endif /* HAVE_DIR_STRUCT */
1268 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1269 "magenta", "cyan", "white" };
1273 TextColors textColors[(int)NColorClasses];
1275 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1277 parse_color(str, which)
1281 char *p, buf[100], *d;
1284 if (strlen(str) > 99) /* watch bounds on buf */
1289 for (i=0; i<which; ++i) {
1296 /* Could be looking at something like:
1298 .. in which case we want to stop on a comma also */
1299 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1303 return -1; /* Use default for empty field */
1306 if (which == 2 || isdigit(*p))
1309 while (*p && isalpha(*p))
1314 for (i=0; i<8; ++i) {
1315 if (!StrCaseCmp(buf, cnames[i]))
1316 return which? (i+40) : (i+30);
1318 if (!StrCaseCmp(buf, "default")) return -1;
1320 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1325 parse_cpair(cc, str)
1329 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1330 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1335 /* bg and attr are optional */
1336 textColors[(int)cc].bg = parse_color(str, 1);
1337 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1338 textColors[(int)cc].attr = 0;
1344 /* Arrange to catch delete-window events */
1345 Atom wm_delete_window;
1347 CatchDeleteWindow(Widget w, String procname)
1350 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1351 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1352 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1359 XtSetArg(args[0], XtNiconic, False);
1360 XtSetValues(shellWidget, args, 1);
1362 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1365 //---------------------------------------------------------------------------------------------------------
1366 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1369 #define CW_USEDEFAULT (1<<31)
1370 #define ICS_TEXT_MENU_SIZE 90
1371 #define DEBUG_FILE "xboard.debug"
1372 #define SetCurrentDirectory chdir
1373 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1377 // these two must some day move to frontend.h, when they are implemented
1378 Boolean GameListIsUp();
1380 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1383 // front-end part of option handling
1385 // [HGM] This platform-dependent table provides the location for storing the color info
1386 extern char *crWhite, * crBlack;
1390 &appData.whitePieceColor,
1391 &appData.blackPieceColor,
1392 &appData.lightSquareColor,
1393 &appData.darkSquareColor,
1394 &appData.highlightSquareColor,
1395 &appData.premoveHighlightColor,
1396 &appData.lowTimeWarningColor,
1407 // [HGM] font: keep a font for each square size, even non-stndard ones
1408 #define NUM_SIZES 18
1409 #define MAX_SIZE 130
1410 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1411 char *fontTable[NUM_FONTS][MAX_SIZE];
1414 ParseFont(char *name, int number)
1415 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1417 if(sscanf(name, "size%d:", &size)) {
1418 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1419 // defer processing it until we know if it matches our board size
1420 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1421 fontTable[number][size] = strdup(strchr(name, ':')+1);
1422 fontValid[number][size] = True;
1427 case 0: // CLOCK_FONT
1428 appData.clockFont = strdup(name);
1430 case 1: // MESSAGE_FONT
1431 appData.font = strdup(name);
1433 case 2: // COORD_FONT
1434 appData.coordFont = strdup(name);
1439 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1444 { // only 2 fonts currently
1445 appData.clockFont = CLOCK_FONT_NAME;
1446 appData.coordFont = COORD_FONT_NAME;
1447 appData.font = DEFAULT_FONT_NAME;
1452 { // no-op, until we identify the code for this already in XBoard and move it here
1456 ParseColor(int n, char *name)
1457 { // in XBoard, just copy the color-name string
1458 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1462 ParseTextAttribs(ColorClass cc, char *s)
1464 (&appData.colorShout)[cc] = strdup(s);
1468 ParseBoardSize(void *addr, char *name)
1470 appData.boardSize = strdup(name);
1475 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1479 SetCommPortDefaults()
1480 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1483 // [HGM] args: these three cases taken out to stay in front-end
1485 SaveFontArg(FILE *f, ArgDescriptor *ad)
1488 int i, n = (int)(intptr_t)ad->argLoc;
1490 case 0: // CLOCK_FONT
1491 name = appData.clockFont;
1493 case 1: // MESSAGE_FONT
1494 name = appData.font;
1496 case 2: // COORD_FONT
1497 name = appData.coordFont;
1502 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1503 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1504 fontTable[n][squareSize] = strdup(name);
1505 fontValid[n][squareSize] = True;
1508 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1509 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1514 { // nothing to do, as the sounds are at all times represented by their text-string names already
1518 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1519 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1520 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
1524 SaveColor(FILE *f, ArgDescriptor *ad)
1525 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1526 if(colorVariable[(int)(intptr_t)ad->argLoc])
1527 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
1531 SaveBoardSize(FILE *f, char *name, void *addr)
1532 { // wrapper to shield back-end from BoardSize & sizeInfo
1533 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1537 ParseCommPortSettings(char *s)
1538 { // no such option in XBoard (yet)
1541 extern Widget engineOutputShell;
1542 extern Widget tagsShell, editTagsShell;
1544 GetActualPlacement(Widget wg, WindowPlacement *wp)
1554 XtSetArg(args[i], XtNx, &x); i++;
1555 XtSetArg(args[i], XtNy, &y); i++;
1556 XtSetArg(args[i], XtNwidth, &w); i++;
1557 XtSetArg(args[i], XtNheight, &h); i++;
1558 XtGetValues(wg, args, i);
1567 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1568 // In XBoard this will have to wait until awareness of window parameters is implemented
1569 GetActualPlacement(shellWidget, &wpMain);
1570 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1571 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1572 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1573 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1574 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1575 else GetActualPlacement(editShell, &wpComment);
1576 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1577 else GetActualPlacement(editTagsShell, &wpTags);
1581 PrintCommPortSettings(FILE *f, char *name)
1582 { // This option does not exist in XBoard
1586 MySearchPath(char *installDir, char *name, char *fullname)
1587 { // just append installDir and name. Perhaps ExpandPath should be used here?
1588 name = ExpandPathName(name);
1589 if(name && name[0] == '/')
1590 safeStrCpy(fullname, name, MSG_SIZ );
1592 sprintf(fullname, "%s%c%s", installDir, '/', name);
1598 MyGetFullPathName(char *name, char *fullname)
1599 { // should use ExpandPath?
1600 name = ExpandPathName(name);
1601 safeStrCpy(fullname, name, MSG_SIZ );
1606 EnsureOnScreen(int *x, int *y, int minX, int minY)
1613 { // [HGM] args: allows testing if main window is realized from back-end
1614 return xBoardWindow != 0;
1618 PopUpStartupDialog()
1619 { // start menu not implemented in XBoard
1623 ConvertToLine(int argc, char **argv)
1625 static char line[128*1024], buf[1024];
1629 for(i=1; i<argc; i++)
1631 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1632 && argv[i][0] != '{' )
1633 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1635 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1636 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1639 line[strlen(line)-1] = NULLCHAR;
1643 //--------------------------------------------------------------------------------------------
1645 extern Boolean twoBoards, partnerUp;
1648 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1650 #define BoardSize int
1651 void InitDrawingSizes(BoardSize boardSize, int flags)
1652 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1653 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1655 XtGeometryResult gres;
1658 if(!formWidget) return;
1661 * Enable shell resizing.
1663 shellArgs[0].value = (XtArgVal) &w;
1664 shellArgs[1].value = (XtArgVal) &h;
1665 XtGetValues(shellWidget, shellArgs, 2);
1667 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1668 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1669 XtSetValues(shellWidget, &shellArgs[2], 4);
1671 XtSetArg(args[0], XtNdefaultDistance, &sep);
1672 XtGetValues(formWidget, args, 1);
1674 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1675 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1676 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1678 hOffset = boardWidth + 10;
1679 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1680 secondSegments[i] = gridSegments[i];
1681 secondSegments[i].x1 += hOffset;
1682 secondSegments[i].x2 += hOffset;
1685 XtSetArg(args[0], XtNwidth, boardWidth);
1686 XtSetArg(args[1], XtNheight, boardHeight);
1687 XtSetValues(boardWidget, args, 2);
1689 timerWidth = (boardWidth - sep) / 2;
1690 XtSetArg(args[0], XtNwidth, timerWidth);
1691 XtSetValues(whiteTimerWidget, args, 1);
1692 XtSetValues(blackTimerWidget, args, 1);
1694 XawFormDoLayout(formWidget, False);
1696 if (appData.titleInWindow) {
1698 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1699 XtSetArg(args[i], XtNheight, &h); i++;
1700 XtGetValues(titleWidget, args, i);
1702 w = boardWidth - 2*bor;
1704 XtSetArg(args[0], XtNwidth, &w);
1705 XtGetValues(menuBarWidget, args, 1);
1706 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1709 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1710 if (gres != XtGeometryYes && appData.debugMode) {
1712 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1713 programName, gres, w, h, wr, hr);
1717 XawFormDoLayout(formWidget, True);
1720 * Inhibit shell resizing.
1722 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1723 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1724 shellArgs[4].value = shellArgs[2].value = w;
1725 shellArgs[5].value = shellArgs[3].value = h;
1726 XtSetValues(shellWidget, &shellArgs[0], 6);
1728 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1731 for(i=0; i<4; i++) {
1733 for(p=0; p<=(int)WhiteKing; p++)
1734 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1735 if(gameInfo.variant == VariantShogi) {
1736 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1737 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1738 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1739 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1740 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1743 if(gameInfo.variant == VariantGothic) {
1744 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1747 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1748 xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
1749 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1752 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1753 for(p=0; p<=(int)WhiteKing; p++)
1754 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1755 if(gameInfo.variant == VariantShogi) {
1756 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1757 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1758 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1759 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1760 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1763 if(gameInfo.variant == VariantGothic) {
1764 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1767 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1768 ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
1769 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1774 for(i=0; i<2; i++) {
1776 for(p=0; p<=(int)WhiteKing; p++)
1777 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1778 if(gameInfo.variant == VariantShogi) {
1779 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1780 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1781 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1782 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1783 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1786 if(gameInfo.variant == VariantGothic) {
1787 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1790 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1791 pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
1792 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1802 void ParseIcsTextColors()
1803 { // [HGM] tken out of main(), so it can be called from ICS-Options dialog
1804 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1805 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1806 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1807 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1808 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1809 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1810 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1811 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1812 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1813 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1815 if (appData.colorize) {
1817 _("%s: can't parse color names; disabling colorization\n"),
1820 appData.colorize = FALSE;
1825 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
1826 XrmValue vFrom, vTo;
1827 int forceMono = False;
1829 if (!appData.monoMode) {
1830 vFrom.addr = (caddr_t) appData.lightSquareColor;
1831 vFrom.size = strlen(appData.lightSquareColor);
1832 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1833 if (vTo.addr == NULL) {
1834 appData.monoMode = True;
1837 lightSquareColor = *(Pixel *) vTo.addr;
1840 if (!appData.monoMode) {
1841 vFrom.addr = (caddr_t) appData.darkSquareColor;
1842 vFrom.size = strlen(appData.darkSquareColor);
1843 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1844 if (vTo.addr == NULL) {
1845 appData.monoMode = True;
1848 darkSquareColor = *(Pixel *) vTo.addr;
1851 if (!appData.monoMode) {
1852 vFrom.addr = (caddr_t) appData.whitePieceColor;
1853 vFrom.size = strlen(appData.whitePieceColor);
1854 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1855 if (vTo.addr == NULL) {
1856 appData.monoMode = True;
1859 whitePieceColor = *(Pixel *) vTo.addr;
1862 if (!appData.monoMode) {
1863 vFrom.addr = (caddr_t) appData.blackPieceColor;
1864 vFrom.size = strlen(appData.blackPieceColor);
1865 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1866 if (vTo.addr == NULL) {
1867 appData.monoMode = True;
1870 blackPieceColor = *(Pixel *) vTo.addr;
1874 if (!appData.monoMode) {
1875 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1876 vFrom.size = strlen(appData.highlightSquareColor);
1877 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1878 if (vTo.addr == NULL) {
1879 appData.monoMode = True;
1882 highlightSquareColor = *(Pixel *) vTo.addr;
1886 if (!appData.monoMode) {
1887 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1888 vFrom.size = strlen(appData.premoveHighlightColor);
1889 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1890 if (vTo.addr == NULL) {
1891 appData.monoMode = True;
1894 premoveHighlightColor = *(Pixel *) vTo.addr;
1905 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1906 XSetWindowAttributes window_attributes;
1908 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1909 XrmValue vFrom, vTo;
1910 XtGeometryResult gres;
1913 int forceMono = False;
1915 srandom(time(0)); // [HGM] book: make random truly random
1917 setbuf(stdout, NULL);
1918 setbuf(stderr, NULL);
1921 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1922 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1926 programName = strrchr(argv[0], '/');
1927 if (programName == NULL)
1928 programName = argv[0];
1933 XtSetLanguageProc(NULL, NULL, NULL);
1934 bindtextdomain(PACKAGE, LOCALEDIR);
1935 textdomain(PACKAGE);
1939 XtAppInitialize(&appContext, "XBoard", shellOptions,
1940 XtNumber(shellOptions),
1941 &argc, argv, xboardResources, NULL, 0);
1942 appData.boardSize = "";
1943 InitAppData(ConvertToLine(argc, argv));
1945 if (p == NULL) p = "/tmp";
1946 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1947 gameCopyFilename = (char*) malloc(i);
1948 gamePasteFilename = (char*) malloc(i);
1949 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1950 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1952 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1953 clientResources, XtNumber(clientResources),
1956 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1957 static char buf[MSG_SIZ];
1958 EscapeExpand(buf, appData.initString);
1959 appData.initString = strdup(buf);
1960 EscapeExpand(buf, appData.secondInitString);
1961 appData.secondInitString = strdup(buf);
1962 EscapeExpand(buf, appData.firstComputerString);
1963 appData.firstComputerString = strdup(buf);
1964 EscapeExpand(buf, appData.secondComputerString);
1965 appData.secondComputerString = strdup(buf);
1968 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1971 if (chdir(chessDir) != 0) {
1972 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1978 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1979 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1980 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1981 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1984 setbuf(debugFP, NULL);
1987 /* [HGM,HR] make sure board size is acceptable */
1988 if(appData.NrFiles > BOARD_FILES ||
1989 appData.NrRanks > BOARD_RANKS )
1990 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1993 /* This feature does not work; animation needs a rewrite */
1994 appData.highlightDragging = FALSE;
1998 xDisplay = XtDisplay(shellWidget);
1999 xScreen = DefaultScreen(xDisplay);
2000 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
2002 gameInfo.variant = StringToVariant(appData.variant);
2003 InitPosition(FALSE);
2006 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
2008 if (isdigit(appData.boardSize[0])) {
2009 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
2010 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
2011 &fontPxlSize, &smallLayout, &tinyLayout);
2013 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
2014 programName, appData.boardSize);
2018 /* Find some defaults; use the nearest known size */
2019 SizeDefaults *szd, *nearest;
2020 int distance = 99999;
2021 nearest = szd = sizeDefaults;
2022 while (szd->name != NULL) {
2023 if (abs(szd->squareSize - squareSize) < distance) {
2025 distance = abs(szd->squareSize - squareSize);
2026 if (distance == 0) break;
2030 if (i < 2) lineGap = nearest->lineGap;
2031 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
2032 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
2033 if (i < 5) fontPxlSize = nearest->fontPxlSize;
2034 if (i < 6) smallLayout = nearest->smallLayout;
2035 if (i < 7) tinyLayout = nearest->tinyLayout;
2038 SizeDefaults *szd = sizeDefaults;
2039 if (*appData.boardSize == NULLCHAR) {
2040 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
2041 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
2044 if (szd->name == NULL) szd--;
2045 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
2047 while (szd->name != NULL &&
2048 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
2049 if (szd->name == NULL) {
2050 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
2051 programName, appData.boardSize);
2055 squareSize = szd->squareSize;
2056 lineGap = szd->lineGap;
2057 clockFontPxlSize = szd->clockFontPxlSize;
2058 coordFontPxlSize = szd->coordFontPxlSize;
2059 fontPxlSize = szd->fontPxlSize;
2060 smallLayout = szd->smallLayout;
2061 tinyLayout = szd->tinyLayout;
2062 // [HGM] font: use defaults from settings file if available and not overruled
2064 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
2065 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
2066 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
2067 appData.font = fontTable[MESSAGE_FONT][squareSize];
2068 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
2069 appData.coordFont = fontTable[COORD_FONT][squareSize];
2071 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
2072 if (strlen(appData.pixmapDirectory) > 0) {
2073 p = ExpandPathName(appData.pixmapDirectory);
2075 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
2076 appData.pixmapDirectory);
2079 if (appData.debugMode) {
2080 fprintf(stderr, _("\
2081 XBoard square size (hint): %d\n\
2082 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
2084 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
2085 if (appData.debugMode) {
2086 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
2089 defaultLineGap = lineGap;
2090 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
2092 /* [HR] height treated separately (hacked) */
2093 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
2094 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
2095 if (appData.showJail == 1) {
2096 /* Jail on top and bottom */
2097 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2098 XtSetArg(boardArgs[2], XtNheight,
2099 boardHeight + 2*(lineGap + squareSize));
2100 } else if (appData.showJail == 2) {
2102 XtSetArg(boardArgs[1], XtNwidth,
2103 boardWidth + 2*(lineGap + squareSize));
2104 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2107 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2108 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2112 * Determine what fonts to use.
2114 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2115 clockFontID = XLoadFont(xDisplay, appData.clockFont);
2116 clockFontStruct = XQueryFont(xDisplay, clockFontID);
2117 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2118 coordFontID = XLoadFont(xDisplay, appData.coordFont);
2119 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2120 appData.font = FindFont(appData.font, fontPxlSize);
2121 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
2122 countFontStruct = XQueryFont(xDisplay, countFontID);
2123 // appData.font = FindFont(appData.font, fontPxlSize);
2125 xdb = XtDatabase(xDisplay);
2126 XrmPutStringResource(&xdb, "*font", appData.font);
2129 * Detect if there are not enough colors available and adapt.
2131 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2132 appData.monoMode = True;
2135 forceMono = MakeColors();
2138 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2141 if (appData.bitmapDirectory == NULL ||
2142 appData.bitmapDirectory[0] == NULLCHAR)
2143 appData.bitmapDirectory = DEF_BITMAP_DIR;
2146 if (appData.lowTimeWarning && !appData.monoMode) {
2147 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2148 vFrom.size = strlen(appData.lowTimeWarningColor);
2149 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2150 if (vTo.addr == NULL)
2151 appData.monoMode = True;
2153 lowTimeWarningColor = *(Pixel *) vTo.addr;
2156 if (appData.monoMode && appData.debugMode) {
2157 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2158 (unsigned long) XWhitePixel(xDisplay, xScreen),
2159 (unsigned long) XBlackPixel(xDisplay, xScreen));
2162 ParseIcsTextColors();
2163 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2164 textColors[ColorNone].attr = 0;
2166 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2172 layoutName = "tinyLayout";
2173 } else if (smallLayout) {
2174 layoutName = "smallLayout";
2176 layoutName = "normalLayout";
2178 /* Outer layoutWidget is there only to provide a name for use in
2179 resources that depend on the layout style */
2181 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2182 layoutArgs, XtNumber(layoutArgs));
2184 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2185 formArgs, XtNumber(formArgs));
2186 XtSetArg(args[0], XtNdefaultDistance, &sep);
2187 XtGetValues(formWidget, args, 1);
2190 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2191 XtSetArg(args[0], XtNtop, XtChainTop);
2192 XtSetArg(args[1], XtNbottom, XtChainTop);
2193 XtSetArg(args[2], XtNright, XtChainLeft);
2194 XtSetValues(menuBarWidget, args, 3);
2196 widgetList[j++] = whiteTimerWidget =
2197 XtCreateWidget("whiteTime", labelWidgetClass,
2198 formWidget, timerArgs, XtNumber(timerArgs));
2199 XtSetArg(args[0], XtNfont, clockFontStruct);
2200 XtSetArg(args[1], XtNtop, XtChainTop);
2201 XtSetArg(args[2], XtNbottom, XtChainTop);
2202 XtSetValues(whiteTimerWidget, args, 3);
2204 widgetList[j++] = blackTimerWidget =
2205 XtCreateWidget("blackTime", labelWidgetClass,
2206 formWidget, timerArgs, XtNumber(timerArgs));
2207 XtSetArg(args[0], XtNfont, clockFontStruct);
2208 XtSetArg(args[1], XtNtop, XtChainTop);
2209 XtSetArg(args[2], XtNbottom, XtChainTop);
2210 XtSetValues(blackTimerWidget, args, 3);
2212 if (appData.titleInWindow) {
2213 widgetList[j++] = titleWidget =
2214 XtCreateWidget("title", labelWidgetClass, formWidget,
2215 titleArgs, XtNumber(titleArgs));
2216 XtSetArg(args[0], XtNtop, XtChainTop);
2217 XtSetArg(args[1], XtNbottom, XtChainTop);
2218 XtSetValues(titleWidget, args, 2);
2221 if (appData.showButtonBar) {
2222 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2223 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2224 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2225 XtSetArg(args[2], XtNtop, XtChainTop);
2226 XtSetArg(args[3], XtNbottom, XtChainTop);
2227 XtSetValues(buttonBarWidget, args, 4);
2230 widgetList[j++] = messageWidget =
2231 XtCreateWidget("message", labelWidgetClass, formWidget,
2232 messageArgs, XtNumber(messageArgs));
2233 XtSetArg(args[0], XtNtop, XtChainTop);
2234 XtSetArg(args[1], XtNbottom, XtChainTop);
2235 XtSetValues(messageWidget, args, 2);
2237 widgetList[j++] = boardWidget =
2238 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2239 XtNumber(boardArgs));
2241 XtManageChildren(widgetList, j);
2243 timerWidth = (boardWidth - sep) / 2;
2244 XtSetArg(args[0], XtNwidth, timerWidth);
2245 XtSetValues(whiteTimerWidget, args, 1);
2246 XtSetValues(blackTimerWidget, args, 1);
2248 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2249 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2250 XtGetValues(whiteTimerWidget, args, 2);
2252 if (appData.showButtonBar) {
2253 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2254 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2255 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2259 * formWidget uses these constraints but they are stored
2263 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2264 XtSetValues(menuBarWidget, args, i);
2265 if (appData.titleInWindow) {
2268 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2269 XtSetValues(whiteTimerWidget, args, i);
2271 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2272 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2273 XtSetValues(blackTimerWidget, args, i);
2275 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2276 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2277 XtSetValues(titleWidget, args, i);
2279 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2280 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2281 XtSetValues(messageWidget, args, i);
2282 if (appData.showButtonBar) {
2284 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2285 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2286 XtSetValues(buttonBarWidget, args, i);
2290 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2291 XtSetValues(whiteTimerWidget, args, i);
2293 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2294 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2295 XtSetValues(blackTimerWidget, args, i);
2297 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2298 XtSetValues(titleWidget, args, i);
2300 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2301 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2302 XtSetValues(messageWidget, args, i);
2303 if (appData.showButtonBar) {
2305 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2306 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2307 XtSetValues(buttonBarWidget, args, i);
2312 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2313 XtSetValues(whiteTimerWidget, args, i);
2315 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2316 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2317 XtSetValues(blackTimerWidget, args, i);
2319 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2320 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2321 XtSetValues(messageWidget, args, i);
2322 if (appData.showButtonBar) {
2324 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2325 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2326 XtSetValues(buttonBarWidget, args, i);
2330 XtSetArg(args[0], XtNfromVert, messageWidget);
2331 XtSetArg(args[1], XtNtop, XtChainTop);
2332 XtSetArg(args[2], XtNbottom, XtChainBottom);
2333 XtSetArg(args[3], XtNleft, XtChainLeft);
2334 XtSetArg(args[4], XtNright, XtChainRight);
2335 XtSetValues(boardWidget, args, 5);
2337 XtRealizeWidget(shellWidget);
2340 XtSetArg(args[0], XtNx, wpMain.x);
2341 XtSetArg(args[1], XtNy, wpMain.y);
2342 XtSetValues(shellWidget, args, 2);
2346 * Correct the width of the message and title widgets.
2347 * It is not known why some systems need the extra fudge term.
2348 * The value "2" is probably larger than needed.
2350 XawFormDoLayout(formWidget, False);
2352 #define WIDTH_FUDGE 2
2354 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2355 XtSetArg(args[i], XtNheight, &h); i++;
2356 XtGetValues(messageWidget, args, i);
2357 if (appData.showButtonBar) {
2359 XtSetArg(args[i], XtNwidth, &w); i++;
2360 XtGetValues(buttonBarWidget, args, i);
2361 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2363 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2366 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2367 if (gres != XtGeometryYes && appData.debugMode) {
2368 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2369 programName, gres, w, h, wr, hr);
2372 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2373 /* The size used for the child widget in layout lags one resize behind
2374 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2376 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2377 if (gres != XtGeometryYes && appData.debugMode) {
2378 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2379 programName, gres, w, h, wr, hr);
2382 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2383 XtSetArg(args[1], XtNright, XtChainRight);
2384 XtSetValues(messageWidget, args, 2);
2386 if (appData.titleInWindow) {
2388 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2389 XtSetArg(args[i], XtNheight, &h); i++;
2390 XtGetValues(titleWidget, args, i);
2392 w = boardWidth - 2*bor;
2394 XtSetArg(args[0], XtNwidth, &w);
2395 XtGetValues(menuBarWidget, args, 1);
2396 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2399 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2400 if (gres != XtGeometryYes && appData.debugMode) {
2402 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2403 programName, gres, w, h, wr, hr);
2406 XawFormDoLayout(formWidget, True);
2408 xBoardWindow = XtWindow(boardWidget);
2410 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2411 // not need to go into InitDrawingSizes().
2415 * Create X checkmark bitmap and initialize option menu checks.
2417 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2418 checkmark_bits, checkmark_width, checkmark_height);
2419 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2420 #ifndef OPTIONSDIALOG
2421 if (appData.alwaysPromoteToQueen) {
2422 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2425 if (appData.animateDragging) {
2426 XtSetValues(XtNameToWidget(menuBarWidget,
2427 "menuOptions.Animate Dragging"),
2430 if (appData.animate) {
2431 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2434 if (appData.autoCallFlag) {
2435 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2438 if (appData.autoFlipView) {
2439 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2442 if (appData.blindfold) {
2443 XtSetValues(XtNameToWidget(menuBarWidget,
2444 "menuOptions.Blindfold"), args, 1);
2446 if (appData.flashCount > 0) {
2447 XtSetValues(XtNameToWidget(menuBarWidget,
2448 "menuOptions.Flash Moves"),
2452 if (appData.highlightDragging) {
2453 XtSetValues(XtNameToWidget(menuBarWidget,
2454 "menuOptions.Highlight Dragging"),
2458 if (appData.highlightLastMove) {
2459 XtSetValues(XtNameToWidget(menuBarWidget,
2460 "menuOptions.Highlight Last Move"),
2463 if (appData.highlightMoveWithArrow) {
2464 XtSetValues(XtNameToWidget(menuBarWidget,
2465 "menuOptions.Arrow"),
2468 // if (appData.icsAlarm) {
2469 // XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2472 if (appData.ringBellAfterMoves) {
2473 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2476 if (appData.oneClick) {
2477 XtSetValues(XtNameToWidget(menuBarWidget,
2478 "menuOptions.OneClick"), args, 1);
2480 if (appData.periodicUpdates) {
2481 XtSetValues(XtNameToWidget(menuBarWidget,
2482 "menuOptions.Periodic Updates"), args, 1);
2484 if (appData.ponderNextMove) {
2485 XtSetValues(XtNameToWidget(menuBarWidget,
2486 "menuOptions.Ponder Next Move"), args, 1);
2488 if (appData.popupExitMessage) {
2489 XtSetValues(XtNameToWidget(menuBarWidget,
2490 "menuOptions.Popup Exit Message"), args, 1);
2492 if (appData.popupMoveErrors) {
2493 XtSetValues(XtNameToWidget(menuBarWidget,
2494 "menuOptions.Popup Move Errors"), args, 1);
2496 // if (appData.premove) {
2497 // XtSetValues(XtNameToWidget(menuBarWidget,
2498 // "menuOptions.Premove"), args, 1);
2500 if (appData.showCoords) {
2501 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2504 if (appData.hideThinkingFromHuman) {
2505 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2508 if (appData.testLegality) {
2509 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2513 if (saveSettingsOnExit) {
2514 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2521 ReadBitmap(&wIconPixmap, "icon_white.bm",
2522 icon_white_bits, icon_white_width, icon_white_height);
2523 ReadBitmap(&bIconPixmap, "icon_black.bm",
2524 icon_black_bits, icon_black_width, icon_black_height);
2525 iconPixmap = wIconPixmap;
2527 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2528 XtSetValues(shellWidget, args, i);
2531 * Create a cursor for the board widget.
2533 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2534 XChangeWindowAttributes(xDisplay, xBoardWindow,
2535 CWCursor, &window_attributes);
2538 * Inhibit shell resizing.
2540 shellArgs[0].value = (XtArgVal) &w;
2541 shellArgs[1].value = (XtArgVal) &h;
2542 XtGetValues(shellWidget, shellArgs, 2);
2543 shellArgs[4].value = shellArgs[2].value = w;
2544 shellArgs[5].value = shellArgs[3].value = h;
2545 XtSetValues(shellWidget, &shellArgs[2], 4);
2546 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2547 marginH = h - boardHeight;
2549 CatchDeleteWindow(shellWidget, "QuitProc");
2554 if (appData.bitmapDirectory[0] != NULLCHAR) {
2558 CreateXPMBoard(appData.liteBackTextureFile, 1);
2559 CreateXPMBoard(appData.darkBackTextureFile, 0);
2563 /* Create regular pieces */
2564 if (!useImages) CreatePieces();
2569 if (appData.animate || appData.animateDragging)
2572 XtAugmentTranslations(formWidget,
2573 XtParseTranslationTable(globalTranslations));
2574 XtAugmentTranslations(boardWidget,
2575 XtParseTranslationTable(boardTranslations));
2576 XtAugmentTranslations(whiteTimerWidget,
2577 XtParseTranslationTable(whiteTranslations));
2578 XtAugmentTranslations(blackTimerWidget,
2579 XtParseTranslationTable(blackTranslations));
2581 /* Why is the following needed on some versions of X instead
2582 * of a translation? */
2583 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2584 (XtEventHandler) EventProc, NULL);
2587 /* [AS] Restore layout */
2588 if( wpMoveHistory.visible ) {
2592 if( wpEvalGraph.visible )
2597 if( wpEngineOutput.visible ) {
2598 EngineOutputPopUp();
2603 if (errorExitStatus == -1) {
2604 if (appData.icsActive) {
2605 /* We now wait until we see "login:" from the ICS before
2606 sending the logon script (problems with timestamp otherwise) */
2607 /*ICSInitScript();*/
2608 if (appData.icsInputBox) ICSInputBoxPopUp();
2612 signal(SIGWINCH, TermSizeSigHandler);
2614 signal(SIGINT, IntSigHandler);
2615 signal(SIGTERM, IntSigHandler);
2616 if (*appData.cmailGameName != NULLCHAR) {
2617 signal(SIGUSR1, CmailSigHandler);
2620 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2622 XtSetKeyboardFocus(shellWidget, formWidget);
2624 XtAppMainLoop(appContext);
2625 if (appData.debugMode) fclose(debugFP); // [DM] debug
2632 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2633 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2635 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2636 unlink(gameCopyFilename);
2637 unlink(gamePasteFilename);
2640 RETSIGTYPE TermSizeSigHandler(int sig)
2653 CmailSigHandler(sig)
2659 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2661 /* Activate call-back function CmailSigHandlerCallBack() */
2662 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2664 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2668 CmailSigHandlerCallBack(isr, closure, message, count, error)
2676 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2678 /**** end signal code ****/
2684 /* try to open the icsLogon script, either in the location given
2685 * or in the users HOME directory
2692 f = fopen(appData.icsLogon, "r");
2695 homedir = getenv("HOME");
2696 if (homedir != NULL)
2698 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2699 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2700 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2701 f = fopen(buf, "r");
2706 ProcessICSInitScript(f);
2708 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2717 EditCommentPopDown();
2732 if (!menuBarWidget) return;
2733 w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2735 DisplayError("menuEdit.Revert", 0);
2737 XtSetSensitive(w, !grey);
2739 w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2741 DisplayError("menuEdit.Annotate", 0);
2743 XtSetSensitive(w, !grey);
2748 SetMenuEnables(enab)
2752 if (!menuBarWidget) return;
2753 while (enab->name != NULL) {
2754 w = XtNameToWidget(menuBarWidget, enab->name);
2756 DisplayError(enab->name, 0);
2758 XtSetSensitive(w, enab->value);
2764 Enables icsEnables[] = {
2765 { "menuFile.Mail Move", False },
2766 { "menuFile.Reload CMail Message", False },
2767 { "menuMode.Machine Black", False },
2768 { "menuMode.Machine White", False },
2769 { "menuMode.Analysis Mode", False },
2770 { "menuMode.Analyze File", False },
2771 { "menuMode.Two Machines", False },
2772 { "menuMode.Machine Match", False },
2774 { "menuEngine.Hint", False },
2775 { "menuEngine.Book", False },
2776 { "menuEngine.Move Now", False },
2777 #ifndef OPTIONSDIALOG
2778 { "menuOptions.Periodic Updates", False },
2779 { "menuOptions.Hide Thinking", False },
2780 { "menuOptions.Ponder Next Move", False },
2782 { "menuEngine.Engine #1 Settings", False },
2784 { "menuEngine.Engine #2 Settings", False },
2785 { "menuEdit.Annotate", False },
2789 Enables ncpEnables[] = {
2790 { "menuFile.Mail Move", False },
2791 { "menuFile.Reload CMail Message", False },
2792 { "menuMode.Machine White", False },
2793 { "menuMode.Machine Black", False },
2794 { "menuMode.Analysis Mode", False },
2795 { "menuMode.Analyze File", False },
2796 { "menuMode.Two Machines", False },
2797 { "menuMode.Machine Match", False },
2798 { "menuMode.ICS Client", False },
2799 { "menuView.ICStex", False },
2800 { "menuView.ICS Input Box", False },
2801 { "Action", False },
2802 { "menuEdit.Revert", False },
2803 { "menuEdit.Annotate", False },
2804 { "menuEngine.Engine #1 Settings", False },
2805 { "menuEngine.Engine #2 Settings", False },
2806 { "menuEngine.Move Now", False },
2807 { "menuEngine.Retract Move", False },
2808 { "menuOptions.ICS", False },
2809 #ifndef OPTIONSDIALOG
2810 { "menuOptions.Auto Flag", False },
2811 { "menuOptions.Auto Flip View", False },
2812 // { "menuOptions.ICS Alarm", False },
2813 { "menuOptions.Move Sound", False },
2814 { "menuOptions.Hide Thinking", False },
2815 { "menuOptions.Periodic Updates", False },
2816 { "menuOptions.Ponder Next Move", False },
2818 { "menuEngine.Hint", False },
2819 { "menuEngine.Book", False },
2823 Enables gnuEnables[] = {
2824 { "menuMode.ICS Client", False },
2825 { "menuView.ICStex", False },
2826 { "menuView.ICS Input Box", False },
2827 { "menuAction.Accept", False },
2828 { "menuAction.Decline", False },
2829 { "menuAction.Rematch", False },
2830 { "menuAction.Adjourn", False },
2831 { "menuAction.Stop Examining", False },
2832 { "menuAction.Stop Observing", False },
2833 { "menuAction.Upload to Examine", False },
2834 { "menuEdit.Revert", False },
2835 { "menuEdit.Annotate", False },
2836 { "menuOptions.ICS", False },
2838 /* The next two options rely on SetCmailMode being called *after* */
2839 /* SetGNUMode so that when GNU is being used to give hints these */
2840 /* menu options are still available */
2842 { "menuFile.Mail Move", False },
2843 { "menuFile.Reload CMail Message", False },
2847 Enables cmailEnables[] = {
2849 { "menuAction.Call Flag", False },
2850 { "menuAction.Draw", True },
2851 { "menuAction.Adjourn", False },
2852 { "menuAction.Abort", False },
2853 { "menuAction.Stop Observing", False },
2854 { "menuAction.Stop Examining", False },
2855 { "menuFile.Mail Move", True },
2856 { "menuFile.Reload CMail Message", True },
2860 Enables trainingOnEnables[] = {
2861 { "menuMode.Edit Comment", False },
2862 { "menuMode.Pause", False },
2863 { "menuEdit.Forward", False },
2864 { "menuEdit.Backward", False },
2865 { "menuEdit.Forward to End", False },
2866 { "menuEdit.Back to Start", False },
2867 { "menuEngine.Move Now", False },
2868 { "menuEdit.Truncate Game", False },
2872 Enables trainingOffEnables[] = {
2873 { "menuMode.Edit Comment", True },
2874 { "menuMode.Pause", True },
2875 { "menuEdit.Forward", True },
2876 { "menuEdit.Backward", True },
2877 { "menuEdit.Forward to End", True },
2878 { "menuEdit.Back to Start", True },
2879 { "menuEngine.Move Now", True },
2880 { "menuEdit.Truncate Game", True },
2884 Enables machineThinkingEnables[] = {
2885 { "menuFile.Load Game", False },
2886 // { "menuFile.Load Next Game", False },
2887 // { "menuFile.Load Previous Game", False },
2888 // { "menuFile.Reload Same Game", False },
2889 { "menuEdit.Paste Game", False },
2890 { "menuFile.Load Position", False },
2891 // { "menuFile.Load Next Position", False },
2892 // { "menuFile.Load Previous Position", False },
2893 // { "menuFile.Reload Same Position", False },
2894 { "menuEdit.Paste Position", False },
2895 { "menuMode.Machine White", False },
2896 { "menuMode.Machine Black", False },
2897 { "menuMode.Two Machines", False },
2898 { "menuMode.Machine Match", False },
2899 { "menuEngine.Retract Move", False },
2903 Enables userThinkingEnables[] = {
2904 { "menuFile.Load Game", True },
2905 // { "menuFile.Load Next Game", True },
2906 // { "menuFile.Load Previous Game", True },
2907 // { "menuFile.Reload Same Game", True },
2908 { "menuEdit.Paste Game", True },
2909 { "menuFile.Load Position", True },
2910 // { "menuFile.Load Next Position", True },
2911 // { "menuFile.Load Previous Position", True },
2912 // { "menuFile.Reload Same Position", True },
2913 { "menuEdit.Paste Position", True },
2914 { "menuMode.Machine White", True },
2915 { "menuMode.Machine Black", True },
2916 { "menuMode.Two Machines", True },
2917 { "menuMode.Machine Match", True },
2918 { "menuEngine.Retract Move", True },
2924 SetMenuEnables(icsEnables);
2927 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2928 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2935 SetMenuEnables(ncpEnables);
2941 SetMenuEnables(gnuEnables);
2947 SetMenuEnables(cmailEnables);
2953 SetMenuEnables(trainingOnEnables);
2954 if (appData.showButtonBar) {
2955 XtSetSensitive(buttonBarWidget, False);
2961 SetTrainingModeOff()
2963 SetMenuEnables(trainingOffEnables);
2964 if (appData.showButtonBar) {
2965 XtSetSensitive(buttonBarWidget, True);
2970 SetUserThinkingEnables()
2972 if (appData.noChessProgram) return;
2973 SetMenuEnables(userThinkingEnables);
2977 SetMachineThinkingEnables()
2979 if (appData.noChessProgram) return;
2980 SetMenuEnables(machineThinkingEnables);
2982 case MachinePlaysBlack:
2983 case MachinePlaysWhite:
2984 case TwoMachinesPlay:
2985 XtSetSensitive(XtNameToWidget(menuBarWidget,
2986 ModeToWidgetName(gameMode)), True);
2993 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2994 #define HISTORY_SIZE 64
2995 static char *history[HISTORY_SIZE];
2996 int histIn = 0, histP = 0;
2999 SaveInHistory(char *cmd)
3001 if (history[histIn] != NULL) {
3002 free(history[histIn]);
3003 history[histIn] = NULL;
3005 if (*cmd == NULLCHAR) return;
3006 history[histIn] = StrSave(cmd);
3007 histIn = (histIn + 1) % HISTORY_SIZE;
3008 if (history[histIn] != NULL) {
3009 free(history[histIn]);
3010 history[histIn] = NULL;
3016 PrevInHistory(char *cmd)
3019 if (histP == histIn) {
3020 if (history[histIn] != NULL) free(history[histIn]);
3021 history[histIn] = StrSave(cmd);
3023 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
3024 if (newhp == histIn || history[newhp] == NULL) return NULL;
3026 return history[histP];
3032 if (histP == histIn) return NULL;
3033 histP = (histP + 1) % HISTORY_SIZE;
3034 return history[histP];
3036 // end of borrowed code
3038 #define Abs(n) ((n)<0 ? -(n) : (n))
3041 * Find a font that matches "pattern" that is as close as
3042 * possible to the targetPxlSize. Prefer fonts that are k
3043 * pixels smaller to fonts that are k pixels larger. The
3044 * pattern must be in the X Consortium standard format,
3045 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3046 * The return value should be freed with XtFree when no
3050 FindFont(pattern, targetPxlSize)
3054 char **fonts, *p, *best, *scalable, *scalableTail;
3055 int i, j, nfonts, minerr, err, pxlSize;
3058 char **missing_list;
3060 char *def_string, *base_fnt_lst, strInt[3];
3062 XFontStruct **fnt_list;
3064 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3065 snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
3066 p = strstr(pattern, "--");
3067 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3068 strcat(base_fnt_lst, strInt);
3069 strcat(base_fnt_lst, strchr(p + 2, '-'));
3071 if ((fntSet = XCreateFontSet(xDisplay,
3075 &def_string)) == NULL) {
3077 fprintf(stderr, _("Unable to create font set.\n"));
3081 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3083 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3085 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3086 programName, pattern);
3094 for (i=0; i<nfonts; i++) {
3097 if (*p != '-') continue;
3099 if (*p == NULLCHAR) break;
3100 if (*p++ == '-') j++;
3102 if (j < 7) continue;
3105 scalable = fonts[i];
3108 err = pxlSize - targetPxlSize;
3109 if (Abs(err) < Abs(minerr) ||
3110 (minerr > 0 && err < 0 && -err == minerr)) {
3116 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3117 /* If the error is too big and there is a scalable font,
3118 use the scalable font. */
3119 int headlen = scalableTail - scalable;
3120 p = (char *) XtMalloc(strlen(scalable) + 10);
3121 while (isdigit(*scalableTail)) scalableTail++;
3122 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3124 p = (char *) XtMalloc(strlen(best) + 2);
3125 safeStrCpy(p, best, strlen(best)+1 );
3127 if (appData.debugMode) {
3128 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3129 pattern, targetPxlSize, p);
3132 if (missing_count > 0)
3133 XFreeStringList(missing_list);
3134 XFreeFontSet(xDisplay, fntSet);
3136 XFreeFontNames(fonts);
3142 { // [HGM] deletes GCs that are to be remade, to prevent resource leak;
3143 // must be called before all non-first callse to CreateGCs()
3144 XtReleaseGC(shellWidget, highlineGC);
3145 XtReleaseGC(shellWidget, lightSquareGC);
3146 XtReleaseGC(shellWidget, darkSquareGC);
3147 XtReleaseGC(shellWidget, lineGC);
3148 if (appData.monoMode) {
3149 if (DefaultDepth(xDisplay, xScreen) == 1) {
3150 XtReleaseGC(shellWidget, wbPieceGC);
3152 XtReleaseGC(shellWidget, bwPieceGC);
3155 XtReleaseGC(shellWidget, prelineGC);
3156 XtReleaseGC(shellWidget, jailSquareGC);
3157 XtReleaseGC(shellWidget, wdPieceGC);
3158 XtReleaseGC(shellWidget, wlPieceGC);
3159 XtReleaseGC(shellWidget, wjPieceGC);
3160 XtReleaseGC(shellWidget, bdPieceGC);
3161 XtReleaseGC(shellWidget, blPieceGC);
3162 XtReleaseGC(shellWidget, bjPieceGC);
3166 void CreateGCs(int redo)
3168 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3169 | GCBackground | GCFunction | GCPlaneMask;
3170 XGCValues gc_values;
3173 gc_values.plane_mask = AllPlanes;
3174 gc_values.line_width = lineGap;
3175 gc_values.line_style = LineSolid;
3176 gc_values.function = GXcopy;
3179 DeleteGCs(); // called a second time; clean up old GCs first
3180 } else { // [HGM] grid and font GCs created on first call only
3181 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3182 gc_values.background = XWhitePixel(xDisplay, xScreen);
3183 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3184 XSetFont(xDisplay, coordGC, coordFontID);
3186 // [HGM] make font for holdings counts (white on black)
3187 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3188 gc_values.background = XBlackPixel(xDisplay, xScreen);
3189 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3190 XSetFont(xDisplay, countGC, countFontID);
3192 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3193 gc_values.background = XBlackPixel(xDisplay, xScreen);
3194 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3196 if (appData.monoMode) {
3197 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3198 gc_values.background = XWhitePixel(xDisplay, xScreen);
3199 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3201 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3202 gc_values.background = XBlackPixel(xDisplay, xScreen);
3203 lightSquareGC = wbPieceGC
3204 = XtGetGC(shellWidget, value_mask, &gc_values);
3206 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3207 gc_values.background = XWhitePixel(xDisplay, xScreen);
3208 darkSquareGC = bwPieceGC
3209 = XtGetGC(shellWidget, value_mask, &gc_values);
3211 if (DefaultDepth(xDisplay, xScreen) == 1) {
3212 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3213 gc_values.function = GXcopyInverted;
3214 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3215 gc_values.function = GXcopy;
3216 if (XBlackPixel(xDisplay, xScreen) == 1) {
3217 bwPieceGC = darkSquareGC;
3218 wbPieceGC = copyInvertedGC;
3220 bwPieceGC = copyInvertedGC;
3221 wbPieceGC = lightSquareGC;
3225 gc_values.foreground = highlightSquareColor;
3226 gc_values.background = highlightSquareColor;
3227 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3229 gc_values.foreground = premoveHighlightColor;
3230 gc_values.background = premoveHighlightColor;
3231 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3233 gc_values.foreground = lightSquareColor;
3234 gc_values.background = darkSquareColor;
3235 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3237 gc_values.foreground = darkSquareColor;
3238 gc_values.background = lightSquareColor;
3239 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3241 gc_values.foreground = jailSquareColor;
3242 gc_values.background = jailSquareColor;
3243 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3245 gc_values.foreground = whitePieceColor;
3246 gc_values.background = darkSquareColor;
3247 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3249 gc_values.foreground = whitePieceColor;
3250 gc_values.background = lightSquareColor;
3251 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3253 gc_values.foreground = whitePieceColor;
3254 gc_values.background = jailSquareColor;
3255 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3257 gc_values.foreground = blackPieceColor;
3258 gc_values.background = darkSquareColor;
3259 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3261 gc_values.foreground = blackPieceColor;
3262 gc_values.background = lightSquareColor;
3263 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3265 gc_values.foreground = blackPieceColor;
3266 gc_values.background = jailSquareColor;
3267 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3271 void loadXIM(xim, xmask, filename, dest, mask)
3284 fp = fopen(filename, "rb");
3286 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3293 for (y=0; y<h; ++y) {
3294 for (x=0; x<h; ++x) {
3299 XPutPixel(xim, x, y, blackPieceColor);
3301 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3304 XPutPixel(xim, x, y, darkSquareColor);
3306 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3309 XPutPixel(xim, x, y, whitePieceColor);
3311 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3314 XPutPixel(xim, x, y, lightSquareColor);
3316 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3324 /* create Pixmap of piece */
3325 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3327 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3330 /* create Pixmap of clipmask
3331 Note: We assume the white/black pieces have the same
3332 outline, so we make only 6 masks. This is okay
3333 since the XPM clipmask routines do the same. */
3335 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3337 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3340 /* now create the 1-bit version */
3341 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3344 values.foreground = 1;
3345 values.background = 0;
3347 /* Don't use XtGetGC, not read only */
3348 maskGC = XCreateGC(xDisplay, *mask,
3349 GCForeground | GCBackground, &values);
3350 XCopyPlane(xDisplay, temp, *mask, maskGC,
3351 0, 0, squareSize, squareSize, 0, 0, 1);
3352 XFreePixmap(xDisplay, temp);
3357 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3359 void CreateXIMPieces()
3364 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3369 /* The XSynchronize calls were copied from CreatePieces.
3370 Not sure if needed, but can't hurt */
3371 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3374 /* temp needed by loadXIM() */
3375 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3376 0, 0, ss, ss, AllPlanes, XYPixmap);
3378 if (strlen(appData.pixmapDirectory) == 0) {
3382 if (appData.monoMode) {
3383 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3387 fprintf(stderr, _("\nLoading XIMs...\n"));
3389 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3390 fprintf(stderr, "%d", piece+1);
3391 for (kind=0; kind<4; kind++) {
3392 fprintf(stderr, ".");
3393 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3394 ExpandPathName(appData.pixmapDirectory),
3395 piece <= (int) WhiteKing ? "" : "w",
3396 pieceBitmapNames[piece],
3398 ximPieceBitmap[kind][piece] =
3399 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3400 0, 0, ss, ss, AllPlanes, XYPixmap);
3401 if (appData.debugMode)
3402 fprintf(stderr, _("(File:%s:) "), buf);
3403 loadXIM(ximPieceBitmap[kind][piece],
3405 &(xpmPieceBitmap2[kind][piece]),
3406 &(ximMaskPm2[piece]));
3407 if(piece <= (int)WhiteKing)
3408 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3410 fprintf(stderr," ");
3412 /* Load light and dark squares */
3413 /* If the LSQ and DSQ pieces don't exist, we will
3414 draw them with solid squares. */
3415 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3416 if (access(buf, 0) != 0) {
3420 fprintf(stderr, _("light square "));
3422 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3423 0, 0, ss, ss, AllPlanes, XYPixmap);
3424 if (appData.debugMode)
3425 fprintf(stderr, _("(File:%s:) "), buf);
3427 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3428 fprintf(stderr, _("dark square "));
3429 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3430 ExpandPathName(appData.pixmapDirectory), ss);
3431 if (appData.debugMode)
3432 fprintf(stderr, _("(File:%s:) "), buf);
3434 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3435 0, 0, ss, ss, AllPlanes, XYPixmap);
3436 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3437 xpmJailSquare = xpmLightSquare;
3439 fprintf(stderr, _("Done.\n"));
3441 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3444 static VariantClass oldVariant = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
3447 void CreateXPMBoard(char *s, int kind)
3451 if(s == NULL || *s == 0 || *s == '*') { useTexture &= ~(kind+1); return; }
3452 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3453 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3457 void FreeXPMPieces()
3458 { // [HGM] to prevent resoucre leak on calling CreaeXPMPieces() a second time,
3459 // thisroutine has to be called t free the old piece pixmaps
3461 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++)
3462 for (kind=0; kind<4; kind++) XFreePixmap(xDisplay, xpmPieceBitmap2[kind][piece]);
3464 XFreePixmap(xDisplay, xpmLightSquare);
3465 XFreePixmap(xDisplay, xpmDarkSquare);
3469 void CreateXPMPieces()
3473 u_int ss = squareSize;
3475 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3476 XpmColorSymbol symbols[4];
3477 static int redo = False;
3479 if(redo) FreeXPMPieces(); else redo = 1;
3481 /* The XSynchronize calls were copied from CreatePieces.
3482 Not sure if needed, but can't hurt */
3483 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3485 /* Setup translations so piece colors match square colors */
3486 symbols[0].name = "light_piece";
3487 symbols[0].value = appData.whitePieceColor;
3488 symbols[1].name = "dark_piece";
3489 symbols[1].value = appData.blackPieceColor;
3490 symbols[2].name = "light_square";
3491 symbols[2].value = appData.lightSquareColor;
3492 symbols[3].name = "dark_square";
3493 symbols[3].value = appData.darkSquareColor;
3495 attr.valuemask = XpmColorSymbols;
3496 attr.colorsymbols = symbols;
3497 attr.numsymbols = 4;
3499 if (appData.monoMode) {
3500 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3504 if (strlen(appData.pixmapDirectory) == 0) {
3505 XpmPieces* pieces = builtInXpms;
3508 while (pieces->size != squareSize && pieces->size) pieces++;
3509 if (!pieces->size) {
3510 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3513 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3514 for (kind=0; kind<4; kind++) {
3516 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3517 pieces->xpm[piece][kind],
3518 &(xpmPieceBitmap2[kind][piece]),
3519 NULL, &attr)) != 0) {
3520 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3524 if(piece <= (int) WhiteKing)
3525 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3529 xpmJailSquare = xpmLightSquare;
3533 fprintf(stderr, _("\nLoading XPMs...\n"));
3536 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3537 fprintf(stderr, "%d ", piece+1);
3538 for (kind=0; kind<4; kind++) {
3539 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3540 ExpandPathName(appData.pixmapDirectory),
3541 piece > (int) WhiteKing ? "w" : "",
3542 pieceBitmapNames[piece],
3544 if (appData.debugMode) {
3545 fprintf(stderr, _("(File:%s:) "), buf);
3547 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3548 &(xpmPieceBitmap2[kind][piece]),
3549 NULL, &attr)) != 0) {
3550 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3551 // [HGM] missing: read of unorthodox piece failed; substitute King.
3552 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3553 ExpandPathName(appData.pixmapDirectory),
3555 if (appData.debugMode) {
3556 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3558 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3559 &(xpmPieceBitmap2[kind][piece]),
3563 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3568 if(piece <= (int) WhiteKing)
3569 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3572 /* Load light and dark squares */
3573 /* If the LSQ and DSQ pieces don't exist, we will
3574 draw them with solid squares. */
3575 fprintf(stderr, _("light square "));
3576 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3577 if (access(buf, 0) != 0) {
3581 if (appData.debugMode)
3582 fprintf(stderr, _("(File:%s:) "), buf);
3584 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3585 &xpmLightSquare, NULL, &attr)) != 0) {
3586 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3589 fprintf(stderr, _("dark square "));
3590 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3591 ExpandPathName(appData.pixmapDirectory), ss);
3592 if (appData.debugMode) {
3593 fprintf(stderr, _("(File:%s:) "), buf);
3595 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3596 &xpmDarkSquare, NULL, &attr)) != 0) {
3597 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3601 xpmJailSquare = xpmLightSquare;
3602 fprintf(stderr, _("Done.\n"));
3604 oldVariant = -1; // kludge to force re-makig of animation masks
3605 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3608 #endif /* HAVE_LIBXPM */
3611 /* No built-in bitmaps */
3616 u_int ss = squareSize;
3618 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3621 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3622 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3623 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3624 pieceBitmapNames[piece],
3625 ss, kind == SOLID ? 's' : 'o');
3626 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3627 if(piece <= (int)WhiteKing)
3628 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3632 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3636 /* With built-in bitmaps */
3639 BuiltInBits* bib = builtInBits;
3642 u_int ss = squareSize;
3644 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3647 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3649 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3650 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3651 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3652 pieceBitmapNames[piece],
3653 ss, kind == SOLID ? 's' : 'o');
3654 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3655 bib->bits[kind][piece], ss, ss);
3656 if(piece <= (int)WhiteKing)
3657 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3661 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3666 void ReadBitmap(pm, name, bits, wreq, hreq)
3669 unsigned char bits[];
3675 char msg[MSG_SIZ], fullname[MSG_SIZ];
3677 if (*appData.bitmapDirectory != NULLCHAR) {
3678 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3679 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3680 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3681 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3682 &w, &h, pm, &x_hot, &y_hot);
3683 fprintf(stderr, "load %s\n", name);
3684 if (errcode != BitmapSuccess) {
3686 case BitmapOpenFailed:
3687 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3689 case BitmapFileInvalid:
3690 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3692 case BitmapNoMemory:
3693 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3697 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3701 fprintf(stderr, _("%s: %s...using built-in\n"),
3703 } else if (w != wreq || h != hreq) {
3705 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3706 programName, fullname, w, h, wreq, hreq);
3712 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3721 if (lineGap == 0) return;
3723 /* [HR] Split this into 2 loops for non-square boards. */
3725 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3726 gridSegments[i].x1 = 0;
3727 gridSegments[i].x2 =
3728 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3729 gridSegments[i].y1 = gridSegments[i].y2
3730 = lineGap / 2 + (i * (squareSize + lineGap));
3733 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3734 gridSegments[j + i].y1 = 0;
3735 gridSegments[j + i].y2 =
3736 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3737 gridSegments[j + i].x1 = gridSegments[j + i].x2
3738 = lineGap / 2 + (j * (squareSize + lineGap));
3742 static void MenuBarSelect(w, addr, index)
3747 XtActionProc proc = (XtActionProc) addr;
3749 (proc)(NULL, NULL, NULL, NULL);
3752 void CreateMenuBarPopup(parent, name, mb)
3762 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3765 XtSetArg(args[j], XtNleftMargin, 20); j++;
3766 XtSetArg(args[j], XtNrightMargin, 20); j++;
3768 while (mi->string != NULL) {
3769 if (strcmp(mi->string, "----") == 0) {
3770 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3773 XtSetArg(args[j], XtNlabel, XtNewString(mi->string));
3774 entry = XtCreateManagedWidget(mi->ref, smeBSBObjectClass,
3776 XtAddCallback(entry, XtNcallback,
3777 (XtCallbackProc) MenuBarSelect,
3778 (caddr_t) mi->proc);
3784 Widget CreateMenuBar(mb)
3788 Widget anchor, menuBar;
3790 char menuName[MSG_SIZ];
3793 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3794 XtSetArg(args[j], XtNvSpace, 0); j++;
3795 XtSetArg(args[j], XtNborderWidth, 0); j++;
3796 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3797 formWidget, args, j);
3799 while (mb->name != NULL) {
3800 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3801 strncat(menuName, mb->ref, MSG_SIZ - strlen(menuName) - 1);
3803 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3806 shortName[0] = mb->name[0];
3807 shortName[1] = NULLCHAR;
3808 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3811 XtSetArg(args[j], XtNlabel, XtNewString(mb->name)); j++;
3814 XtSetArg(args[j], XtNborderWidth, 0); j++;
3815 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3817 CreateMenuBarPopup(menuBar, menuName, mb);
3823 Widget CreateButtonBar(mi)
3827 Widget button, buttonBar;
3831 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3833 XtSetArg(args[j], XtNhSpace, 0); j++;
3835 XtSetArg(args[j], XtNborderWidth, 0); j++;
3836 XtSetArg(args[j], XtNvSpace, 0); j++;
3837 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3838 formWidget, args, j);
3840 while (mi->string != NULL) {
3843 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3844 XtSetArg(args[j], XtNborderWidth, 0); j++;
3846 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3847 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3848 buttonBar, args, j);
3849 XtAddCallback(button, XtNcallback,
3850 (XtCallbackProc) MenuBarSelect,
3851 (caddr_t) mi->proc);
3858 CreatePieceMenu(name, color)
3865 ChessSquare selection;
3867 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3868 boardWidget, args, 0);
3870 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3871 String item = pieceMenuStrings[color][i];
3873 if (strcmp(item, "----") == 0) {
3874 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3877 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3878 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3880 selection = pieceMenuTranslation[color][i];
3881 XtAddCallback(entry, XtNcallback,
3882 (XtCallbackProc) PieceMenuSelect,
3883 (caddr_t) selection);
3884 if (selection == WhitePawn || selection == BlackPawn) {
3885 XtSetArg(args[0], XtNpopupOnEntry, entry);
3886 XtSetValues(menu, args, 1);
3899 ChessSquare selection;
3901 whitePieceMenu = CreatePieceMenu("menuW", 0);
3902 blackPieceMenu = CreatePieceMenu("menuB", 1);
3904 XtRegisterGrabAction(PieceMenuPopup, True,
3905 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3906 GrabModeAsync, GrabModeAsync);
3908 XtSetArg(args[0], XtNlabel, _("Drop"));
3909 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3910 boardWidget, args, 1);
3911 for (i = 0; i < DROP_MENU_SIZE; i++) {
3912 String item = dropMenuStrings[i];
3914 if (strcmp(item, "----") == 0) {
3915 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3918 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3919 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3921 selection = dropMenuTranslation[i];
3922 XtAddCallback(entry, XtNcallback,
3923 (XtCallbackProc) DropMenuSelect,
3924 (caddr_t) selection);
3929 void SetupDropMenu()
3937 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3938 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3939 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3940 dmEnables[i].piece);
3941 XtSetSensitive(entry, p != NULL || !appData.testLegality
3942 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3943 && !appData.icsActive));
3945 while (p && *p++ == dmEnables[i].piece) count++;
3946 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3948 XtSetArg(args[j], XtNlabel, label); j++;
3949 XtSetValues(entry, args, j);
3953 void PieceMenuPopup(w, event, params, num_params)
3957 Cardinal *num_params;
3959 String whichMenu; int menuNr;
3960 if (event->type == ButtonRelease)
3961 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3962 else if (event->type == ButtonPress)
3963 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3965 case 0: whichMenu = params[0]; break;
3966 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3968 case -1: if (errorUp) ErrorPopDown();
3971 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3974 static void PieceMenuSelect(w, piece, junk)
3979 if (pmFromX < 0 || pmFromY < 0) return;
3980 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3983 static void DropMenuSelect(w, piece, junk)
3988 if (pmFromX < 0 || pmFromY < 0) return;
3989 DropMenuEvent(piece, pmFromX, pmFromY);
3992 void WhiteClock(w, event, prms, nprms)
4001 void BlackClock(w, event, prms, nprms)
4012 * If the user selects on a border boundary, return -1; if off the board,
4013 * return -2. Otherwise map the event coordinate to the square.
4015 int EventToSquare(x, limit)
4023 if ((x % (squareSize + lineGap)) >= squareSize)
4025 x /= (squareSize + lineGap);
4031 static void do_flash_delay(msec)
4037 static void drawHighlight(file, rank, gc)
4043 if (lineGap == 0) return;
4046 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
4047 (squareSize + lineGap);
4048 y = lineGap/2 + rank * (squareSize + lineGap);
4050 x = lineGap/2 + file * (squareSize + lineGap);
4051 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
4052 (squareSize + lineGap);
4055 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
4056 squareSize+lineGap, squareSize+lineGap);
4059 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
4060 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4063 SetHighlights(fromX, fromY, toX, toY)
4064 int fromX, fromY, toX, toY;
4066 if (hi1X != fromX || hi1Y != fromY) {
4067 if (hi1X >= 0 && hi1Y >= 0) {
4068 drawHighlight(hi1X, hi1Y, lineGC);
4070 } // [HGM] first erase both, then draw new!
4071 if (hi2X != toX || hi2Y != toY) {
4072 if (hi2X >= 0 && hi2Y >= 0) {
4073 drawHighlight(hi2X, hi2Y, lineGC);
4076 if (hi1X != fromX || hi1Y != fromY) {
4077 if (fromX >= 0 && fromY >= 0) {
4078 drawHighlight(fromX, fromY, highlineGC);
4081 if (hi2X != toX || hi2Y != toY) {
4082 if (toX >= 0 && toY >= 0) {
4083 drawHighlight(toX, toY, highlineGC);
4095 SetHighlights(-1, -1, -1, -1);
4100 SetPremoveHighlights(fromX, fromY, toX, toY)
4101 int fromX, fromY, toX, toY;
4103 if (pm1X != fromX || pm1Y != fromY) {
4104 if (pm1X >= 0 && pm1Y >= 0) {
4105 drawHighlight(pm1X, pm1Y, lineGC);
4107 if (fromX >= 0 && fromY >= 0) {
4108 drawHighlight(fromX, fromY, prelineGC);
4111 if (pm2X != toX || pm2Y != toY) {
4112 if (pm2X >= 0 && pm2Y >= 0) {
4113 drawHighlight(pm2X, pm2Y, lineGC);
4115 if (toX >= 0 && toY >= 0) {
4116 drawHighlight(toX, toY, prelineGC);
4126 ClearPremoveHighlights()
4128 SetPremoveHighlights(-1, -1, -1, -1);
4131 static int CutOutSquare(x, y, x0, y0, kind)
4132 int x, y, *x0, *y0, kind;
4134 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
4135 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
4137 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
4138 if(textureW[kind] < W*squareSize)
4139 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
4141 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
4142 if(textureH[kind] < H*squareSize)
4143 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
4145 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
4149 static void BlankSquare(x, y, color, piece, dest, fac)
4150 int x, y, color, fac;
4153 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
4155 if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
4156 XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
4157 squareSize, squareSize, x*fac, y*fac);
4159 if (useImages && useImageSqs) {
4163 pm = xpmLightSquare;
4168 case 2: /* neutral */
4173 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4174 squareSize, squareSize, x*fac, y*fac);
4184 case 2: /* neutral */
4189 XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
4194 I split out the routines to draw a piece so that I could
4195 make a generic flash routine.
4197 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4199 int square_color, x, y;
4202 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4203 switch (square_color) {
4205 case 2: /* neutral */
4207 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4208 ? *pieceToOutline(piece)
4209 : *pieceToSolid(piece),
4210 dest, bwPieceGC, 0, 0,
4211 squareSize, squareSize, x, y);
4214 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4215 ? *pieceToSolid(piece)
4216 : *pieceToOutline(piece),
4217 dest, wbPieceGC, 0, 0,
4218 squareSize, squareSize, x, y);
4223 static void monoDrawPiece(piece, square_color, x, y, dest)
4225 int square_color, x, y;
4228 switch (square_color) {
4230 case 2: /* neutral */
4232 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4233 ? *pieceToOutline(piece)
4234 : *pieceToSolid(piece),
4235 dest, bwPieceGC, 0, 0,
4236 squareSize, squareSize, x, y, 1);
4239 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4240 ? *pieceToSolid(piece)
4241 : *pieceToOutline(piece),
4242 dest, wbPieceGC, 0, 0,
4243 squareSize, squareSize, x, y, 1);
4248 static void colorDrawPiece(piece, square_color, x, y, dest)
4250 int square_color, x, y;
4253 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4254 switch (square_color) {
4256 XCopyPlane(xDisplay, *pieceToSolid(piece),
4257 dest, (int) piece < (int) BlackPawn
4258 ? wlPieceGC : blPieceGC, 0, 0,
4259 squareSize, squareSize, x, y, 1);
4262 XCopyPlane(xDisplay, *pieceToSolid(piece),
4263 dest, (int) piece < (int) BlackPawn
4264 ? wdPieceGC : bdPieceGC, 0, 0,
4265 squareSize, squareSize, x, y, 1);
4267 case 2: /* neutral */
4269 XCopyPlane(xDisplay, *pieceToSolid(piece),
4270 dest, (int) piece < (int) BlackPawn
4271 ? wjPieceGC : bjPieceGC, 0, 0,
4272 squareSize, squareSize, x, y, 1);
4277 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4279 int square_color, x, y;
4282 int kind, p = piece;
4284 switch (square_color) {
4286 case 2: /* neutral */
4288 if ((int)piece < (int) BlackPawn) {
4296 if ((int)piece < (int) BlackPawn) {
4304 if(appData.upsideDown && flipView) { kind ^= 2; p += p < BlackPawn ? BlackPawn : -BlackPawn; }// swap white and black pieces
4305 if(useTexture & square_color+1) {
4306 BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
4307 XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
4308 XSetClipOrigin(xDisplay, wlPieceGC, x, y);
4309 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);
4310 XSetClipMask(xDisplay, wlPieceGC, None);
4311 XSetClipOrigin(xDisplay, wlPieceGC, 0, 0);
4313 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4314 dest, wlPieceGC, 0, 0,
4315 squareSize, squareSize, x, y);
4318 typedef void (*DrawFunc)();
4320 DrawFunc ChooseDrawFunc()
4322 if (appData.monoMode) {
4323 if (DefaultDepth(xDisplay, xScreen) == 1) {
4324 return monoDrawPiece_1bit;
4326 return monoDrawPiece;
4330 return colorDrawPieceImage;
4332 return colorDrawPiece;
4336 /* [HR] determine square color depending on chess variant. */
4337 static int SquareColor(row, column)
4342 if (gameInfo.variant == VariantXiangqi) {
4343 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4345 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4347 } else if (row <= 4) {
4353 square_color = ((column + row) % 2) == 1;
4356 /* [hgm] holdings: next line makes all holdings squares light */
4357 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4359 return square_color;
4362 void DrawSquare(row, column, piece, do_flash)
4363 int row, column, do_flash;
4366 int square_color, x, y, direction, font_ascent, font_descent;
4369 XCharStruct overall;
4373 /* Calculate delay in milliseconds (2-delays per complete flash) */
4374 flash_delay = 500 / appData.flashRate;
4377 x = lineGap + ((BOARD_WIDTH-1)-column) *
4378 (squareSize + lineGap);
4379 y = lineGap + row * (squareSize + lineGap);
4381 x = lineGap + column * (squareSize + lineGap);
4382 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4383 (squareSize + lineGap);
4386 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4388 square_color = SquareColor(row, column);
4390 if ( // [HGM] holdings: blank out area between board and holdings
4391 column == BOARD_LEFT-1 || column == BOARD_RGHT
4392 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4393 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4394 BlankSquare(x, y, 2, EmptySquare, xBoardWindow, 1);
4396 // [HGM] print piece counts next to holdings
4397 string[1] = NULLCHAR;
4398 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4399 string[0] = '0' + piece;
4400 XTextExtents(countFontStruct, string, 1, &direction,
4401 &font_ascent, &font_descent, &overall);
4402 if (appData.monoMode) {
4403 XDrawImageString(xDisplay, xBoardWindow, countGC,
4404 x + squareSize - overall.width - 2,
4405 y + font_ascent + 1, string, 1);
4407 XDrawString(xDisplay, xBoardWindow, countGC,
4408 x + squareSize - overall.width - 2,
4409 y + font_ascent + 1, string, 1);
4412 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4413 string[0] = '0' + piece;
4414 XTextExtents(countFontStruct, string, 1, &direction,
4415 &font_ascent, &font_descent, &overall);
4416 if (appData.monoMode) {
4417 XDrawImageString(xDisplay, xBoardWindow, countGC,
4418 x + 2, y + font_ascent + 1, string, 1);
4420 XDrawString(xDisplay, xBoardWindow, countGC,
4421 x + 2, y + font_ascent + 1, string, 1);
4425 if (piece == EmptySquare || appData.blindfold) {
4426 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4428 drawfunc = ChooseDrawFunc();
4430 if (do_flash && appData.flashCount > 0) {
4431 for (i=0; i<appData.flashCount; ++i) {
4432 drawfunc(piece, square_color, x, y, xBoardWindow);
4433 XSync(xDisplay, False);
4434 do_flash_delay(flash_delay);
4436 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4437 XSync(xDisplay, False);
4438 do_flash_delay(flash_delay);
4441 drawfunc(piece, square_color, x, y, xBoardWindow);
4445 string[1] = NULLCHAR;
4446 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4447 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4448 string[0] = 'a' + column - BOARD_LEFT;
4449 XTextExtents(coordFontStruct, string, 1, &direction,
4450 &font_ascent, &font_descent, &overall);
4451 if (appData.monoMode) {
4452 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4453 x + squareSize - overall.width - 2,
4454 y + squareSize - font_descent - 1, string, 1);
4456 XDrawString(xDisplay, xBoardWindow, coordGC,
4457 x + squareSize - overall.width - 2,
4458 y + squareSize - font_descent - 1, string, 1);
4461 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4462 string[0] = ONE + row;
4463 XTextExtents(coordFontStruct, string, 1, &direction,
4464 &font_ascent, &font_descent, &overall);
4465 if (appData.monoMode) {
4466 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4467 x + 2, y + font_ascent + 1, string, 1);
4469 XDrawString(xDisplay, xBoardWindow, coordGC,
4470 x + 2, y + font_ascent + 1, string, 1);
4473 if(!partnerUp && marker[row][column]) {
4474 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4475 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4480 /* Why is this needed on some versions of X? */
4481 void EventProc(widget, unused, event)
4486 if (!XtIsRealized(widget))
4489 switch (event->type) {
4491 if (event->xexpose.count > 0) return; /* no clipping is done */
4492 XDrawPosition(widget, True, NULL);
4493 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4494 flipView = !flipView; partnerUp = !partnerUp;
4495 XDrawPosition(widget, True, NULL);
4496 flipView = !flipView; partnerUp = !partnerUp;
4500 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
4507 void DrawPosition(fullRedraw, board)
4508 /*Boolean*/int fullRedraw;
4511 XDrawPosition(boardWidget, fullRedraw, board);
4514 /* Returns 1 if there are "too many" differences between b1 and b2
4515 (i.e. more than 1 move was made) */
4516 static int too_many_diffs(b1, b2)
4522 for (i=0; i<BOARD_HEIGHT; ++i) {
4523 for (j=0; j<BOARD_WIDTH; ++j) {
4524 if (b1[i][j] != b2[i][j]) {
4525 if (++c > 4) /* Castling causes 4 diffs */
4533 /* Matrix describing castling maneuvers */
4534 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4535 static int castling_matrix[4][5] = {
4536 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4537 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4538 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4539 { 7, 7, 4, 5, 6 } /* 0-0, black */
4542 /* Checks whether castling occurred. If it did, *rrow and *rcol
4543 are set to the destination (row,col) of the rook that moved.
4545 Returns 1 if castling occurred, 0 if not.
4547 Note: Only handles a max of 1 castling move, so be sure
4548 to call too_many_diffs() first.
4550 static int check_castle_draw(newb, oldb, rrow, rcol)
4557 /* For each type of castling... */
4558 for (i=0; i<4; ++i) {
4559 r = castling_matrix[i];
4561 /* Check the 4 squares involved in the castling move */
4563 for (j=1; j<=4; ++j) {
4564 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4571 /* All 4 changed, so it must be a castling move */
4580 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4581 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4583 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4586 void DrawSeekBackground( int left, int top, int right, int bottom )
4588 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4591 void DrawSeekText(char *buf, int x, int y)
4593 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4596 void DrawSeekDot(int x, int y, int colorNr)
4598 int square = colorNr & 0x80;
4601 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4603 XFillRectangle(xDisplay, xBoardWindow, color,
4604 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4606 XFillArc(xDisplay, xBoardWindow, color,
4607 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4610 static int damage[2][BOARD_RANKS][BOARD_FILES];
4613 * event handler for redrawing the board
4615 void XDrawPosition(w, repaint, board)
4617 /*Boolean*/int repaint;
4621 static int lastFlipView = 0;
4622 static int lastBoardValid[2] = {0, 0};
4623 static Board lastBoard[2];
4626 int nr = twoBoards*partnerUp;
4628 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4630 if (board == NULL) {
4631 if (!lastBoardValid[nr]) return;
4632 board = lastBoard[nr];
4634 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4635 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4636 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Flip View"),
4641 * It would be simpler to clear the window with XClearWindow()
4642 * but this causes a very distracting flicker.
4645 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4647 if ( lineGap && IsDrawArrowEnabled())
4648 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4649 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4651 /* If too much changes (begin observing new game, etc.), don't
4653 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4655 /* Special check for castling so we don't flash both the king
4656 and the rook (just flash the king). */
4658 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4659 /* Draw rook with NO flashing. King will be drawn flashing later */
4660 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4661 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4665 /* First pass -- Draw (newly) empty squares and repair damage.
4666 This prevents you from having a piece show up twice while it
4667 is flashing on its new square */
4668 for (i = 0; i < BOARD_HEIGHT; i++)
4669 for (j = 0; j < BOARD_WIDTH; j++)
4670 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4671 || damage[nr][i][j]) {
4672 DrawSquare(i, j, board[i][j], 0);
4673 damage[nr][i][j] = False;
4676 /* Second pass -- Draw piece(s) in new position and flash them */
4677 for (i = 0; i < BOARD_HEIGHT; i++)
4678 for (j = 0; j < BOARD_WIDTH; j++)
4679 if (board[i][j] != lastBoard[nr][i][j]) {
4680 DrawSquare(i, j, board[i][j], do_flash);
4684 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4685 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4686 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4688 for (i = 0; i < BOARD_HEIGHT; i++)
4689 for (j = 0; j < BOARD_WIDTH; j++) {
4690 DrawSquare(i, j, board[i][j], 0);
4691 damage[nr][i][j] = False;
4695 CopyBoard(lastBoard[nr], board);
4696 lastBoardValid[nr] = 1;
4697 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4698 lastFlipView = flipView;
4700 /* Draw highlights */
4701 if (pm1X >= 0 && pm1Y >= 0) {
4702 drawHighlight(pm1X, pm1Y, prelineGC);
4704 if (pm2X >= 0 && pm2Y >= 0) {
4705 drawHighlight(pm2X, pm2Y, prelineGC);
4707 if (hi1X >= 0 && hi1Y >= 0) {
4708 drawHighlight(hi1X, hi1Y, highlineGC);
4710 if (hi2X >= 0 && hi2Y >= 0) {
4711 drawHighlight(hi2X, hi2Y, highlineGC);
4713 DrawArrowHighlight(hi1X, hi1Y, hi2X, hi2Y);
4715 /* If piece being dragged around board, must redraw that too */
4718 XSync(xDisplay, False);
4723 * event handler for redrawing the board
4725 void DrawPositionProc(w, event, prms, nprms)
4731 XDrawPosition(w, True, NULL);
4736 * event handler for parsing user moves
4738 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4739 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4740 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4741 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4742 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4743 // and at the end FinishMove() to perform the move after optional promotion popups.
4744 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4745 void HandleUserMove(w, event, prms, nprms)
4751 if (w != boardWidget || errorExitStatus != -1) return;
4752 if(nprms) shiftKey = !strcmp(prms[0], "1");
4755 if (event->type == ButtonPress) {
4756 XtPopdown(promotionShell);
4757 XtDestroyWidget(promotionShell);
4758 promotionUp = False;
4766 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4767 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4768 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4771 void AnimateUserMove (Widget w, XEvent * event,
4772 String * params, Cardinal * nParams)
4774 DragPieceMove(event->xmotion.x, event->xmotion.y);
4777 void HandlePV (Widget w, XEvent * event,
4778 String * params, Cardinal * nParams)
4779 { // [HGM] pv: walk PV
4780 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4783 Widget CommentCreate(name, text, mutable, callback, lines)
4785 int /*Boolean*/ mutable;
4786 XtCallbackProc callback;
4790 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4795 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4796 XtGetValues(boardWidget, args, j);
4799 XtSetArg(args[j], XtNresizable, True); j++;
4802 XtCreatePopupShell(name, topLevelShellWidgetClass,
4803 shellWidget, args, j);
4806 XtCreatePopupShell(name, transientShellWidgetClass,
4807 shellWidget, args, j);
4810 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4811 layoutArgs, XtNumber(layoutArgs));
4813 XtCreateManagedWidget("form", formWidgetClass, layout,
4814 formArgs, XtNumber(formArgs));
4818 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4819 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4821 XtSetArg(args[j], XtNstring, text); j++;
4822 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4823 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4824 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4825 XtSetArg(args[j], XtNright, XtChainRight); j++;
4826 XtSetArg(args[j], XtNresizable, True); j++;
4827 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4828 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4829 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4830 XtSetArg(args[j], XtNautoFill, True); j++;
4831 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4833 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4834 XtOverrideTranslations(edit, XtParseTranslationTable(commentTranslations));
4838 XtSetArg(args[j], XtNfromVert, edit); j++;
4839 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4840 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4841 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4842 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4844 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4845 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4848 XtSetArg(args[j], XtNfromVert, edit); j++;
4849 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4850 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4851 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4852 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4853 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4855 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4856 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4859 XtSetArg(args[j], XtNfromVert, edit); j++;
4860 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4861 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4862 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4863 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4864 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4866 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4867 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4870 XtSetArg(args[j], XtNfromVert, edit); j++;
4871 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4872 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4873 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4874 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4876 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4877 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4880 XtSetArg(args[j], XtNfromVert, edit); j++;
4881 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4882 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4883 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4884 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4885 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4887 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4888 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4891 XtRealizeWidget(shell);
4893 if (commentX == -1) {
4896 Dimension pw_height;
4897 Dimension ew_height;
4900 XtSetArg(args[j], XtNheight, &ew_height); j++;
4901 XtGetValues(edit, args, j);
4904 XtSetArg(args[j], XtNheight, &pw_height); j++;
4905 XtGetValues(shell, args, j);
4906 commentH = pw_height + (lines - 1) * ew_height;
4907 commentW = bw_width - 16;
4909 XSync(xDisplay, False);
4911 /* This code seems to tickle an X bug if it is executed too soon
4912 after xboard starts up. The coordinates get transformed as if
4913 the main window was positioned at (0, 0).
4915 XtTranslateCoords(shellWidget,
4916 (bw_width - commentW) / 2, 0 - commentH / 2,
4917 &commentX, &commentY);
4919 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4920 RootWindowOfScreen(XtScreen(shellWidget)),
4921 (bw_width - commentW) / 2, 0 - commentH / 2,
4926 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4929 if(wpComment.width > 0) {
4930 commentX = wpComment.x;
4931 commentY = wpComment.y;
4932 commentW = wpComment.width;
4933 commentH = wpComment.height;
4937 XtSetArg(args[j], XtNheight, commentH); j++;
4938 XtSetArg(args[j], XtNwidth, commentW); j++;
4939 XtSetArg(args[j], XtNx, commentX); j++;
4940 XtSetArg(args[j], XtNy, commentY); j++;
4941 XtSetValues(shell, args, j);
4942 XtSetKeyboardFocus(shell, edit);
4947 static int savedIndex; /* gross that this is global */
4949 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
4952 XawTextPosition index, dummy;
4955 XawTextGetSelectionPos(w, &index, &dummy);
4956 XtSetArg(arg, XtNstring, &val);
4957 XtGetValues(w, &arg, 1);
4958 ReplaceComment(savedIndex, val);
4959 if(savedIndex != currentMove) ToNrEvent(savedIndex);
4960 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
4963 void EditCommentPopUp(index, title, text)
4972 if (text == NULL) text = "";
4974 if (editShell == NULL) {
4976 CommentCreate(title, text, True, EditCommentCallback, 4);
4977 XtRealizeWidget(editShell);
4978 CatchDeleteWindow(editShell, "EditCommentPopDown");
4980 edit = XtNameToWidget(editShell, "*form.text");
4982 XtSetArg(args[j], XtNstring, text); j++;
4983 XtSetValues(edit, args, j);
4985 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4986 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4987 XtSetValues(editShell, args, j);
4990 XtPopup(editShell, XtGrabNone);
4994 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4995 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"),
4997 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"),
5001 void EditCommentCallback(w, client_data, call_data)
5003 XtPointer client_data, call_data;
5011 XtSetArg(args[j], XtNlabel, &name); j++;
5012 XtGetValues(w, args, j);
5014 if (strcmp(name, _("ok")) == 0) {
5015 edit = XtNameToWidget(editShell, "*form.text");
5017 XtSetArg(args[j], XtNstring, &val); j++;
5018 XtGetValues(edit, args, j);
5019 ReplaceComment(savedIndex, val);
5020 EditCommentPopDown();
5021 } else if (strcmp(name, _("cancel")) == 0) {
5022 EditCommentPopDown();
5023 } else if (strcmp(name, _("clear")) == 0) {
5024 edit = XtNameToWidget(editShell, "*form.text");
5025 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5026 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5030 void EditCommentPopDown()
5035 if (!editUp) return;
5037 XtSetArg(args[j], XtNx, &commentX); j++;
5038 XtSetArg(args[j], XtNy, &commentY); j++;
5039 XtSetArg(args[j], XtNheight, &commentH); j++;
5040 XtSetArg(args[j], XtNwidth, &commentW); j++;
5041 XtGetValues(editShell, args, j);
5042 XtPopdown(editShell);
5045 XtSetArg(args[j], XtNleftBitmap, None); j++;
5046 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"),
5048 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"),
5052 void ICSInputBoxPopUp()
5057 extern Option boxOptions[];
5059 void ICSInputSendText()
5066 edit = boxOptions[0].handle;
5068 XtSetArg(args[j], XtNstring, &val); j++;
5069 XtGetValues(edit, args, j);
5071 SendMultiLineToICS(val);
5072 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5073 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5076 void ICSInputBoxPopDown()
5081 void CommentPopUp(title, text)
5088 savedIndex = currentMove; // [HGM] vari
5089 if (commentShell == NULL) {
5091 CommentCreate(title, text, False, CommentCallback, 4);
5092 XtRealizeWidget(commentShell);
5093 CatchDeleteWindow(commentShell, "CommentPopDown");
5095 edit = XtNameToWidget(commentShell, "*form.text");
5097 XtSetArg(args[j], XtNstring, text); j++;
5098 XtSetValues(edit, args, j);
5100 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5101 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5102 XtSetValues(commentShell, args, j);
5105 XtPopup(commentShell, XtGrabNone);
5106 XSync(xDisplay, False);
5111 void CommentCallback(w, client_data, call_data)
5113 XtPointer client_data, call_data;
5120 XtSetArg(args[j], XtNlabel, &name); j++;
5121 XtGetValues(w, args, j);
5123 if (strcmp(name, _("close")) == 0) {
5125 } else if (strcmp(name, _("edit")) == 0) {
5132 void CommentPopDown()
5137 if (!commentUp) return;
5139 XtSetArg(args[j], XtNx, &commentX); j++;
5140 XtSetArg(args[j], XtNy, &commentY); j++;
5141 XtSetArg(args[j], XtNwidth, &commentW); j++;
5142 XtSetArg(args[j], XtNheight, &commentH); j++;
5143 XtGetValues(commentShell, args, j);
5144 XtPopdown(commentShell);
5145 XSync(xDisplay, False);
5149 void FileNamePopUp(label, def, filter, proc, openMode)
5156 fileProc = proc; /* I can't see a way not */
5157 fileOpenMode = openMode; /* to use globals here */
5158 { // [HGM] use file-selector dialog stolen from Ghostview
5160 int index; // this is not supported yet
5162 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5163 (def[0] ? def : NULL), filter, openMode, NULL, &name))
5164 (void) (*fileProc)(f, index=0, name);
5168 void FileNamePopDown()
5170 if (!filenameUp) return;
5171 XtPopdown(fileNameShell);
5172 XtDestroyWidget(fileNameShell);
5177 void FileNameCallback(w, client_data, call_data)
5179 XtPointer client_data, call_data;
5184 XtSetArg(args[0], XtNlabel, &name);
5185 XtGetValues(w, args, 1);
5187 if (strcmp(name, _("cancel")) == 0) {
5192 FileNameAction(w, NULL, NULL, NULL);
5195 void FileNameAction(w, event, prms, nprms)
5207 name = XawDialogGetValueString(w = XtParent(w));
5209 if ((name != NULL) && (*name != NULLCHAR)) {
5210 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
5211 XtPopdown(w = XtParent(XtParent(w)));
5215 p = strrchr(buf, ' ');
5222 fullname = ExpandPathName(buf);
5224 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5227 f = fopen(fullname, fileOpenMode);
5229 DisplayError(_("Failed to open file"), errno);
5231 (void) (*fileProc)(f, index, buf);
5238 XtPopdown(w = XtParent(XtParent(w)));
5244 void PromotionPopUp()
5247 Widget dialog, layout;
5249 Dimension bw_width, pw_width;
5253 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5254 XtGetValues(boardWidget, args, j);
5257 XtSetArg(args[j], XtNresizable, True); j++;
5258 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5260 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5261 shellWidget, args, j);
5263 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5264 layoutArgs, XtNumber(layoutArgs));
5267 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5268 XtSetArg(args[j], XtNborderWidth, 0); j++;
5269 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5272 if(gameInfo.variant != VariantShogi) {
5273 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) {
5274 XawDialogAddButton(dialog, _("Warlord"), PromotionCallback,
5275 (XtPointer) dialog);
5276 XawDialogAddButton(dialog, _("General"), PromotionCallback,
5277 (XtPointer) dialog);
5278 XawDialogAddButton(dialog, _("Lieutenant"), PromotionCallback,
5279 (XtPointer) dialog);
5280 XawDialogAddButton(dialog, _("Captain"), PromotionCallback,
5281 (XtPointer) dialog);
5283 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5284 (XtPointer) dialog);
5285 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5286 (XtPointer) dialog);
5287 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5288 (XtPointer) dialog);
5289 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5290 (XtPointer) dialog);
5292 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5293 gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
\r
5294 gameInfo.variant == VariantGiveaway) {
5295 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5296 (XtPointer) dialog);
5298 if(gameInfo.variant == VariantCapablanca ||
5299 gameInfo.variant == VariantGothic ||
5300 gameInfo.variant == VariantCapaRandom) {
5301 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5302 (XtPointer) dialog);
5303 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5304 (XtPointer) dialog);
5306 } else // [HGM] shogi
5308 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5309 (XtPointer) dialog);
5310 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5311 (XtPointer) dialog);
5313 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5314 (XtPointer) dialog);
5316 XtRealizeWidget(promotionShell);
5317 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5320 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5321 XtGetValues(promotionShell, args, j);
5323 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5324 lineGap + squareSize/3 +
5325 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5326 0 : 6*(squareSize + lineGap)), &x, &y);
5329 XtSetArg(args[j], XtNx, x); j++;
5330 XtSetArg(args[j], XtNy, y); j++;
5331 XtSetValues(promotionShell, args, j);
5333 XtPopup(promotionShell, XtGrabNone);
5338 void PromotionPopDown()
5340 if (!promotionUp) return;
5341 XtPopdown(promotionShell);
5342 XtDestroyWidget(promotionShell);
5343 promotionUp = False;
5346 void PromotionCallback(w, client_data, call_data)
5348 XtPointer client_data, call_data;
5354 XtSetArg(args[0], XtNlabel, &name);
5355 XtGetValues(w, args, 1);
5359 if (fromX == -1) return;
5361 if (strcmp(name, _("cancel")) == 0) {
5365 } else if (strcmp(name, _("Knight")) == 0) {
5367 } else if (strcmp(name, _("Promote")) == 0) {
5369 } else if (strcmp(name, _("Defer")) == 0) {
5372 promoChar = ToLower(name[0]);
5375 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5377 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5378 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5383 void ErrorCallback(w, client_data, call_data)
5385 XtPointer client_data, call_data;
5388 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5390 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5396 if (!errorUp) return;
5398 XtPopdown(errorShell);
5399 XtDestroyWidget(errorShell);
5400 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5403 void ErrorPopUp(title, label, modal)
5404 char *title, *label;
5408 Widget dialog, layout;
5412 Dimension bw_width, pw_width;
5413 Dimension pw_height;
5417 XtSetArg(args[i], XtNresizable, True); i++;
5418 XtSetArg(args[i], XtNtitle, title); i++;
5420 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5421 shellWidget, args, i);
5423 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5424 layoutArgs, XtNumber(layoutArgs));
5427 XtSetArg(args[i], XtNlabel, label); i++;
5428 XtSetArg(args[i], XtNborderWidth, 0); i++;
5429 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5432 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5434 XtRealizeWidget(errorShell);
5435 CatchDeleteWindow(errorShell, "ErrorPopDown");
5438 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5439 XtGetValues(boardWidget, args, i);
5441 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5442 XtSetArg(args[i], XtNheight, &pw_height); i++;
5443 XtGetValues(errorShell, args, i);
5446 /* This code seems to tickle an X bug if it is executed too soon
5447 after xboard starts up. The coordinates get transformed as if
5448 the main window was positioned at (0, 0).
5450 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5451 0 - pw_height + squareSize / 3, &x, &y);
5453 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5454 RootWindowOfScreen(XtScreen(boardWidget)),
5455 (bw_width - pw_width) / 2,
5456 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5460 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5463 XtSetArg(args[i], XtNx, x); i++;
5464 XtSetArg(args[i], XtNy, y); i++;
5465 XtSetValues(errorShell, args, i);
5468 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5471 /* Disable all user input other than deleting the window */
5472 static int frozen = 0;
5476 /* Grab by a widget that doesn't accept input */
5477 XtAddGrab(messageWidget, TRUE, FALSE);
5481 /* Undo a FreezeUI */
5484 if (!frozen) return;
5485 XtRemoveGrab(messageWidget);
5489 char *ModeToWidgetName(mode)
5493 case BeginningOfGame:
5494 if (appData.icsActive)
5495 return "menuMode.ICS Client";
5496 else if (appData.noChessProgram ||
5497 *appData.cmailGameName != NULLCHAR)
5498 return "menuMode.Edit Game";
5500 return "menuMode.Machine Black";
5501 case MachinePlaysBlack:
5502 return "menuMode.Machine Black";
5503 case MachinePlaysWhite:
5504 return "menuMode.Machine White";
5506 return "menuMode.Analysis Mode";
5508 return "menuMode.Analyze File";
5509 case TwoMachinesPlay:
5510 return "menuMode.Two Machines";
5512 return "menuMode.Edit Game";
5513 case PlayFromGameFile:
5514 return "menuFile.Load Game";
5516 return "menuMode.Edit Position";
5518 return "menuMode.Training";
5519 case IcsPlayingWhite:
5520 case IcsPlayingBlack:
5524 return "menuMode.ICS Client";
5531 void ModeHighlight()
5534 static int oldPausing = FALSE;
5535 static GameMode oldmode = (GameMode) -1;
5538 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5540 if (pausing != oldPausing) {
5541 oldPausing = pausing;
5543 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5545 XtSetArg(args[0], XtNleftBitmap, None);
5547 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5550 if (appData.showButtonBar) {
5551 /* Always toggle, don't set. Previous code messes up when
5552 invoked while the button is pressed, as releasing it
5553 toggles the state again. */
5556 XtSetArg(args[0], XtNbackground, &oldbg);
5557 XtSetArg(args[1], XtNforeground, &oldfg);
5558 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5560 XtSetArg(args[0], XtNbackground, oldfg);
5561 XtSetArg(args[1], XtNforeground, oldbg);
5563 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5567 wname = ModeToWidgetName(oldmode);
5568 if (wname != NULL) {
5569 XtSetArg(args[0], XtNleftBitmap, None);
5570 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5572 wname = ModeToWidgetName(gameMode);
5573 if (wname != NULL) {
5574 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5575 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5579 /* Maybe all the enables should be handled here, not just this one */
5580 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5581 gameMode == Training || gameMode == PlayFromGameFile);
5586 * Button/menu procedures
5588 void ResetProc(w, event, prms, nprms)
5597 int LoadGamePopUp(f, gameNumber, title)
5602 cmailMsgLoaded = FALSE;
5603 if (gameNumber == 0) {
5604 int error = GameListBuild(f);
5606 DisplayError(_("Cannot build game list"), error);
5607 } else if (!ListEmpty(&gameList) &&
5608 ((ListGame *) gameList.tailPred)->number > 1) {
5609 GameListPopUp(f, title);
5615 return LoadGame(f, gameNumber, title, FALSE);
5618 void LoadGameProc(w, event, prms, nprms)
5624 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5627 FileNamePopUp(_("Load game file name?"), "", ".pgn .game", LoadGamePopUp, "rb");
5630 void LoadNextGameProc(w, event, prms, nprms)
5639 void LoadPrevGameProc(w, event, prms, nprms)
5648 void ReloadGameProc(w, event, prms, nprms)
5657 void LoadNextPositionProc(w, event, prms, nprms)
5666 void LoadPrevPositionProc(w, event, prms, nprms)
5675 void ReloadPositionProc(w, event, prms, nprms)
5684 void LoadPositionProc(w, event, prms, nprms)
5690 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5693 FileNamePopUp(_("Load position file name?"), "", ".fen .epd .pos", LoadPosition, "rb");
5696 void SaveGameProc(w, event, prms, nprms)
5702 FileNamePopUp(_("Save game file name?"),
5703 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5704 appData.oldSaveStyle ? ".game" : ".pgn",
5708 void SavePositionProc(w, event, prms, nprms)
5714 FileNamePopUp(_("Save position file name?"),
5715 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5716 appData.oldSaveStyle ? ".pos" : ".fen",
5720 void ReloadCmailMsgProc(w, event, prms, nprms)
5726 ReloadCmailMsgEvent(FALSE);
5729 void MailMoveProc(w, event, prms, nprms)
5738 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5739 char *selected_fen_position=NULL;
5742 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5743 Atom *type_return, XtPointer *value_return,
5744 unsigned long *length_return, int *format_return)
5746 char *selection_tmp;
5748 if (!selected_fen_position) return False; /* should never happen */
5749 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5750 /* note: since no XtSelectionDoneProc was registered, Xt will
5751 * automatically call XtFree on the value returned. So have to
5752 * make a copy of it allocated with XtMalloc */
5753 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5754 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
5756 *value_return=selection_tmp;
5757 *length_return=strlen(selection_tmp);
5758 *type_return=*target;
5759 *format_return = 8; /* bits per byte */
5761 } else if (*target == XA_TARGETS(xDisplay)) {
5762 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5763 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5764 targets_tmp[1] = XA_STRING;
5765 *value_return = targets_tmp;
5766 *type_return = XA_ATOM;
5768 *format_return = 8 * sizeof(Atom);
5769 if (*format_return > 32) {
5770 *length_return *= *format_return / 32;
5771 *format_return = 32;
5779 /* note: when called from menu all parameters are NULL, so no clue what the
5780 * Widget which was clicked on was, or what the click event was
5782 void CopyPositionProc(w, event, prms, nprms)
5789 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5790 * have a notion of a position that is selected but not copied.
5791 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5793 if(gameMode == EditPosition) EditPositionDone(TRUE);
5794 if (selected_fen_position) free(selected_fen_position);
5795 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5796 if (!selected_fen_position) return;
5797 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5799 SendPositionSelection,
5800 NULL/* lose_ownership_proc */ ,
5801 NULL/* transfer_done_proc */);
5802 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5804 SendPositionSelection,
5805 NULL/* lose_ownership_proc */ ,
5806 NULL/* transfer_done_proc */);
5809 /* function called when the data to Paste is ready */
5811 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5812 Atom *type, XtPointer value, unsigned long *len, int *format)
5815 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5816 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5817 EditPositionPasteFEN(fenstr);
5821 /* called when Paste Position button is pressed,
5822 * all parameters will be NULL */
5823 void PastePositionProc(w, event, prms, nprms)
5829 XtGetSelectionValue(menuBarWidget,
5830 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5831 /* (XtSelectionCallbackProc) */ PastePositionCB,
5832 NULL, /* client_data passed to PastePositionCB */
5834 /* better to use the time field from the event that triggered the
5835 * call to this function, but that isn't trivial to get
5843 SendGameSelection(Widget w, Atom *selection, Atom *target,
5844 Atom *type_return, XtPointer *value_return,
5845 unsigned long *length_return, int *format_return)
5847 char *selection_tmp;
5849 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5850 FILE* f = fopen(gameCopyFilename, "r");
5853 if (f == NULL) return False;
5857 selection_tmp = XtMalloc(len + 1);
5858 count = fread(selection_tmp, 1, len, f);
5861 XtFree(selection_tmp);
5864 selection_tmp[len] = NULLCHAR;
5865 *value_return = selection_tmp;
5866 *length_return = len;
5867 *type_return = *target;
5868 *format_return = 8; /* bits per byte */
5870 } else if (*target == XA_TARGETS(xDisplay)) {
5871 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5872 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5873 targets_tmp[1] = XA_STRING;
5874 *value_return = targets_tmp;
5875 *type_return = XA_ATOM;
5877 *format_return = 8 * sizeof(Atom);
5878 if (*format_return > 32) {
5879 *length_return *= *format_return / 32;
5880 *format_return = 32;
5888 /* note: when called from menu all parameters are NULL, so no clue what the
5889 * Widget which was clicked on was, or what the click event was
5891 void CopyGameProc(w, event, prms, nprms)
5899 ret = SaveGameToFile(gameCopyFilename, FALSE);
5903 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5904 * have a notion of a game that is selected but not copied.
5905 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5907 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5910 NULL/* lose_ownership_proc */ ,
5911 NULL/* transfer_done_proc */);
5912 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5915 NULL/* lose_ownership_proc */ ,
5916 NULL/* transfer_done_proc */);
5919 /* function called when the data to Paste is ready */
5921 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5922 Atom *type, XtPointer value, unsigned long *len, int *format)
5925 if (value == NULL || *len == 0) {
5926 return; /* nothing had been selected to copy */
5928 f = fopen(gamePasteFilename, "w");
5930 DisplayError(_("Can't open temp file"), errno);
5933 fwrite(value, 1, *len, f);
5936 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5939 /* called when Paste Game button is pressed,
5940 * all parameters will be NULL */
5941 void PasteGameProc(w, event, prms, nprms)
5947 XtGetSelectionValue(menuBarWidget,
5948 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5949 /* (XtSelectionCallbackProc) */ PasteGameCB,
5950 NULL, /* client_data passed to PasteGameCB */
5952 /* better to use the time field from the event that triggered the
5953 * call to this function, but that isn't trivial to get
5963 SaveGameProc(NULL, NULL, NULL, NULL);
5967 void QuitProc(w, event, prms, nprms)
5976 void PauseProc(w, event, prms, nprms)
5986 void MachineBlackProc(w, event, prms, nprms)
5992 MachineBlackEvent();
5995 void MachineWhiteProc(w, event, prms, nprms)
6001 MachineWhiteEvent();
6004 void AnalyzeModeProc(w, event, prms, nprms)
6012 if (!first.analysisSupport) {
6013 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6014 DisplayError(buf, 0);
6017 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
6018 if (appData.icsActive) {
6019 if (gameMode != IcsObserving) {
6020 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
6021 DisplayError(buf, 0);
6023 if (appData.icsEngineAnalyze) {
6024 if (appData.debugMode)
6025 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
6031 /* if enable, use want disable icsEngineAnalyze */
6032 if (appData.icsEngineAnalyze) {
6037 appData.icsEngineAnalyze = TRUE;
6038 if (appData.debugMode)
6039 fprintf(debugFP, _("ICS engine analyze starting... \n"));
6041 #ifndef OPTIONSDIALOG
6042 if (!appData.showThinking)
6043 ShowThinkingProc(w,event,prms,nprms);
6049 void AnalyzeFileProc(w, event, prms, nprms)
6055 if (!first.analysisSupport) {
6057 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6058 DisplayError(buf, 0);
6062 #ifndef OPTIONSDIALOG
6063 if (!appData.showThinking)
6064 ShowThinkingProc(w,event,prms,nprms);
6067 FileNamePopUp(_("File to analyze"), "", ".pgn .game", LoadGamePopUp, "rb");
6068 AnalysisPeriodicEvent(1);
6071 void TwoMachinesProc(w, event, prms, nprms)
6080 void MatchProc(w, event, prms, nprms)
6086 if(gameMode != BeginningOfGame) { DisplayError(_("You can only start a match from the initial position."), 0); return; }
6087 matchMode = 2; // This is back-end, really
\r
6088 appData.matchGames = appData.defaultMatchGames;
\r
6090 first.matchWins = second.matchWins = 0;
\r
6094 void IcsClientProc(w, event, prms, nprms)
6103 void EditGameProc(w, event, prms, nprms)
6112 void EditPositionProc(w, event, prms, nprms)
6118 EditPositionEvent();
6121 void TrainingProc(w, event, prms, nprms)
6130 void EditCommentProc(w, event, prms, nprms)
6137 EditCommentPopDown();
6143 void IcsInputBoxProc(w, event, prms, nprms)
6149 if (!PopDown(4)) ICSInputBoxPopUp();
6152 void AcceptProc(w, event, prms, nprms)
6161 void DeclineProc(w, event, prms, nprms)
6170 void RematchProc(w, event, prms, nprms)
6179 void CallFlagProc(w, event, prms, nprms)
6188 void DrawProc(w, event, prms, nprms)
6197 void AbortProc(w, event, prms, nprms)
6206 void AdjournProc(w, event, prms, nprms)
6215 void ResignProc(w, event, prms, nprms)
6224 void AdjuWhiteProc(w, event, prms, nprms)
6230 UserAdjudicationEvent(+1);
6233 void AdjuBlackProc(w, event, prms, nprms)
6239 UserAdjudicationEvent(-1);
6242 void AdjuDrawProc(w, event, prms, nprms)
6248 UserAdjudicationEvent(0);
6251 void EnterKeyProc(w, event, prms, nprms)
6257 if (shellUp[4] == True)
6261 void UpKeyProc(w, event, prms, nprms)
6266 { // [HGM] input: let up-arrow recall previous line from history
6273 if (!shellUp[4]) return;
6274 edit = boxOptions[0].handle;
6276 XtSetArg(args[j], XtNstring, &val); j++;
6277 XtGetValues(edit, args, j);
6278 val = PrevInHistory(val);
6279 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6280 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6282 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6283 XawTextReplace(edit, 0, 0, &t);
6284 XawTextSetInsertionPoint(edit, 9999);
6288 void DownKeyProc(w, event, prms, nprms)
6293 { // [HGM] input: let down-arrow recall next line from history
6298 if (!shellUp[4]) return;
6299 edit = boxOptions[0].handle;
6300 val = NextInHistory();
6301 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6302 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6304 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6305 XawTextReplace(edit, 0, 0, &t);
6306 XawTextSetInsertionPoint(edit, 9999);
6310 void StopObservingProc(w, event, prms, nprms)
6316 StopObservingEvent();
6319 void StopExaminingProc(w, event, prms, nprms)
6325 StopExaminingEvent();
6328 void UploadProc(w, event, prms, nprms)
6338 void ForwardProc(w, event, prms, nprms)
6348 void BackwardProc(w, event, prms, nprms)
6357 void ToStartProc(w, event, prms, nprms)
6366 void ToEndProc(w, event, prms, nprms)
6375 void RevertProc(w, event, prms, nprms)
6384 void AnnotateProc(w, event, prms, nprms)
6393 void TruncateGameProc(w, event, prms, nprms)
6399 TruncateGameEvent();
6401 void RetractMoveProc(w, event, prms, nprms)
6410 void MoveNowProc(w, event, prms, nprms)
6419 void FlipViewProc(w, event, prms, nprms)
6425 flipView = !flipView;
6426 DrawPosition(True, NULL);
6429 void PonderNextMoveProc(w, event, prms, nprms)
6437 PonderNextMoveEvent(!appData.ponderNextMove);
6438 #ifndef OPTIONSDIALOG
6439 if (appData.ponderNextMove) {
6440 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6442 XtSetArg(args[0], XtNleftBitmap, None);
6444 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6449 #ifndef OPTIONSDIALOG
6450 void AlwaysQueenProc(w, event, prms, nprms)
6458 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6460 if (appData.alwaysPromoteToQueen) {
6461 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6463 XtSetArg(args[0], XtNleftBitmap, None);
6465 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6469 void AnimateDraggingProc(w, event, prms, nprms)
6477 appData.animateDragging = !appData.animateDragging;
6479 if (appData.animateDragging) {
6480 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6483 XtSetArg(args[0], XtNleftBitmap, None);
6485 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6489 void AnimateMovingProc(w, event, prms, nprms)
6497 appData.animate = !appData.animate;
6499 if (appData.animate) {
6500 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6503 XtSetArg(args[0], XtNleftBitmap, None);
6505 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6509 void AutoflagProc(w, event, prms, nprms)
6517 appData.autoCallFlag = !appData.autoCallFlag;
6519 if (appData.autoCallFlag) {
6520 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6522 XtSetArg(args[0], XtNleftBitmap, None);
6524 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6528 void AutoflipProc(w, event, prms, nprms)
6536 appData.autoFlipView = !appData.autoFlipView;
6538 if (appData.autoFlipView) {
6539 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6541 XtSetArg(args[0], XtNleftBitmap, None);
6543 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6547 void BlindfoldProc(w, event, prms, nprms)
6555 appData.blindfold = !appData.blindfold;
6557 if (appData.blindfold) {
6558 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6560 XtSetArg(args[0], XtNleftBitmap, None);
6562 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6565 DrawPosition(True, NULL);
6568 void TestLegalityProc(w, event, prms, nprms)
6576 appData.testLegality = !appData.testLegality;
6578 if (appData.testLegality) {
6579 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6581 XtSetArg(args[0], XtNleftBitmap, None);
6583 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6588 void FlashMovesProc(w, event, prms, nprms)
6596 if (appData.flashCount == 0) {
6597 appData.flashCount = 3;
6599 appData.flashCount = -appData.flashCount;
6602 if (appData.flashCount > 0) {
6603 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6605 XtSetArg(args[0], XtNleftBitmap, None);
6607 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6612 void HighlightDraggingProc(w, event, prms, nprms)
6620 appData.highlightDragging = !appData.highlightDragging;
6622 if (appData.highlightDragging) {
6623 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6625 XtSetArg(args[0], XtNleftBitmap, None);
6627 XtSetValues(XtNameToWidget(menuBarWidget,
6628 "menuOptions.Highlight Dragging"), args, 1);
6632 void HighlightLastMoveProc(w, event, prms, nprms)
6640 appData.highlightLastMove = !appData.highlightLastMove;
6642 if (appData.highlightLastMove) {
6643 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6645 XtSetArg(args[0], XtNleftBitmap, None);
6647 XtSetValues(XtNameToWidget(menuBarWidget,
6648 "menuOptions.Highlight Last Move"), args, 1);
6651 void HighlightArrowProc(w, event, prms, nprms)
6659 appData.highlightMoveWithArrow = !appData.highlightMoveWithArrow;
6661 if (appData.highlightMoveWithArrow) {
6662 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6664 XtSetArg(args[0], XtNleftBitmap, None);
6666 XtSetValues(XtNameToWidget(menuBarWidget,
6667 "menuOptions.Arrow"), args, 1);
6671 void IcsAlarmProc(w, event, prms, nprms)
6679 appData.icsAlarm = !appData.icsAlarm;
6681 if (appData.icsAlarm) {
6682 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6684 XtSetArg(args[0], XtNleftBitmap, None);
6686 XtSetValues(XtNameToWidget(menuBarWidget,
6687 "menuOptions.ICS Alarm"), args, 1);
6691 void MoveSoundProc(w, event, prms, nprms)
6699 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6701 if (appData.ringBellAfterMoves) {
6702 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6704 XtSetArg(args[0], XtNleftBitmap, None);
6706 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6710 void OneClickProc(w, event, prms, nprms)
6718 appData.oneClick = !appData.oneClick;
6720 if (appData.oneClick) {
6721 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6723 XtSetArg(args[0], XtNleftBitmap, None);
6725 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.OneClick"),
6729 void PeriodicUpdatesProc(w, event, prms, nprms)
6737 PeriodicUpdatesEvent(!appData.periodicUpdates);
6739 if (appData.periodicUpdates) {
6740 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6742 XtSetArg(args[0], XtNleftBitmap, None);
6744 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6748 void PopupExitMessageProc(w, event, prms, nprms)
6756 appData.popupExitMessage = !appData.popupExitMessage;
6758 if (appData.popupExitMessage) {
6759 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6761 XtSetArg(args[0], XtNleftBitmap, None);
6763 XtSetValues(XtNameToWidget(menuBarWidget,
6764 "menuOptions.Popup Exit Message"), args, 1);
6767 void PopupMoveErrorsProc(w, event, prms, nprms)
6775 appData.popupMoveErrors = !appData.popupMoveErrors;
6777 if (appData.popupMoveErrors) {
6778 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6780 XtSetArg(args[0], XtNleftBitmap, None);
6782 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6787 void PremoveProc(w, event, prms, nprms)
6795 appData.premove = !appData.premove;
6797 if (appData.premove) {
6798 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6800 XtSetArg(args[0], XtNleftBitmap, None);
6802 XtSetValues(XtNameToWidget(menuBarWidget,
6803 "menuOptions.Premove"), args, 1);
6807 void ShowCoordsProc(w, event, prms, nprms)
6815 appData.showCoords = !appData.showCoords;
6817 if (appData.showCoords) {
6818 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6820 XtSetArg(args[0], XtNleftBitmap, None);
6822 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6825 DrawPosition(True, NULL);
6828 void ShowThinkingProc(w, event, prms, nprms)
6834 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6835 ShowThinkingEvent();
6838 void HideThinkingProc(w, event, prms, nprms)
6846 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6847 ShowThinkingEvent();
6849 if (appData.hideThinkingFromHuman) {
6850 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6852 XtSetArg(args[0], XtNleftBitmap, None);
6854 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6859 void SaveOnExitProc(w, event, prms, nprms)
6867 saveSettingsOnExit = !saveSettingsOnExit;
6869 if (saveSettingsOnExit) {
6870 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6872 XtSetArg(args[0], XtNleftBitmap, None);
6874 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6878 void SaveSettingsProc(w, event, prms, nprms)
6884 SaveSettings(settingsFileName);
6887 void InfoProc(w, event, prms, nprms)
6894 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6899 void ManProc(w, event, prms, nprms)
6907 if (nprms && *nprms > 0)
6911 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6915 void HintProc(w, event, prms, nprms)
6924 void BookProc(w, event, prms, nprms)
6933 void AboutProc(w, event, prms, nprms)
6941 char *zippy = " (with Zippy code)";
6945 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6946 programVersion, zippy,
6947 "Copyright 1991 Digital Equipment Corporation",
6948 "Enhancements Copyright 1992-2009 Free Software Foundation",
6949 "Enhancements Copyright 2005 Alessandro Scotti",
6950 PACKAGE, " is free software and carries NO WARRANTY;",
6951 "see the file COPYING for more information.");
6952 ErrorPopUp(_("About XBoard"), buf, FALSE);
6955 void DebugProc(w, event, prms, nprms)
6961 appData.debugMode = !appData.debugMode;
6964 void AboutGameProc(w, event, prms, nprms)
6973 void NothingProc(w, event, prms, nprms)
6982 void Iconify(w, event, prms, nprms)
6991 XtSetArg(args[0], XtNiconic, True);
6992 XtSetValues(shellWidget, args, 1);
6995 void DisplayMessage(message, extMessage)
6996 char *message, *extMessage;
6998 /* display a message in the message widget */
7007 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
7012 message = extMessage;
7016 /* need to test if messageWidget already exists, since this function
7017 can also be called during the startup, if for example a Xresource
7018 is not set up correctly */
7021 XtSetArg(arg, XtNlabel, message);
7022 XtSetValues(messageWidget, &arg, 1);
7028 void DisplayTitle(text)
7033 char title[MSG_SIZ];
7036 if (text == NULL) text = "";
7038 if (appData.titleInWindow) {
7040 XtSetArg(args[i], XtNlabel, text); i++;
7041 XtSetValues(titleWidget, args, i);
7044 if (*text != NULLCHAR) {
7045 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
7046 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
7047 } else if (appData.icsActive) {
7048 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7049 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7050 } else if (appData.cmailGameName[0] != NULLCHAR) {
7051 snprintf(icon, sizeof(icon), "%s", "CMail");
7052 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7054 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7055 } else if (gameInfo.variant == VariantGothic) {
7056 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7057 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
7060 } else if (gameInfo.variant == VariantFalcon) {
7061 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7062 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
7064 } else if (appData.noChessProgram) {
7065 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7066 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
7068 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
7069 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7072 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7073 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7074 XtSetValues(shellWidget, args, i);
7079 DisplayError(message, error)
7086 if (appData.debugMode || appData.matchMode) {
7087 fprintf(stderr, "%s: %s\n", programName, message);
7090 if (appData.debugMode || appData.matchMode) {
7091 fprintf(stderr, "%s: %s: %s\n",
7092 programName, message, strerror(error));
7094 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7097 ErrorPopUp(_("Error"), message, FALSE);
7101 void DisplayMoveError(message)
7106 DrawPosition(FALSE, NULL);
7107 if (appData.debugMode || appData.matchMode) {
7108 fprintf(stderr, "%s: %s\n", programName, message);
7110 if (appData.popupMoveErrors) {
7111 ErrorPopUp(_("Error"), message, FALSE);
7113 DisplayMessage(message, "");
7118 void DisplayFatalError(message, error, status)
7124 errorExitStatus = status;
7126 fprintf(stderr, "%s: %s\n", programName, message);
7128 fprintf(stderr, "%s: %s: %s\n",
7129 programName, message, strerror(error));
7130 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7133 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7134 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7140 void DisplayInformation(message)
7144 ErrorPopUp(_("Information"), message, TRUE);
7147 void DisplayNote(message)
7151 ErrorPopUp(_("Note"), message, FALSE);
7155 NullXErrorCheck(dpy, error_event)
7157 XErrorEvent *error_event;
7162 void DisplayIcsInteractionTitle(message)
7165 if (oldICSInteractionTitle == NULL) {
7166 /* Magic to find the old window title, adapted from vim */
7167 char *wina = getenv("WINDOWID");
7169 Window win = (Window) atoi(wina);
7170 Window root, parent, *children;
7171 unsigned int nchildren;
7172 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7174 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7175 if (!XQueryTree(xDisplay, win, &root, &parent,
7176 &children, &nchildren)) break;
7177 if (children) XFree((void *)children);
7178 if (parent == root || parent == 0) break;
7181 XSetErrorHandler(oldHandler);
7183 if (oldICSInteractionTitle == NULL) {
7184 oldICSInteractionTitle = "xterm";
7187 printf("\033]0;%s\007", message);
7191 char pendingReplyPrefix[MSG_SIZ];
7192 ProcRef pendingReplyPR;
7194 void AskQuestionProc(w, event, prms, nprms)
7201 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7205 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7208 void AskQuestionPopDown()
7210 if (!askQuestionUp) return;
7211 XtPopdown(askQuestionShell);
7212 XtDestroyWidget(askQuestionShell);
7213 askQuestionUp = False;
7216 void AskQuestionReplyAction(w, event, prms, nprms)
7226 reply = XawDialogGetValueString(w = XtParent(w));
7227 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
7228 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
7229 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
7230 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
7231 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7232 AskQuestionPopDown();
7234 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7237 void AskQuestionCallback(w, client_data, call_data)
7239 XtPointer client_data, call_data;
7244 XtSetArg(args[0], XtNlabel, &name);
7245 XtGetValues(w, args, 1);
7247 if (strcmp(name, _("cancel")) == 0) {
7248 AskQuestionPopDown();
7250 AskQuestionReplyAction(w, NULL, NULL, NULL);
7254 void AskQuestion(title, question, replyPrefix, pr)
7255 char *title, *question, *replyPrefix;
7259 Widget popup, layout, dialog, edit;
7265 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
7266 pendingReplyPR = pr;
7269 XtSetArg(args[i], XtNresizable, True); i++;
7270 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7271 askQuestionShell = popup =
7272 XtCreatePopupShell(title, transientShellWidgetClass,
7273 shellWidget, args, i);
7276 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7277 layoutArgs, XtNumber(layoutArgs));
7280 XtSetArg(args[i], XtNlabel, question); i++;
7281 XtSetArg(args[i], XtNvalue, ""); i++;
7282 XtSetArg(args[i], XtNborderWidth, 0); i++;
7283 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7286 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7287 (XtPointer) dialog);
7288 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7289 (XtPointer) dialog);
7291 XtRealizeWidget(popup);
7292 CatchDeleteWindow(popup, "AskQuestionPopDown");
7294 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7295 &x, &y, &win_x, &win_y, &mask);
7297 XtSetArg(args[0], XtNx, x - 10);
7298 XtSetArg(args[1], XtNy, y - 30);
7299 XtSetValues(popup, args, 2);
7301 XtPopup(popup, XtGrabExclusive);
7302 askQuestionUp = True;
7304 edit = XtNameToWidget(dialog, "*value");
7305 XtSetKeyboardFocus(popup, edit);
7313 if (*name == NULLCHAR) {
7315 } else if (strcmp(name, "$") == 0) {
7316 putc(BELLCHAR, stderr);
7319 char *prefix = "", *sep = "";
7320 if(!strchr(name, '/')) { prefix = appData.soundDirectory; sep = "/"; }
7321 snprintf(buf, sizeof(buf), "%s '%s%s%s' &", appData.soundProgram, prefix, sep, name);
7329 PlaySound(appData.soundMove);
7335 PlaySound(appData.soundIcsWin);
7341 PlaySound(appData.soundIcsLoss);
7347 PlaySound(appData.soundIcsDraw);
7351 PlayIcsUnfinishedSound()
7353 PlaySound(appData.soundIcsUnfinished);
7359 PlaySound(appData.soundIcsAlarm);
7365 system("stty echo");
7371 system("stty -echo");
7375 Colorize(cc, continuation)
7380 int count, outCount, error;
7382 if (textColors[(int)cc].bg > 0) {
7383 if (textColors[(int)cc].fg > 0) {
7384 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7385 textColors[(int)cc].fg, textColors[(int)cc].bg);
7387 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7388 textColors[(int)cc].bg);
7391 if (textColors[(int)cc].fg > 0) {
7392 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7393 textColors[(int)cc].fg);
7395 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7398 count = strlen(buf);
7399 outCount = OutputToProcess(NoProc, buf, count, &error);
7400 if (outCount < count) {
7401 DisplayFatalError(_("Error writing to display"), error, 1);
7404 if (continuation) return;
7407 PlaySound(appData.soundShout);
7410 PlaySound(appData.soundSShout);
7413 PlaySound(appData.soundChannel1);
7416 PlaySound(appData.soundChannel);
7419 PlaySound(appData.soundKibitz);
7422 PlaySound(appData.soundTell);
7424 case ColorChallenge:
7425 PlaySound(appData.soundChallenge);
7428 PlaySound(appData.soundRequest);
7431 PlaySound(appData.soundSeek);
7442 return getpwuid(getuid())->pw_name;
7446 ExpandPathName(path)
7449 static char static_buf[4*MSG_SIZ];
7450 char *d, *s, buf[4*MSG_SIZ];
7456 while (*s && isspace(*s))
7465 if (*(s+1) == '/') {
7466 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7470 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7471 { char *p; if(p = strchr(buf, '/')) *p = 0; }
7472 pwd = getpwnam(buf);
7475 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7479 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7480 strcat(d, strchr(s+1, '/'));
7484 safeStrCpy(d, s, 4*MSG_SIZ );
7491 static char host_name[MSG_SIZ];
7493 #if HAVE_GETHOSTNAME
7494 gethostname(host_name, MSG_SIZ);
7496 #else /* not HAVE_GETHOSTNAME */
7497 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7498 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7500 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7502 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7503 #endif /* not HAVE_GETHOSTNAME */
7506 XtIntervalId delayedEventTimerXID = 0;
7507 DelayedEventCallback delayedEventCallback = 0;
7512 delayedEventTimerXID = 0;
7513 delayedEventCallback();
7517 ScheduleDelayedEvent(cb, millisec)
7518 DelayedEventCallback cb; long millisec;
7520 if(delayedEventTimerXID && delayedEventCallback == cb)
7521 // [HGM] alive: replace, rather than add or flush identical event
7522 XtRemoveTimeOut(delayedEventTimerXID);
7523 delayedEventCallback = cb;
7524 delayedEventTimerXID =
7525 XtAppAddTimeOut(appContext, millisec,
7526 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7529 DelayedEventCallback
7532 if (delayedEventTimerXID) {
7533 return delayedEventCallback;
7540 CancelDelayedEvent()
7542 if (delayedEventTimerXID) {
7543 XtRemoveTimeOut(delayedEventTimerXID);
7544 delayedEventTimerXID = 0;
7548 XtIntervalId loadGameTimerXID = 0;
7550 int LoadGameTimerRunning()
7552 return loadGameTimerXID != 0;
7555 int StopLoadGameTimer()
7557 if (loadGameTimerXID != 0) {
7558 XtRemoveTimeOut(loadGameTimerXID);
7559 loadGameTimerXID = 0;
7567 LoadGameTimerCallback(arg, id)
7571 loadGameTimerXID = 0;
7576 StartLoadGameTimer(millisec)
7580 XtAppAddTimeOut(appContext, millisec,
7581 (XtTimerCallbackProc) LoadGameTimerCallback,
7585 XtIntervalId analysisClockXID = 0;
7588 AnalysisClockCallback(arg, id)
7592 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7593 || appData.icsEngineAnalyze) { // [DM]
7594 AnalysisPeriodicEvent(0);
7595 StartAnalysisClock();
7600 StartAnalysisClock()
7603 XtAppAddTimeOut(appContext, 2000,
7604 (XtTimerCallbackProc) AnalysisClockCallback,
7608 XtIntervalId clockTimerXID = 0;
7610 int ClockTimerRunning()
7612 return clockTimerXID != 0;
7615 int StopClockTimer()
7617 if (clockTimerXID != 0) {
7618 XtRemoveTimeOut(clockTimerXID);
7627 ClockTimerCallback(arg, id)
7636 StartClockTimer(millisec)
7640 XtAppAddTimeOut(appContext, millisec,
7641 (XtTimerCallbackProc) ClockTimerCallback,
7646 DisplayTimerLabel(w, color, timer, highlight)
7655 /* check for low time warning */
7656 Pixel foregroundOrWarningColor = timerForegroundPixel;
7659 appData.lowTimeWarning &&
7660 (timer / 1000) < appData.icsAlarmTime)
7661 foregroundOrWarningColor = lowTimeWarningColor;
7663 if (appData.clockMode) {
7664 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7665 XtSetArg(args[0], XtNlabel, buf);
7667 snprintf(buf, MSG_SIZ, "%s ", color);
7668 XtSetArg(args[0], XtNlabel, buf);
7673 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7674 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7676 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7677 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7680 XtSetValues(w, args, 3);
7684 DisplayWhiteClock(timeRemaining, highlight)
7690 if(appData.noGUI) return;
7691 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7692 if (highlight && iconPixmap == bIconPixmap) {
7693 iconPixmap = wIconPixmap;
7694 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7695 XtSetValues(shellWidget, args, 1);
7700 DisplayBlackClock(timeRemaining, highlight)
7706 if(appData.noGUI) return;
7707 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7708 if (highlight && iconPixmap == wIconPixmap) {
7709 iconPixmap = bIconPixmap;
7710 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7711 XtSetValues(shellWidget, args, 1);
7729 int StartChildProcess(cmdLine, dir, pr)
7736 int to_prog[2], from_prog[2];
7740 if (appData.debugMode) {
7741 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7744 /* We do NOT feed the cmdLine to the shell; we just
7745 parse it into blank-separated arguments in the
7746 most simple-minded way possible.
7749 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7752 while(*p == ' ') p++;
7754 if(*p == '"' || *p == '\'')
7755 p = strchr(++argv[i-1], *p);
7756 else p = strchr(p, ' ');
7757 if (p == NULL) break;
7762 SetUpChildIO(to_prog, from_prog);
7764 if ((pid = fork()) == 0) {
7766 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7767 close(to_prog[1]); // first close the unused pipe ends
7768 close(from_prog[0]);
7769 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7770 dup2(from_prog[1], 1);
7771 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7772 close(from_prog[1]); // and closing again loses one of the pipes!
7773 if(fileno(stderr) >= 2) // better safe than sorry...
7774 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7776 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7781 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7783 execvp(argv[0], argv);
7785 /* If we get here, exec failed */
7790 /* Parent process */
7792 close(from_prog[1]);
7794 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7797 cp->fdFrom = from_prog[0];
7798 cp->fdTo = to_prog[1];
7803 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7804 static RETSIGTYPE AlarmCallBack(int n)
7810 DestroyChildProcess(pr, signalType)
7814 ChildProc *cp = (ChildProc *) pr;
7816 if (cp->kind != CPReal) return;
7818 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7819 signal(SIGALRM, AlarmCallBack);
7821 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7822 kill(cp->pid, SIGKILL); // kill it forcefully
7823 wait((int *) 0); // and wait again
7827 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7829 /* Process is exiting either because of the kill or because of
7830 a quit command sent by the backend; either way, wait for it to die.
7839 InterruptChildProcess(pr)
7842 ChildProc *cp = (ChildProc *) pr;
7844 if (cp->kind != CPReal) return;
7845 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7848 int OpenTelnet(host, port, pr)
7853 char cmdLine[MSG_SIZ];
7855 if (port[0] == NULLCHAR) {
7856 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7858 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7860 return StartChildProcess(cmdLine, "", pr);
7863 int OpenTCP(host, port, pr)
7869 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7870 #else /* !OMIT_SOCKETS */
7872 struct sockaddr_in sa;
7874 unsigned short uport;
7877 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7881 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7882 sa.sin_family = AF_INET;
7883 sa.sin_addr.s_addr = INADDR_ANY;
7884 uport = (unsigned short) 0;
7885 sa.sin_port = htons(uport);
7886 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7890 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7891 if (!(hp = gethostbyname(host))) {
7893 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7894 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7895 hp->h_addrtype = AF_INET;
7897 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7898 hp->h_addr_list[0] = (char *) malloc(4);
7899 hp->h_addr_list[0][0] = b0;
7900 hp->h_addr_list[0][1] = b1;
7901 hp->h_addr_list[0][2] = b2;
7902 hp->h_addr_list[0][3] = b3;
7907 sa.sin_family = hp->h_addrtype;
7908 uport = (unsigned short) atoi(port);
7909 sa.sin_port = htons(uport);
7910 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7912 if (connect(s, (struct sockaddr *) &sa,
7913 sizeof(struct sockaddr_in)) < 0) {
7917 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7924 #endif /* !OMIT_SOCKETS */
7929 int OpenCommPort(name, pr)
7936 fd = open(name, 2, 0);
7937 if (fd < 0) return errno;
7939 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7949 int OpenLoopback(pr)
7955 SetUpChildIO(to, from);
7957 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7960 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7967 int OpenRcmd(host, user, cmd, pr)
7968 char *host, *user, *cmd;
7971 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7975 #define INPUT_SOURCE_BUF_SIZE 8192
7984 char buf[INPUT_SOURCE_BUF_SIZE];
7989 DoInputCallback(closure, source, xid)
7994 InputSource *is = (InputSource *) closure;
7999 if (is->lineByLine) {
8000 count = read(is->fd, is->unused,
8001 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
8003 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
8006 is->unused += count;
8008 while (p < is->unused) {
8009 q = memchr(p, '\n', is->unused - p);
8010 if (q == NULL) break;
8012 (is->func)(is, is->closure, p, q - p, 0);
8016 while (p < is->unused) {
8021 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8026 (is->func)(is, is->closure, is->buf, count, error);
8030 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8037 ChildProc *cp = (ChildProc *) pr;
8039 is = (InputSource *) calloc(1, sizeof(InputSource));
8040 is->lineByLine = lineByLine;
8044 is->fd = fileno(stdin);
8046 is->kind = cp->kind;
8047 is->fd = cp->fdFrom;
8050 is->unused = is->buf;
8053 is->xid = XtAppAddInput(appContext, is->fd,
8054 (XtPointer) (XtInputReadMask),
8055 (XtInputCallbackProc) DoInputCallback,
8057 is->closure = closure;
8058 return (InputSourceRef) is;
8062 RemoveInputSource(isr)
8065 InputSource *is = (InputSource *) isr;
8067 if (is->xid == 0) return;
8068 XtRemoveInput(is->xid);
8072 int OutputToProcess(pr, message, count, outError)
8078 static int line = 0;
8079 ChildProc *cp = (ChildProc *) pr;
8084 if (appData.noJoin || !appData.useInternalWrap)
8085 outCount = fwrite(message, 1, count, stdout);
8088 int width = get_term_width();
8089 int len = wrap(NULL, message, count, width, &line);
8090 char *msg = malloc(len);
8094 outCount = fwrite(message, 1, count, stdout);
8097 dbgchk = wrap(msg, message, count, width, &line);
8098 if (dbgchk != len && appData.debugMode)
8099 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8100 outCount = fwrite(msg, 1, dbgchk, stdout);
8106 outCount = write(cp->fdTo, message, count);
8116 /* Output message to process, with "ms" milliseconds of delay
8117 between each character. This is needed when sending the logon
8118 script to ICC, which for some reason doesn't like the
8119 instantaneous send. */
8120 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8127 ChildProc *cp = (ChildProc *) pr;
8132 r = write(cp->fdTo, message++, 1);
8145 /**** Animation code by Hugh Fisher, DCS, ANU.
8147 Known problem: if a window overlapping the board is
8148 moved away while a piece is being animated underneath,
8149 the newly exposed area won't be updated properly.
8150 I can live with this.
8152 Known problem: if you look carefully at the animation
8153 of pieces in mono mode, they are being drawn as solid
8154 shapes without interior detail while moving. Fixing
8155 this would be a major complication for minimal return.
8158 /* Masks for XPM pieces. Black and white pieces can have
8159 different shapes, but in the interest of retaining my
8160 sanity pieces must have the same outline on both light
8161 and dark squares, and all pieces must use the same
8162 background square colors/images. */
8164 static int xpmDone = 0;
8167 CreateAnimMasks (pieceDepth)
8174 unsigned long plane;
8177 /* Need a bitmap just to get a GC with right depth */
8178 buf = XCreatePixmap(xDisplay, xBoardWindow,
8180 values.foreground = 1;
8181 values.background = 0;
8182 /* Don't use XtGetGC, not read only */
8183 maskGC = XCreateGC(xDisplay, buf,
8184 GCForeground | GCBackground, &values);
8185 XFreePixmap(xDisplay, buf);
8187 buf = XCreatePixmap(xDisplay, xBoardWindow,
8188 squareSize, squareSize, pieceDepth);
8189 values.foreground = XBlackPixel(xDisplay, xScreen);
8190 values.background = XWhitePixel(xDisplay, xScreen);
8191 bufGC = XCreateGC(xDisplay, buf,
8192 GCForeground | GCBackground, &values);
8194 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8195 /* Begin with empty mask */
8196 if(!xpmDone) // [HGM] pieces: keep using existing
8197 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8198 squareSize, squareSize, 1);
8199 XSetFunction(xDisplay, maskGC, GXclear);
8200 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8201 0, 0, squareSize, squareSize);
8203 /* Take a copy of the piece */
8208 XSetFunction(xDisplay, bufGC, GXcopy);
8209 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8211 0, 0, squareSize, squareSize, 0, 0);
8213 /* XOR the background (light) over the piece */
8214 XSetFunction(xDisplay, bufGC, GXxor);
8216 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8217 0, 0, squareSize, squareSize, 0, 0);
8219 XSetForeground(xDisplay, bufGC, lightSquareColor);
8220 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8223 /* We now have an inverted piece image with the background
8224 erased. Construct mask by just selecting all the non-zero
8225 pixels - no need to reconstruct the original image. */
8226 XSetFunction(xDisplay, maskGC, GXor);
8228 /* Might be quicker to download an XImage and create bitmap
8229 data from it rather than this N copies per piece, but it
8230 only takes a fraction of a second and there is a much
8231 longer delay for loading the pieces. */
8232 for (n = 0; n < pieceDepth; n ++) {
8233 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8234 0, 0, squareSize, squareSize,
8240 XFreePixmap(xDisplay, buf);
8241 XFreeGC(xDisplay, bufGC);
8242 XFreeGC(xDisplay, maskGC);
8246 InitAnimState (anim, info)
8248 XWindowAttributes * info;
8253 /* Each buffer is square size, same depth as window */
8254 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8255 squareSize, squareSize, info->depth);
8256 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8257 squareSize, squareSize, info->depth);
8259 /* Create a plain GC for blitting */
8260 mask = GCForeground | GCBackground | GCFunction |
8261 GCPlaneMask | GCGraphicsExposures;
8262 values.foreground = XBlackPixel(xDisplay, xScreen);
8263 values.background = XWhitePixel(xDisplay, xScreen);
8264 values.function = GXcopy;
8265 values.plane_mask = AllPlanes;
8266 values.graphics_exposures = False;
8267 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8269 /* Piece will be copied from an existing context at
8270 the start of each new animation/drag. */
8271 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8273 /* Outline will be a read-only copy of an existing */
8274 anim->outlineGC = None;
8280 XWindowAttributes info;
8282 if (xpmDone && gameInfo.variant == oldVariant) return;
8283 if(xpmDone) oldVariant = gameInfo.variant; // first time pieces might not be created yet
8284 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8286 InitAnimState(&game, &info);
8287 InitAnimState(&player, &info);
8289 /* For XPM pieces, we need bitmaps to use as masks. */
8291 CreateAnimMasks(info.depth);
8297 static Boolean frameWaiting;
8299 static RETSIGTYPE FrameAlarm (sig)
8302 frameWaiting = False;
8303 /* In case System-V style signals. Needed?? */
8304 signal(SIGALRM, FrameAlarm);
8311 struct itimerval delay;
8313 XSync(xDisplay, False);
8316 frameWaiting = True;
8317 signal(SIGALRM, FrameAlarm);
8318 delay.it_interval.tv_sec =
8319 delay.it_value.tv_sec = time / 1000;
8320 delay.it_interval.tv_usec =
8321 delay.it_value.tv_usec = (time % 1000) * 1000;
8322 setitimer(ITIMER_REAL, &delay, NULL);
8323 while (frameWaiting) pause();
8324 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8325 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8326 setitimer(ITIMER_REAL, &delay, NULL);
8336 XSync(xDisplay, False);
8338 usleep(time * 1000);
8343 /* Convert board position to corner of screen rect and color */
8346 ScreenSquare(column, row, pt, color)
8347 int column; int row; XPoint * pt; int * color;
8350 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8351 pt->y = lineGap + row * (squareSize + lineGap);
8353 pt->x = lineGap + column * (squareSize + lineGap);
8354 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8356 *color = SquareColor(row, column);
8359 /* Convert window coords to square */
8362 BoardSquare(x, y, column, row)
8363 int x; int y; int * column; int * row;
8365 *column = EventToSquare(x, BOARD_WIDTH);
8366 if (flipView && *column >= 0)
8367 *column = BOARD_WIDTH - 1 - *column;
8368 *row = EventToSquare(y, BOARD_HEIGHT);
8369 if (!flipView && *row >= 0)
8370 *row = BOARD_HEIGHT - 1 - *row;
8375 #undef Max /* just in case */
8377 #define Max(a, b) ((a) > (b) ? (a) : (b))
8378 #define Min(a, b) ((a) < (b) ? (a) : (b))
8381 SetRect(rect, x, y, width, height)
8382 XRectangle * rect; int x; int y; int width; int height;
8386 rect->width = width;
8387 rect->height = height;
8390 /* Test if two frames overlap. If they do, return
8391 intersection rect within old and location of
8392 that rect within new. */
8395 Intersect(old, new, size, area, pt)
8396 XPoint * old; XPoint * new;
8397 int size; XRectangle * area; XPoint * pt;
8399 if (old->x > new->x + size || new->x > old->x + size ||
8400 old->y > new->y + size || new->y > old->y + size) {
8403 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8404 size - abs(old->x - new->x), size - abs(old->y - new->y));
8405 pt->x = Max(old->x - new->x, 0);
8406 pt->y = Max(old->y - new->y, 0);
8411 /* For two overlapping frames, return the rect(s)
8412 in the old that do not intersect with the new. */
8415 CalcUpdateRects(old, new, size, update, nUpdates)
8416 XPoint * old; XPoint * new; int size;
8417 XRectangle update[]; int * nUpdates;
8421 /* If old = new (shouldn't happen) then nothing to draw */
8422 if (old->x == new->x && old->y == new->y) {
8426 /* Work out what bits overlap. Since we know the rects
8427 are the same size we don't need a full intersect calc. */
8429 /* Top or bottom edge? */
8430 if (new->y > old->y) {
8431 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8433 } else if (old->y > new->y) {
8434 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8435 size, old->y - new->y);
8438 /* Left or right edge - don't overlap any update calculated above. */
8439 if (new->x > old->x) {
8440 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8441 new->x - old->x, size - abs(new->y - old->y));
8443 } else if (old->x > new->x) {
8444 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8445 old->x - new->x, size - abs(new->y - old->y));
8452 /* Generate a series of frame coords from start->mid->finish.
8453 The movement rate doubles until the half way point is
8454 reached, then halves back down to the final destination,
8455 which gives a nice slow in/out effect. The algorithmn
8456 may seem to generate too many intermediates for short
8457 moves, but remember that the purpose is to attract the
8458 viewers attention to the piece about to be moved and
8459 then to where it ends up. Too few frames would be less
8463 Tween(start, mid, finish, factor, frames, nFrames)
8464 XPoint * start; XPoint * mid;
8465 XPoint * finish; int factor;
8466 XPoint frames[]; int * nFrames;
8468 int fraction, n, count;
8472 /* Slow in, stepping 1/16th, then 1/8th, ... */
8474 for (n = 0; n < factor; n++)
8476 for (n = 0; n < factor; n++) {
8477 frames[count].x = start->x + (mid->x - start->x) / fraction;
8478 frames[count].y = start->y + (mid->y - start->y) / fraction;
8480 fraction = fraction / 2;
8484 frames[count] = *mid;
8487 /* Slow out, stepping 1/2, then 1/4, ... */
8489 for (n = 0; n < factor; n++) {
8490 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8491 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8493 fraction = fraction * 2;
8498 /* Draw a piece on the screen without disturbing what's there */
8501 SelectGCMask(piece, clip, outline, mask)
8502 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8506 /* Bitmap for piece being moved. */
8507 if (appData.monoMode) {
8508 *mask = *pieceToSolid(piece);
8509 } else if (useImages) {
8511 *mask = xpmMask[piece];
8513 *mask = ximMaskPm[piece];
8516 *mask = *pieceToSolid(piece);
8519 /* GC for piece being moved. Square color doesn't matter, but
8520 since it gets modified we make a copy of the original. */
8522 if (appData.monoMode)
8527 if (appData.monoMode)
8532 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8534 /* Outline only used in mono mode and is not modified */
8536 *outline = bwPieceGC;
8538 *outline = wbPieceGC;
8542 OverlayPiece(piece, clip, outline, dest)
8543 ChessSquare piece; GC clip; GC outline; Drawable dest;
8548 /* Draw solid rectangle which will be clipped to shape of piece */
8549 XFillRectangle(xDisplay, dest, clip,
8550 0, 0, squareSize, squareSize);
8551 if (appData.monoMode)
8552 /* Also draw outline in contrasting color for black
8553 on black / white on white cases */
8554 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8555 0, 0, squareSize, squareSize, 0, 0, 1);
8557 /* Copy the piece */
8562 if(appData.upsideDown && flipView) kind ^= 2;
8563 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8565 0, 0, squareSize, squareSize,
8570 /* Animate the movement of a single piece */
8573 BeginAnimation(anim, piece, startColor, start)
8581 if(appData.upsideDown && flipView) piece += piece < BlackPawn ? BlackPawn : -BlackPawn;
8582 /* The old buffer is initialised with the start square (empty) */
8583 BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0);
8584 anim->prevFrame = *start;
8586 /* The piece will be drawn using its own bitmap as a matte */
8587 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8588 XSetClipMask(xDisplay, anim->pieceGC, mask);
8592 AnimationFrame(anim, frame, piece)
8597 XRectangle updates[4];
8602 /* Save what we are about to draw into the new buffer */
8603 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8604 frame->x, frame->y, squareSize, squareSize,
8607 /* Erase bits of the previous frame */
8608 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8609 /* Where the new frame overlapped the previous,
8610 the contents in newBuf are wrong. */
8611 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8612 overlap.x, overlap.y,
8613 overlap.width, overlap.height,
8615 /* Repaint the areas in the old that don't overlap new */
8616 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8617 for (i = 0; i < count; i++)
8618 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8619 updates[i].x - anim->prevFrame.x,
8620 updates[i].y - anim->prevFrame.y,
8621 updates[i].width, updates[i].height,
8622 updates[i].x, updates[i].y);
8624 /* Easy when no overlap */
8625 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8626 0, 0, squareSize, squareSize,
8627 anim->prevFrame.x, anim->prevFrame.y);
8630 /* Save this frame for next time round */
8631 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8632 0, 0, squareSize, squareSize,
8634 anim->prevFrame = *frame;
8636 /* Draw piece over original screen contents, not current,
8637 and copy entire rect. Wipes out overlapping piece images. */
8638 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8639 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8640 0, 0, squareSize, squareSize,
8641 frame->x, frame->y);
8645 EndAnimation (anim, finish)
8649 XRectangle updates[4];
8654 /* The main code will redraw the final square, so we
8655 only need to erase the bits that don't overlap. */
8656 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8657 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8658 for (i = 0; i < count; i++)
8659 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8660 updates[i].x - anim->prevFrame.x,
8661 updates[i].y - anim->prevFrame.y,
8662 updates[i].width, updates[i].height,
8663 updates[i].x, updates[i].y);
8665 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8666 0, 0, squareSize, squareSize,
8667 anim->prevFrame.x, anim->prevFrame.y);
8672 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8674 ChessSquare piece; int startColor;
8675 XPoint * start; XPoint * finish;
8676 XPoint frames[]; int nFrames;
8680 BeginAnimation(anim, piece, startColor, start);
8681 for (n = 0; n < nFrames; n++) {
8682 AnimationFrame(anim, &(frames[n]), piece);
8683 FrameDelay(appData.animSpeed);
8685 EndAnimation(anim, finish);
8689 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
8692 ChessSquare piece = board[fromY][toY];
8693 board[fromY][toY] = EmptySquare;
8694 DrawPosition(FALSE, board);
8696 x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap);
8697 y = lineGap + toY * (squareSize + lineGap);
8699 x = lineGap + toX * (squareSize + lineGap);
8700 y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap);
8702 for(i=1; i<4*kFactor; i++) {
8703 int r = squareSize * 9 * i/(20*kFactor - 5);
8704 XFillArc(xDisplay, xBoardWindow, highlineGC,
8705 x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360);
8706 FrameDelay(appData.animSpeed);
8708 board[fromY][toY] = piece;
8711 /* Main control logic for deciding what to animate and how */
8714 AnimateMove(board, fromX, fromY, toX, toY)
8723 XPoint start, finish, mid;
8724 XPoint frames[kFactor * 2 + 1];
8725 int nFrames, startColor, endColor;
8727 /* Are we animating? */
8728 if (!appData.animate || appData.blindfold)
8731 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8732 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8733 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8735 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8736 piece = board[fromY][fromX];
8737 if (piece >= EmptySquare) return;
8742 hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1;
8745 if (appData.debugMode) {
8746 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8747 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8748 piece, fromX, fromY, toX, toY); }
8750 ScreenSquare(fromX, fromY, &start, &startColor);
8751 ScreenSquare(toX, toY, &finish, &endColor);
8754 /* Knight: make straight movement then diagonal */
8755 if (abs(toY - fromY) < abs(toX - fromX)) {
8756 mid.x = start.x + (finish.x - start.x) / 2;
8760 mid.y = start.y + (finish.y - start.y) / 2;
8763 mid.x = start.x + (finish.x - start.x) / 2;
8764 mid.y = start.y + (finish.y - start.y) / 2;
8767 /* Don't use as many frames for very short moves */
8768 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8769 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8771 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8772 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8773 if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
8775 for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
8776 if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
8779 /* Be sure end square is redrawn */
8780 damage[0][toY][toX] = True;
8784 DragPieceBegin(x, y)
8787 int boardX, boardY, color;
8790 /* Are we animating? */
8791 if (!appData.animateDragging || appData.blindfold)
8794 /* Figure out which square we start in and the
8795 mouse position relative to top left corner. */
8796 BoardSquare(x, y, &boardX, &boardY);
8797 player.startBoardX = boardX;
8798 player.startBoardY = boardY;
8799 ScreenSquare(boardX, boardY, &corner, &color);
8800 player.startSquare = corner;
8801 player.startColor = color;
8802 /* As soon as we start dragging, the piece will jump slightly to
8803 be centered over the mouse pointer. */
8804 player.mouseDelta.x = squareSize/2;
8805 player.mouseDelta.y = squareSize/2;
8806 /* Initialise animation */
8807 player.dragPiece = PieceForSquare(boardX, boardY);
8809 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8810 player.dragActive = True;
8811 BeginAnimation(&player, player.dragPiece, color, &corner);
8812 /* Mark this square as needing to be redrawn. Note that
8813 we don't remove the piece though, since logically (ie
8814 as seen by opponent) the move hasn't been made yet. */
8815 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8816 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8817 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8818 corner.x, corner.y, squareSize, squareSize,
8819 0, 0); // [HGM] zh: unstack in stead of grab
8820 if(gatingPiece != EmptySquare) {
8821 /* Kludge alert: When gating we want the introduced
8822 piece to appear on the from square. To generate an
8823 image of it, we draw it on the board, copy the image,
8824 and draw the original piece again. */
8825 ChessSquare piece = boards[currentMove][boardY][boardX];
8826 DrawSquare(boardY, boardX, gatingPiece, 0);
8827 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8828 corner.x, corner.y, squareSize, squareSize, 0, 0);
8829 DrawSquare(boardY, boardX, piece, 0);
8831 damage[0][boardY][boardX] = True;
8833 player.dragActive = False;
8843 /* Are we animating? */
8844 if (!appData.animateDragging || appData.blindfold)
8848 if (! player.dragActive)
8850 /* Move piece, maintaining same relative position
8851 of mouse within square */
8852 corner.x = x - player.mouseDelta.x;
8853 corner.y = y - player.mouseDelta.y;
8854 AnimationFrame(&player, &corner, player.dragPiece);
8856 if (appData.highlightDragging) {
8858 BoardSquare(x, y, &boardX, &boardY);
8859 SetHighlights(fromX, fromY, boardX, boardY);
8868 int boardX, boardY, color;
8871 /* Are we animating? */
8872 if (!appData.animateDragging || appData.blindfold)
8876 if (! player.dragActive)
8878 /* Last frame in sequence is square piece is
8879 placed on, which may not match mouse exactly. */
8880 BoardSquare(x, y, &boardX, &boardY);
8881 ScreenSquare(boardX, boardY, &corner, &color);
8882 EndAnimation(&player, &corner);
8884 /* Be sure end square is redrawn */
8885 damage[0][boardY][boardX] = True;
8887 /* This prevents weird things happening with fast successive
8888 clicks which on my Sun at least can cause motion events
8889 without corresponding press/release. */
8890 player.dragActive = False;
8893 /* Handle expose event while piece being dragged */
8898 if (!player.dragActive || appData.blindfold)
8901 /* What we're doing: logically, the move hasn't been made yet,
8902 so the piece is still in it's original square. But visually
8903 it's being dragged around the board. So we erase the square
8904 that the piece is on and draw it at the last known drag point. */
8905 BlankSquare(player.startSquare.x, player.startSquare.y,
8906 player.startColor, EmptySquare, xBoardWindow, 1);
8907 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8908 damage[0][player.startBoardY][player.startBoardX] = TRUE;
8911 #include <sys/ioctl.h>
8912 int get_term_width()
8914 int fd, default_width;
8917 default_width = 79; // this is FICS default anyway...
8919 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8921 if (!ioctl(fd, TIOCGSIZE, &win))
8922 default_width = win.ts_cols;
8923 #elif defined(TIOCGWINSZ)
8925 if (!ioctl(fd, TIOCGWINSZ, &win))
8926 default_width = win.ws_col;
8928 return default_width;
8934 static int old_width = 0;
8935 int new_width = get_term_width();
8937 if (old_width != new_width)
8938 ics_printf("set width %d\n", new_width);
8939 old_width = new_width;
8942 void NotifyFrontendLogin()
8947 /* [AS] Arrow highlighting support */
8949 static double A_WIDTH = 5; /* Width of arrow body */
8951 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
8952 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
8954 static double Sqr( double x )
8959 static int Round( double x )
8961 return (int) (x + 0.5);
8964 void SquareToPos(int rank, int file, int *x, int *y)
8967 *x = lineGap + ((BOARD_WIDTH-1)-file) * (squareSize + lineGap);
8968 *y = lineGap + rank * (squareSize + lineGap);
8970 *x = lineGap + file * (squareSize + lineGap);
8971 *y = lineGap + ((BOARD_HEIGHT-1)-rank) * (squareSize + lineGap);
8975 /* Draw an arrow between two points using current settings */
8976 void DrawArrowBetweenPoints( int s_x, int s_y, int d_x, int d_y )
8979 double dx, dy, j, k, x, y;
8982 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
8984 arrow[0].x = s_x + A_WIDTH + 0.5;
8987 arrow[1].x = s_x + A_WIDTH + 0.5;
8988 arrow[1].y = d_y - h;
8990 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8991 arrow[2].y = d_y - h;
8996 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
8997 arrow[5].y = d_y - h;
8999 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9000 arrow[4].y = d_y - h;
9002 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
9005 else if( d_y == s_y ) {
9006 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
9009 arrow[0].y = s_y + A_WIDTH + 0.5;
9011 arrow[1].x = d_x - w;
9012 arrow[1].y = s_y + A_WIDTH + 0.5;
9014 arrow[2].x = d_x - w;
9015 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9020 arrow[5].x = d_x - w;
9021 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
9023 arrow[4].x = d_x - w;
9024 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9027 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
9030 /* [AS] Needed a lot of paper for this! :-) */
9031 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
9032 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
9034 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
9036 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
9041 arrow[0].x = Round(x - j);
9042 arrow[0].y = Round(y + j*dx);
9044 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
9045 arrow[1].y = Round(arrow[0].y - 2*j*dx);
9048 x = (double) d_x - k;
9049 y = (double) d_y - k*dy;
9052 x = (double) d_x + k;
9053 y = (double) d_y + k*dy;
9056 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
9058 arrow[6].x = Round(x - j);
9059 arrow[6].y = Round(y + j*dx);
9061 arrow[2].x = Round(arrow[6].x + 2*j);
9062 arrow[2].y = Round(arrow[6].y - 2*j*dx);
9064 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
9065 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
9070 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
9071 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
9074 XFillPolygon(xDisplay, xBoardWindow, highlineGC, arrow, 7, Nonconvex, CoordModeOrigin);
9075 // Polygon( hdc, arrow, 7 );
9078 /* [AS] Draw an arrow between two squares */
9079 void DrawArrowBetweenSquares( int s_col, int s_row, int d_col, int d_row )
9081 int s_x, s_y, d_x, d_y, hor, vert, i;
9083 if( s_col == d_col && s_row == d_row ) {
9087 /* Get source and destination points */
9088 SquareToPos( s_row, s_col, &s_x, &s_y);
9089 SquareToPos( d_row, d_col, &d_x, &d_y);
9092 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
9094 else if( d_y < s_y ) {
9095 d_y += squareSize / 2 + squareSize / 4;
9098 d_y += squareSize / 2;
9102 d_x += squareSize / 2 - squareSize / 4;
9104 else if( d_x < s_x ) {
9105 d_x += squareSize / 2 + squareSize / 4;
9108 d_x += squareSize / 2;
9111 s_x += squareSize / 2;
9112 s_y += squareSize / 2;
9115 A_WIDTH = squareSize / 14.; //[HGM] make float
9117 DrawArrowBetweenPoints( s_x, s_y, d_x, d_y );
9119 hor = 64*s_col + 32; vert = 64*s_row + 32;
9120 for(i=0; i<= 64; i++) {
9121 damage[0][vert+6>>6][hor+6>>6] = True;
9122 damage[0][vert-6>>6][hor+6>>6] = True;
9123 damage[0][vert+6>>6][hor-6>>6] = True;
9124 damage[0][vert-6>>6][hor-6>>6] = True;
9125 hor += d_col - s_col; vert += d_row - s_row;
9129 Boolean IsDrawArrowEnabled()
9131 return appData.highlightMoveWithArrow && squareSize >= 32;
9134 void DrawArrowHighlight(int fromX, int fromY, int toX,int toY)
9136 if( IsDrawArrowEnabled() && fromX >= 0 && fromY >= 0 && toX >= 0 && toY >= 0)
9137 DrawArrowBetweenSquares(fromX, fromY, toX, toY);