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 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>
65 # if HAVE_SYS_SOCKET_H
66 # include <sys/socket.h>
67 # include <netinet/in.h>
69 # else /* not HAVE_SYS_SOCKET_H */
70 # if HAVE_LAN_SOCKET_H
71 # include <lan/socket.h>
73 # include <lan/netdb.h>
74 # else /* not HAVE_LAN_SOCKET_H */
75 # define OMIT_SOCKETS 1
76 # endif /* not HAVE_LAN_SOCKET_H */
77 # endif /* not HAVE_SYS_SOCKET_H */
78 #endif /* !OMIT_SOCKETS */
83 #else /* not STDC_HEADERS */
84 extern char *getenv();
87 # else /* not HAVE_STRING_H */
89 # endif /* not HAVE_STRING_H */
90 #endif /* not STDC_HEADERS */
93 # include <sys/fcntl.h>
94 #else /* not HAVE_SYS_FCNTL_H */
97 # endif /* HAVE_FCNTL_H */
98 #endif /* not HAVE_SYS_FCNTL_H */
100 #if HAVE_SYS_SYSTEMINFO_H
101 # include <sys/systeminfo.h>
102 #endif /* HAVE_SYS_SYSTEMINFO_H */
104 #if TIME_WITH_SYS_TIME
105 # include <sys/time.h>
109 # include <sys/time.h>
120 # include <sys/wait.h>
125 # define NAMLEN(dirent) strlen((dirent)->d_name)
126 # define HAVE_DIR_STRUCT
128 # define dirent direct
129 # define NAMLEN(dirent) (dirent)->d_namlen
131 # include <sys/ndir.h>
132 # define HAVE_DIR_STRUCT
135 # include <sys/dir.h>
136 # define HAVE_DIR_STRUCT
140 # define HAVE_DIR_STRUCT
145 # if HAVE_LIBREADLINE /* add gnu-readline support */
146 #include <readline/readline.h>
147 #include <readline/history.h>
150 #include <X11/Intrinsic.h>
151 #include <X11/StringDefs.h>
152 #include <X11/Shell.h>
153 #include <X11/cursorfont.h>
154 #include <X11/Xatom.h>
155 #include <X11/Xmu/Atoms.h>
157 #include <X11/Xaw3d/Dialog.h>
158 #include <X11/Xaw3d/Form.h>
159 #include <X11/Xaw3d/List.h>
160 #include <X11/Xaw3d/Label.h>
161 #include <X11/Xaw3d/SimpleMenu.h>
162 #include <X11/Xaw3d/SmeBSB.h>
163 #include <X11/Xaw3d/SmeLine.h>
164 #include <X11/Xaw3d/Box.h>
165 #include <X11/Xaw3d/MenuButton.h>
166 #include <X11/Xaw3d/Text.h>
167 #include <X11/Xaw3d/AsciiText.h>
169 #include <X11/Xaw/Dialog.h>
170 #include <X11/Xaw/Form.h>
171 #include <X11/Xaw/List.h>
172 #include <X11/Xaw/Label.h>
173 #include <X11/Xaw/SimpleMenu.h>
174 #include <X11/Xaw/SmeBSB.h>
175 #include <X11/Xaw/SmeLine.h>
176 #include <X11/Xaw/Box.h>
177 #include <X11/Xaw/MenuButton.h>
178 #include <X11/Xaw/Text.h>
179 #include <X11/Xaw/AsciiText.h>
182 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
187 #include "pixmaps/pixmaps.h"
188 #define IMAGE_EXT "xpm"
190 #define IMAGE_EXT "xim"
191 #include "bitmaps/bitmaps.h"
194 #include "bitmaps/icon_white.bm"
195 #include "bitmaps/icon_black.bm"
196 #include "bitmaps/checkmark.bm"
198 #include "frontend.h"
200 #include "backendz.h"
204 #include "xgamelist.h"
205 #include "xhistory.h"
206 #include "xedittags.h"
209 // must be moved to xengineoutput.h
211 void EngineOutputProc P((Widget w, XEvent *event,
212 String *prms, Cardinal *nprms));
213 void EvalGraphProc P((Widget w, XEvent *event,
214 String *prms, Cardinal *nprms));
221 #define usleep(t) _sleep2(((t)+500)/1000)
225 # define _(s) gettext (s)
226 # define N_(s) gettext_noop (s)
242 int main P((int argc, char **argv));
243 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
244 char *init_path, char *mode, int (*show_entry)(), char **name_return));
245 RETSIGTYPE CmailSigHandler P((int sig));
246 RETSIGTYPE IntSigHandler P((int sig));
247 RETSIGTYPE TermSizeSigHandler P((int sig));
248 void CreateGCs P((void));
249 void CreateXIMPieces P((void));
250 void CreateXPMPieces P((void));
251 void CreateXPMBoard P((char *s, int n));
252 void CreatePieces P((void));
253 void CreatePieceMenus P((void));
254 Widget CreateMenuBar P((Menu *mb));
255 Widget CreateButtonBar P ((MenuItem *mi));
256 char *FindFont P((char *pattern, int targetPxlSize));
257 void PieceMenuPopup P((Widget w, XEvent *event,
258 String *params, Cardinal *num_params));
259 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
260 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
261 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
262 u_int wreq, u_int hreq));
263 void CreateGrid P((void));
264 int EventToSquare P((int x, int limit));
265 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
266 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
267 void HandleUserMove P((Widget w, XEvent *event,
268 String *prms, Cardinal *nprms));
269 void AnimateUserMove P((Widget w, XEvent * event,
270 String * params, Cardinal * nParams));
271 void HandlePV P((Widget w, XEvent * event,
272 String * params, Cardinal * nParams));
273 void SelectPV P((Widget w, XEvent * event,
274 String * params, Cardinal * nParams));
275 void StopPV P((Widget w, XEvent * event,
276 String * params, Cardinal * nParams));
277 void WhiteClock P((Widget w, XEvent *event,
278 String *prms, Cardinal *nprms));
279 void BlackClock P((Widget w, XEvent *event,
280 String *prms, Cardinal *nprms));
281 void DrawPositionProc P((Widget w, XEvent *event,
282 String *prms, Cardinal *nprms));
283 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
285 void CommentClick P((Widget w, XEvent * event,
286 String * params, Cardinal * nParams));
287 void CommentPopUp P((char *title, char *label));
288 void CommentPopDown P((void));
289 void CommentCallback P((Widget w, XtPointer client_data,
290 XtPointer call_data));
291 void ICSInputBoxPopUp P((void));
292 void ICSInputBoxPopDown P((void));
293 void FileNamePopUp P((char *label, char *def,
294 FileProc proc, char *openMode));
295 void FileNamePopDown P((void));
296 void FileNameCallback P((Widget w, XtPointer client_data,
297 XtPointer call_data));
298 void FileNameAction P((Widget w, XEvent *event,
299 String *prms, Cardinal *nprms));
300 void AskQuestionReplyAction P((Widget w, XEvent *event,
301 String *prms, Cardinal *nprms));
302 void AskQuestionProc P((Widget w, XEvent *event,
303 String *prms, Cardinal *nprms));
304 void AskQuestionPopDown P((void));
305 void PromotionPopDown P((void));
306 void PromotionCallback P((Widget w, XtPointer client_data,
307 XtPointer call_data));
308 void EditCommentPopDown P((void));
309 void EditCommentCallback P((Widget w, XtPointer client_data,
310 XtPointer call_data));
311 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
312 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
313 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
314 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
316 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
318 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
320 void LoadPositionProc P((Widget w, XEvent *event,
321 String *prms, Cardinal *nprms));
322 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
324 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
326 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
328 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
330 void PastePositionProc P((Widget w, XEvent *event, String *prms,
332 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
333 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
334 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
335 void SavePositionProc P((Widget w, XEvent *event,
336 String *prms, Cardinal *nprms));
337 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
338 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
340 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
341 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
342 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
344 void MachineWhiteProc P((Widget w, XEvent *event,
345 String *prms, Cardinal *nprms));
346 void AnalyzeModeProc P((Widget w, XEvent *event,
347 String *prms, Cardinal *nprms));
348 void AnalyzeFileProc P((Widget w, XEvent *event,
349 String *prms, Cardinal *nprms));
350 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
352 void IcsClientProc P((Widget w, XEvent *event, String *prms,
354 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
355 void EditPositionProc P((Widget w, XEvent *event,
356 String *prms, Cardinal *nprms));
357 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
358 void EditCommentProc P((Widget w, XEvent *event,
359 String *prms, Cardinal *nprms));
360 void IcsInputBoxProc P((Widget w, XEvent *event,
361 String *prms, Cardinal *nprms));
362 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
365 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
370 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
371 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
372 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
373 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
374 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
375 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
376 void StopObservingProc P((Widget w, XEvent *event, String *prms,
378 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
380 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
384 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
385 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
386 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
387 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
389 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
391 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
392 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
394 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
396 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
398 void AutocommProc P((Widget w, XEvent *event, String *prms,
400 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
401 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
402 void AutobsProc P((Widget w, XEvent *event, String *prms,
404 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
405 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
406 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
407 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
409 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
410 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
412 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
414 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
416 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
417 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
418 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
420 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
422 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
424 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
426 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
428 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
429 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
430 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
432 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
434 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
436 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
438 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
442 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
443 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
444 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
445 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
446 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
447 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
448 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
449 void DisplayMove P((int moveNumber));
450 void DisplayTitle P((char *title));
451 void ICSInitScript P((void));
452 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
453 void ErrorPopUp P((char *title, char *text, int modal));
454 void ErrorPopDown P((void));
455 static char *ExpandPathName P((char *path));
456 static void CreateAnimVars P((void));
457 static void DragPieceMove P((int x, int y));
458 static void DrawDragPiece P((void));
459 char *ModeToWidgetName P((GameMode mode));
460 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
461 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
462 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
463 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
464 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
465 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
466 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
467 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
468 void GameListOptionsPopDown P(());
469 void ShufflePopDown P(());
470 void EnginePopDown P(());
471 void UciPopDown P(());
472 void TimeControlPopDown P(());
473 void NewVariantPopDown P(());
474 void SettingsPopDown P(());
475 void update_ics_width P(());
476 int get_term_width P(());
477 int CopyMemoProc P(());
479 # if HAVE_LIBREADLINE /* add gnu-readline support */
480 static void ReadlineCompleteHandler P((char *));
484 * XBoard depends on Xt R4 or higher
486 int xtVersion = XtSpecificationRelease;
491 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
492 jailSquareColor, highlightSquareColor, premoveHighlightColor;
493 Pixel lowTimeWarningColor;
494 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
495 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
496 wjPieceGC, bjPieceGC, prelineGC, countGC;
497 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
498 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
499 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
500 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
501 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
502 ICSInputShell, fileNameShell, askQuestionShell;
503 Widget historyShell, evalGraphShell, gameListShell;
504 int hOffset; // [HGM] dual
505 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
506 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
507 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
508 Font clockFontID, coordFontID, countFontID;
509 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
510 XtAppContext appContext;
512 char *oldICSInteractionTitle;
516 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
518 # if HAVE_LIBREADLINE /* gnu readline support */
519 static char* readline_buffer;
520 static int readline_complete=0;
521 extern int sending_ICS_login;
522 extern int sending_ICS_password;
525 Position commentX = -1, commentY = -1;
526 Dimension commentW, commentH;
527 typedef unsigned int BoardSize;
529 Boolean chessProgram;
531 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
532 int squareSize, smallLayout = 0, tinyLayout = 0,
533 marginW, marginH, // [HGM] for run-time resizing
534 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
535 ICSInputBoxUp = False, askQuestionUp = False,
536 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
537 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
538 Pixel timerForegroundPixel, timerBackgroundPixel;
539 Pixel buttonForegroundPixel, buttonBackgroundPixel;
540 char *chessDir, *programName, *programVersion,
541 *gameCopyFilename, *gamePasteFilename;
542 Boolean alwaysOnTop = False;
543 Boolean saveSettingsOnExit;
544 char *settingsFileName;
545 char *icsTextMenuString;
547 char *firstChessProgramNames;
548 char *secondChessProgramNames;
550 WindowPlacement wpMain;
551 WindowPlacement wpConsole;
552 WindowPlacement wpComment;
553 WindowPlacement wpMoveHistory;
554 WindowPlacement wpEvalGraph;
555 WindowPlacement wpEngineOutput;
556 WindowPlacement wpGameList;
557 WindowPlacement wpTags;
561 Pixmap pieceBitmap[2][(int)BlackPawn];
562 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
563 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
564 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
565 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
566 Pixmap xpmBoardBitmap[2];
567 int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
568 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
569 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
570 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
571 XImage *ximLightSquare, *ximDarkSquare;
574 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
575 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
577 #define White(piece) ((int)(piece) < (int)BlackPawn)
579 /* Variables for doing smooth animation. This whole thing
580 would be much easier if the board was double-buffered,
581 but that would require a fairly major rewrite. */
586 GC blitGC, pieceGC, outlineGC;
587 XPoint startSquare, prevFrame, mouseDelta;
591 int startBoardX, startBoardY;
594 /* There can be two pieces being animated at once: a player
595 can begin dragging a piece before the remote opponent has moved. */
597 static AnimState game, player;
599 /* Bitmaps for use as masks when drawing XPM pieces.
600 Need one for each black and white piece. */
601 static Pixmap xpmMask[BlackKing + 1];
603 /* This magic number is the number of intermediate frames used
604 in each half of the animation. For short moves it's reduced
605 by 1. The total number of frames will be factor * 2 + 1. */
608 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
610 MenuItem fileMenu[] = {
611 {N_("New Game"), ResetProc},
612 {N_("New Shuffle Game ..."), ShuffleMenuProc},
613 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
614 {"----", NothingProc},
615 {N_("Load Game"), LoadGameProc},
616 {N_("Load Next Game"), LoadNextGameProc},
617 {N_("Load Previous Game"), LoadPrevGameProc},
618 {N_("Reload Same Game"), ReloadGameProc},
619 {N_("Save Game"), SaveGameProc},
620 {"----", NothingProc},
621 {N_("Copy Game"), CopyGameProc},
622 {N_("Paste Game"), PasteGameProc},
623 {"----", NothingProc},
624 {N_("Load Position"), LoadPositionProc},
625 {N_("Load Next Position"), LoadNextPositionProc},
626 {N_("Load Previous Position"), LoadPrevPositionProc},
627 {N_("Reload Same Position"), ReloadPositionProc},
628 {N_("Save Position"), SavePositionProc},
629 {"----", NothingProc},
630 {N_("Copy Position"), CopyPositionProc},
631 {N_("Paste Position"), PastePositionProc},
632 {"----", NothingProc},
633 {N_("Mail Move"), MailMoveProc},
634 {N_("Reload CMail Message"), ReloadCmailMsgProc},
635 {"----", NothingProc},
636 {N_("Exit"), QuitProc},
640 MenuItem modeMenu[] = {
641 {N_("Machine White"), MachineWhiteProc},
642 {N_("Machine Black"), MachineBlackProc},
643 {N_("Two Machines"), TwoMachinesProc},
644 {N_("Analysis Mode"), AnalyzeModeProc},
645 {N_("Analyze File"), AnalyzeFileProc },
646 {N_("ICS Client"), IcsClientProc},
647 {N_("Edit Game"), EditGameProc},
648 {N_("Edit Position"), EditPositionProc},
649 {N_("Training"), TrainingProc},
650 {"----", NothingProc},
651 {N_("Show Engine Output"), EngineOutputProc},
652 {N_("Show Evaluation Graph"), EvalGraphProc},
653 {N_("Show Game List"), ShowGameListProc},
654 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
655 {"----", NothingProc},
656 {N_("Edit Tags"), EditTagsProc},
657 {N_("Edit Comment"), EditCommentProc},
658 {N_("ICS Input Box"), IcsInputBoxProc},
659 {N_("Pause"), PauseProc},
663 MenuItem actionMenu[] = {
664 {N_("Accept"), AcceptProc},
665 {N_("Decline"), DeclineProc},
666 {N_("Rematch"), RematchProc},
667 {"----", NothingProc},
668 {N_("Call Flag"), CallFlagProc},
669 {N_("Draw"), DrawProc},
670 {N_("Adjourn"), AdjournProc},
671 {N_("Abort"), AbortProc},
672 {N_("Resign"), ResignProc},
673 {"----", NothingProc},
674 {N_("Stop Observing"), StopObservingProc},
675 {N_("Stop Examining"), StopExaminingProc},
676 {N_("Upload to Examine"), UploadProc},
677 {"----", NothingProc},
678 {N_("Adjudicate to White"), AdjuWhiteProc},
679 {N_("Adjudicate to Black"), AdjuBlackProc},
680 {N_("Adjudicate Draw"), AdjuDrawProc},
684 MenuItem stepMenu[] = {
685 {N_("Backward"), BackwardProc},
686 {N_("Forward"), ForwardProc},
687 {N_("Back to Start"), ToStartProc},
688 {N_("Forward to End"), ToEndProc},
689 {N_("Revert"), RevertProc},
690 {N_("Annotate"), AnnotateProc},
691 {N_("Truncate Game"), TruncateGameProc},
692 {"----", NothingProc},
693 {N_("Move Now"), MoveNowProc},
694 {N_("Retract Move"), RetractMoveProc},
698 MenuItem optionsMenu[] = {
699 {N_("Flip View"), FlipViewProc},
700 {"----", NothingProc},
701 {N_("Adjudications ..."), EngineMenuProc},
702 {N_("General Settings ..."), UciMenuProc},
703 {N_("Engine #1 Settings ..."), FirstSettingsProc},
704 {N_("Engine #2 Settings ..."), SecondSettingsProc},
705 {N_("Time Control ..."), TimeControlProc},
706 {N_("Game List ..."), GameListOptionsPopUp},
707 {"----", NothingProc},
708 {N_("Always Queen"), AlwaysQueenProc},
709 {N_("Animate Dragging"), AnimateDraggingProc},
710 {N_("Animate Moving"), AnimateMovingProc},
711 {N_("Auto Comment"), AutocommProc},
712 {N_("Auto Flag"), AutoflagProc},
713 {N_("Auto Flip View"), AutoflipProc},
714 {N_("Auto Observe"), AutobsProc},
715 {N_("Auto Raise Board"), AutoraiseProc},
716 {N_("Auto Save"), AutosaveProc},
717 {N_("Blindfold"), BlindfoldProc},
718 {N_("Flash Moves"), FlashMovesProc},
719 {N_("Get Move List"), GetMoveListProc},
721 {N_("Highlight Dragging"), HighlightDraggingProc},
723 {N_("Highlight Last Move"), HighlightLastMoveProc},
724 {N_("Move Sound"), MoveSoundProc},
725 {N_("ICS Alarm"), IcsAlarmProc},
726 {N_("Old Save Style"), OldSaveStyleProc},
727 {N_("Periodic Updates"), PeriodicUpdatesProc},
728 {N_("Ponder Next Move"), PonderNextMoveProc},
729 {N_("Popup Exit Message"), PopupExitMessageProc},
730 {N_("Popup Move Errors"), PopupMoveErrorsProc},
731 {N_("Premove"), PremoveProc},
732 {N_("Quiet Play"), QuietPlayProc},
733 {N_("Show Coords"), ShowCoordsProc},
734 {N_("Hide Thinking"), HideThinkingProc},
735 {N_("Test Legality"), TestLegalityProc},
736 {"----", NothingProc},
737 {N_("Save Settings Now"), SaveSettingsProc},
738 {N_("Save Settings on Exit"), SaveOnExitProc},
742 MenuItem helpMenu[] = {
743 {N_("Info XBoard"), InfoProc},
744 {N_("Man XBoard"), ManProc},
745 {"----", NothingProc},
746 {N_("Hint"), HintProc},
747 {N_("Book"), BookProc},
748 {"----", NothingProc},
749 {N_("About XBoard"), AboutProc},
754 {N_("File"), fileMenu},
755 {N_("Mode"), modeMenu},
756 {N_("Action"), actionMenu},
757 {N_("Step"), stepMenu},
758 {N_("Options"), optionsMenu},
759 {N_("Help"), helpMenu},
763 #define PAUSE_BUTTON N_("P")
764 MenuItem buttonBar[] = {
767 {PAUSE_BUTTON, PauseProc},
773 #define PIECE_MENU_SIZE 18
774 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
775 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
776 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
777 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
778 N_("Empty square"), N_("Clear board") },
779 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
780 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
781 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
782 N_("Empty square"), N_("Clear board") }
784 /* must be in same order as PieceMenuStrings! */
785 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
786 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
787 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
788 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
789 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
790 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
791 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
792 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
793 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
796 #define DROP_MENU_SIZE 6
797 String dropMenuStrings[DROP_MENU_SIZE] = {
798 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
800 /* must be in same order as PieceMenuStrings! */
801 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
802 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
803 WhiteRook, WhiteQueen
811 DropMenuEnables dmEnables[] = {
829 { XtNborderWidth, 0 },
830 { XtNdefaultDistance, 0 },
834 { XtNborderWidth, 0 },
835 { XtNresizable, (XtArgVal) True },
839 { XtNborderWidth, 0 },
845 { XtNjustify, (XtArgVal) XtJustifyRight },
846 { XtNlabel, (XtArgVal) "..." },
847 { XtNresizable, (XtArgVal) True },
848 { XtNresize, (XtArgVal) False }
851 Arg messageArgs[] = {
852 { XtNjustify, (XtArgVal) XtJustifyLeft },
853 { XtNlabel, (XtArgVal) "..." },
854 { XtNresizable, (XtArgVal) True },
855 { XtNresize, (XtArgVal) False }
859 { XtNborderWidth, 0 },
860 { XtNjustify, (XtArgVal) XtJustifyLeft }
863 XtResource clientResources[] = {
864 { "flashCount", "flashCount", XtRInt, sizeof(int),
865 XtOffset(AppDataPtr, flashCount), XtRImmediate,
866 (XtPointer) FLASH_COUNT },
869 XrmOptionDescRec shellOptions[] = {
870 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
871 { "-flash", "flashCount", XrmoptionNoArg, "3" },
872 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
875 XtActionsRec boardActions[] = {
876 { "DrawPosition", DrawPositionProc },
877 { "HandleUserMove", HandleUserMove },
878 { "AnimateUserMove", AnimateUserMove },
879 { "HandlePV", HandlePV },
880 { "SelectPV", SelectPV },
881 { "StopPV", StopPV },
882 { "FileNameAction", FileNameAction },
883 { "AskQuestionProc", AskQuestionProc },
884 { "AskQuestionReplyAction", AskQuestionReplyAction },
885 { "PieceMenuPopup", PieceMenuPopup },
886 { "WhiteClock", WhiteClock },
887 { "BlackClock", BlackClock },
888 { "Iconify", Iconify },
889 { "ResetProc", ResetProc },
890 { "NewVariantProc", NewVariantProc },
891 { "LoadGameProc", LoadGameProc },
892 { "LoadNextGameProc", LoadNextGameProc },
893 { "LoadPrevGameProc", LoadPrevGameProc },
894 { "LoadSelectedProc", LoadSelectedProc },
895 { "SetFilterProc", SetFilterProc },
896 { "ReloadGameProc", ReloadGameProc },
897 { "LoadPositionProc", LoadPositionProc },
898 { "LoadNextPositionProc", LoadNextPositionProc },
899 { "LoadPrevPositionProc", LoadPrevPositionProc },
900 { "ReloadPositionProc", ReloadPositionProc },
901 { "CopyPositionProc", CopyPositionProc },
902 { "PastePositionProc", PastePositionProc },
903 { "CopyGameProc", CopyGameProc },
904 { "PasteGameProc", PasteGameProc },
905 { "SaveGameProc", SaveGameProc },
906 { "SavePositionProc", SavePositionProc },
907 { "MailMoveProc", MailMoveProc },
908 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
909 { "QuitProc", QuitProc },
910 { "MachineWhiteProc", MachineWhiteProc },
911 { "MachineBlackProc", MachineBlackProc },
912 { "AnalysisModeProc", AnalyzeModeProc },
913 { "AnalyzeFileProc", AnalyzeFileProc },
914 { "TwoMachinesProc", TwoMachinesProc },
915 { "IcsClientProc", IcsClientProc },
916 { "EditGameProc", EditGameProc },
917 { "EditPositionProc", EditPositionProc },
918 { "TrainingProc", EditPositionProc },
919 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
920 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
921 { "ShowGameListProc", ShowGameListProc },
922 { "ShowMoveListProc", HistoryShowProc},
923 { "EditTagsProc", EditCommentProc },
924 { "EditCommentProc", EditCommentProc },
925 { "IcsAlarmProc", IcsAlarmProc },
926 { "IcsInputBoxProc", IcsInputBoxProc },
927 { "PauseProc", PauseProc },
928 { "AcceptProc", AcceptProc },
929 { "DeclineProc", DeclineProc },
930 { "RematchProc", RematchProc },
931 { "CallFlagProc", CallFlagProc },
932 { "DrawProc", DrawProc },
933 { "AdjournProc", AdjournProc },
934 { "AbortProc", AbortProc },
935 { "ResignProc", ResignProc },
936 { "AdjuWhiteProc", AdjuWhiteProc },
937 { "AdjuBlackProc", AdjuBlackProc },
938 { "AdjuDrawProc", AdjuDrawProc },
939 { "EnterKeyProc", EnterKeyProc },
940 { "UpKeyProc", UpKeyProc },
941 { "DownKeyProc", DownKeyProc },
942 { "StopObservingProc", StopObservingProc },
943 { "StopExaminingProc", StopExaminingProc },
944 { "UploadProc", UploadProc },
945 { "BackwardProc", BackwardProc },
946 { "ForwardProc", ForwardProc },
947 { "ToStartProc", ToStartProc },
948 { "ToEndProc", ToEndProc },
949 { "RevertProc", RevertProc },
950 { "AnnotateProc", AnnotateProc },
951 { "TruncateGameProc", TruncateGameProc },
952 { "MoveNowProc", MoveNowProc },
953 { "RetractMoveProc", RetractMoveProc },
954 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
955 { "UciMenuProc", (XtActionProc) UciMenuProc },
956 { "TimeControlProc", (XtActionProc) TimeControlProc },
957 { "AlwaysQueenProc", AlwaysQueenProc },
958 { "AnimateDraggingProc", AnimateDraggingProc },
959 { "AnimateMovingProc", AnimateMovingProc },
960 { "AutoflagProc", AutoflagProc },
961 { "AutoflipProc", AutoflipProc },
962 { "AutobsProc", AutobsProc },
963 { "AutoraiseProc", AutoraiseProc },
964 { "AutosaveProc", AutosaveProc },
965 { "BlindfoldProc", BlindfoldProc },
966 { "FlashMovesProc", FlashMovesProc },
967 { "FlipViewProc", FlipViewProc },
968 { "GetMoveListProc", GetMoveListProc },
970 { "HighlightDraggingProc", HighlightDraggingProc },
972 { "HighlightLastMoveProc", HighlightLastMoveProc },
973 { "IcsAlarmProc", IcsAlarmProc },
974 { "MoveSoundProc", MoveSoundProc },
975 { "OldSaveStyleProc", OldSaveStyleProc },
976 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
977 { "PonderNextMoveProc", PonderNextMoveProc },
978 { "PopupExitMessageProc", PopupExitMessageProc },
979 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
980 { "PremoveProc", PremoveProc },
981 { "QuietPlayProc", QuietPlayProc },
982 { "ShowCoordsProc", ShowCoordsProc },
983 { "ShowThinkingProc", ShowThinkingProc },
984 { "HideThinkingProc", HideThinkingProc },
985 { "TestLegalityProc", TestLegalityProc },
986 { "SaveSettingsProc", SaveSettingsProc },
987 { "SaveOnExitProc", SaveOnExitProc },
988 { "InfoProc", InfoProc },
989 { "ManProc", ManProc },
990 { "HintProc", HintProc },
991 { "BookProc", BookProc },
992 { "AboutGameProc", AboutGameProc },
993 { "AboutProc", AboutProc },
994 { "DebugProc", DebugProc },
995 { "NothingProc", NothingProc },
996 { "CommentClick", (XtActionProc) CommentClick },
997 { "CommentPopDown", (XtActionProc) CommentPopDown },
998 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
999 { "TagsPopDown", (XtActionProc) TagsPopDown },
1000 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
1001 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
1002 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
1003 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
1004 { "GameListPopDown", (XtActionProc) GameListPopDown },
1005 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
1006 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1007 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
1008 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1009 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1010 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
1011 { "EnginePopDown", (XtActionProc) EnginePopDown },
1012 { "UciPopDown", (XtActionProc) UciPopDown },
1013 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
1014 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
1015 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
1016 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1019 char globalTranslations[] =
1020 ":<Key>F9: ResignProc() \n \
1021 :Ctrl<Key>n: ResetProc() \n \
1022 :Meta<Key>V: NewVariantProc() \n \
1023 :Ctrl<Key>o: LoadGameProc() \n \
1024 :Meta<Key>Next: LoadNextGameProc() \n \
1025 :Meta<Key>Prior: LoadPrevGameProc() \n \
1026 :Ctrl<Key>s: SaveGameProc() \n \
1027 :Ctrl<Key>c: CopyGameProc() \n \
1028 :Ctrl<Key>v: PasteGameProc() \n \
1029 :Ctrl<Key>O: LoadPositionProc() \n \
1030 :Shift Meta<Key>Next: LoadNextPositionProc() \n \
1031 :Shift Meta<Key>Prior: LoadPrevPositionProc() \n \
1032 :Ctrl<Key>S: SavePositionProc() \n \
1033 :Ctrl<Key>C: CopyPositionProc() \n \
1034 :Ctrl<Key>V: PastePositionProc() \n \
1035 :Ctrl<Key>q: QuitProc() \n \
1036 :Ctrl<Key>w: MachineWhiteProc() \n \
1037 :Ctrl<Key>b: MachineBlackProc() \n \
1038 :Ctrl<Key>t: TwoMachinesProc() \n \
1039 :Ctrl<Key>a: AnalysisModeProc() \n \
1040 :Ctrl<Key>f: AnalyzeFileProc() \n \
1041 :Ctrl<Key>e: EditGameProc() \n \
1042 :Ctrl<Key>E: EditPositionProc() \n \
1043 :Meta<Key>O: EngineOutputProc() \n \
1044 :Meta<Key>E: EvalGraphProc() \n \
1045 :Meta<Key>G: ShowGameListProc() \n \
1046 :Meta<Key>H: ShowMoveListProc() \n \
1047 :<Key>Pause: PauseProc() \n \
1048 :<Key>F3: AcceptProc() \n \
1049 :<Key>F4: DeclineProc() \n \
1050 :<Key>F12: RematchProc() \n \
1051 :<Key>F5: CallFlagProc() \n \
1052 :<Key>F6: DrawProc() \n \
1053 :<Key>F7: AdjournProc() \n \
1054 :<Key>F8: AbortProc() \n \
1055 :<Key>F10: StopObservingProc() \n \
1056 :<Key>F11: StopExaminingProc() \n \
1057 :Meta Ctrl<Key>F12: DebugProc() \n \
1058 :Meta<Key>End: ToEndProc() \n \
1059 :Meta<Key>Right: ForwardProc() \n \
1060 :Meta<Key>Home: ToStartProc() \n \
1061 :Meta<Key>Left: BackwardProc() \n \
1062 :Ctrl<Key>m: MoveNowProc() \n \
1063 :Ctrl<Key>x: RetractMoveProc() \n \
1064 :Meta<Key>J: EngineMenuProc() \n \
1065 :Meta<Key>U: UciMenuProc() \n \
1066 :Meta<Key>T: TimeControlProc() \n \
1067 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1068 :Ctrl<Key>F: AutoflagProc() \n \
1069 :Ctrl<Key>A: AnimateMovingProc() \n \
1070 :Ctrl<Key>P: PonderNextMoveProc() \n \
1071 :Ctrl<Key>L: TestLegalityProc() \n \
1072 :Ctrl<Key>H: HideThinkingProc() \n \
1073 :<Key>-: Iconify() \n \
1074 :<Key>F1: ManProc() \n \
1075 :<Key>F2: FlipViewProc() \n \
1076 <KeyDown>.: BackwardProc() \n \
1077 <KeyUp>.: ForwardProc() \n \
1078 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1079 \"Send to chess program:\",,1) \n \
1080 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1081 \"Send to second chess program:\",,2) \n";
1083 char boardTranslations[] =
1084 "<Btn1Down>: HandleUserMove(0) \n \
1085 Shift<Btn1Up>: HandleUserMove(1) \n \
1086 <Btn1Up>: HandleUserMove(0) \n \
1087 <Btn1Motion>: AnimateUserMove() \n \
1088 <Btn3Motion>: HandlePV() \n \
1089 <Btn3Up>: PieceMenuPopup(menuB) \n \
1090 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1091 PieceMenuPopup(menuB) \n \
1092 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1093 PieceMenuPopup(menuW) \n \
1094 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1095 PieceMenuPopup(menuW) \n \
1096 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1097 PieceMenuPopup(menuB) \n";
1099 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1100 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1102 char ICSInputTranslations[] =
1103 "<Key>Up: UpKeyProc() \n "
1104 "<Key>Down: DownKeyProc() \n "
1105 "<Key>Return: EnterKeyProc() \n";
1107 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1108 // as the widget is destroyed before the up-click can call extend-end
1109 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1111 String xboardResources[] = {
1112 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1113 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1114 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1119 /* Max possible square size */
1120 #define MAXSQSIZE 256
1122 static int xpm_avail[MAXSQSIZE];
1124 #ifdef HAVE_DIR_STRUCT
1126 /* Extract piece size from filename */
1128 xpm_getsize(name, len, ext)
1139 if ((p=strchr(name, '.')) == NULL ||
1140 StrCaseCmp(p+1, ext) != 0)
1146 while (*p && isdigit(*p))
1153 /* Setup xpm_avail */
1155 xpm_getavail(dirname, ext)
1163 for (i=0; i<MAXSQSIZE; ++i)
1166 if (appData.debugMode)
1167 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1169 dir = opendir(dirname);
1172 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1173 programName, dirname);
1177 while ((ent=readdir(dir)) != NULL) {
1178 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1179 if (i > 0 && i < MAXSQSIZE)
1189 xpm_print_avail(fp, ext)
1195 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1196 for (i=1; i<MAXSQSIZE; ++i) {
1202 /* Return XPM piecesize closest to size */
1204 xpm_closest_to(dirname, size, ext)
1210 int sm_diff = MAXSQSIZE;
1214 xpm_getavail(dirname, ext);
1216 if (appData.debugMode)
1217 xpm_print_avail(stderr, ext);
1219 for (i=1; i<MAXSQSIZE; ++i) {
1222 diff = (diff<0) ? -diff : diff;
1223 if (diff < sm_diff) {
1231 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1237 #else /* !HAVE_DIR_STRUCT */
1238 /* If we are on a system without a DIR struct, we can't
1239 read the directory, so we can't collect a list of
1240 filenames, etc., so we can't do any size-fitting. */
1242 xpm_closest_to(dirname, size, ext)
1247 fprintf(stderr, _("\
1248 Warning: No DIR structure found on this system --\n\
1249 Unable to autosize for XPM/XIM pieces.\n\
1250 Please report this error to frankm@hiwaay.net.\n\
1251 Include system type & operating system in message.\n"));
1254 #endif /* HAVE_DIR_STRUCT */
1256 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1257 "magenta", "cyan", "white" };
1261 TextColors textColors[(int)NColorClasses];
1263 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1265 parse_color(str, which)
1269 char *p, buf[100], *d;
1272 if (strlen(str) > 99) /* watch bounds on buf */
1277 for (i=0; i<which; ++i) {
1284 /* Could be looking at something like:
1286 .. in which case we want to stop on a comma also */
1287 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1291 return -1; /* Use default for empty field */
1294 if (which == 2 || isdigit(*p))
1297 while (*p && isalpha(*p))
1302 for (i=0; i<8; ++i) {
1303 if (!StrCaseCmp(buf, cnames[i]))
1304 return which? (i+40) : (i+30);
1306 if (!StrCaseCmp(buf, "default")) return -1;
1308 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1313 parse_cpair(cc, str)
1317 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1318 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1323 /* bg and attr are optional */
1324 textColors[(int)cc].bg = parse_color(str, 1);
1325 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1326 textColors[(int)cc].attr = 0;
1332 /* Arrange to catch delete-window events */
1333 Atom wm_delete_window;
1335 CatchDeleteWindow(Widget w, String procname)
1338 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1339 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1340 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1347 XtSetArg(args[0], XtNiconic, False);
1348 XtSetValues(shellWidget, args, 1);
1350 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1353 //---------------------------------------------------------------------------------------------------------
1354 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1357 #define CW_USEDEFAULT (1<<31)
1358 #define ICS_TEXT_MENU_SIZE 90
1359 #define DEBUG_FILE "xboard.debug"
1360 #define SetCurrentDirectory chdir
1361 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1365 // these two must some day move to frontend.h, when they are implemented
1366 Boolean GameListIsUp();
1368 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1371 // front-end part of option handling
1373 // [HGM] This platform-dependent table provides the location for storing the color info
1374 extern char *crWhite, * crBlack;
1378 &appData.whitePieceColor,
1379 &appData.blackPieceColor,
1380 &appData.lightSquareColor,
1381 &appData.darkSquareColor,
1382 &appData.highlightSquareColor,
1383 &appData.premoveHighlightColor,
1384 &appData.lowTimeWarningColor,
1395 // [HGM] font: keep a font for each square size, even non-stndard ones
1396 #define NUM_SIZES 18
1397 #define MAX_SIZE 130
1398 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1399 char *fontTable[NUM_FONTS][MAX_SIZE];
1402 ParseFont(char *name, int number)
1403 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1405 if(sscanf(name, "size%d:", &size)) {
1406 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1407 // defer processing it until we know if it matches our board size
1408 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1409 fontTable[number][size] = strdup(strchr(name, ':')+1);
1410 fontValid[number][size] = True;
1415 case 0: // CLOCK_FONT
1416 appData.clockFont = strdup(name);
1418 case 1: // MESSAGE_FONT
1419 appData.font = strdup(name);
1421 case 2: // COORD_FONT
1422 appData.coordFont = strdup(name);
1427 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1432 { // only 2 fonts currently
1433 appData.clockFont = CLOCK_FONT_NAME;
1434 appData.coordFont = COORD_FONT_NAME;
1435 appData.font = DEFAULT_FONT_NAME;
1440 { // no-op, until we identify the code for this already in XBoard and move it here
1444 ParseColor(int n, char *name)
1445 { // in XBoard, just copy the color-name string
1446 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1450 ParseTextAttribs(ColorClass cc, char *s)
1452 (&appData.colorShout)[cc] = strdup(s);
1456 ParseBoardSize(void *addr, char *name)
1458 appData.boardSize = strdup(name);
1463 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1467 SetCommPortDefaults()
1468 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1471 // [HGM] args: these three cases taken out to stay in front-end
1473 SaveFontArg(FILE *f, ArgDescriptor *ad)
1476 int i, n = (int)ad->argLoc;
1478 case 0: // CLOCK_FONT
1479 name = appData.clockFont;
1481 case 1: // MESSAGE_FONT
1482 name = appData.font;
1484 case 2: // COORD_FONT
1485 name = appData.coordFont;
1490 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1491 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1492 fontTable[n][squareSize] = strdup(name);
1493 fontValid[n][squareSize] = True;
1496 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1497 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1502 { // nothing to do, as the sounds are at all times represented by their text-string names already
1506 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1507 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1508 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1512 SaveColor(FILE *f, ArgDescriptor *ad)
1513 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1514 if(colorVariable[(int)ad->argLoc])
1515 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1519 SaveBoardSize(FILE *f, char *name, void *addr)
1520 { // wrapper to shield back-end from BoardSize & sizeInfo
1521 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1525 ParseCommPortSettings(char *s)
1526 { // no such option in XBoard (yet)
1529 extern Widget engineOutputShell;
1530 extern Widget tagsShell, editTagsShell;
1532 GetActualPlacement(Widget wg, WindowPlacement *wp)
1542 XtSetArg(args[i], XtNx, &x); i++;
1543 XtSetArg(args[i], XtNy, &y); i++;
1544 XtSetArg(args[i], XtNwidth, &w); i++;
1545 XtSetArg(args[i], XtNheight, &h); i++;
1546 XtGetValues(wg, args, i);
1555 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1556 // In XBoard this will have to wait until awareness of window parameters is implemented
1557 GetActualPlacement(shellWidget, &wpMain);
1558 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1559 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1560 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1561 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1562 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1563 else GetActualPlacement(editShell, &wpComment);
1564 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1565 else GetActualPlacement(editTagsShell, &wpTags);
1569 PrintCommPortSettings(FILE *f, char *name)
1570 { // This option does not exist in XBoard
1574 MySearchPath(char *installDir, char *name, char *fullname)
1575 { // just append installDir and name. Perhaps ExpandPath should be used here?
1576 name = ExpandPathName(name);
1577 if(name && name[0] == '/')
1578 safeStrCpy(fullname, name, MSG_SIZ );
1580 sprintf(fullname, "%s%c%s", installDir, '/', name);
1586 MyGetFullPathName(char *name, char *fullname)
1587 { // should use ExpandPath?
1588 name = ExpandPathName(name);
1589 safeStrCpy(fullname, name, MSG_SIZ );
1594 EnsureOnScreen(int *x, int *y, int minX, int minY)
1601 { // [HGM] args: allows testing if main window is realized from back-end
1602 return xBoardWindow != 0;
1606 PopUpStartupDialog()
1607 { // start menu not implemented in XBoard
1611 ConvertToLine(int argc, char **argv)
1613 static char line[128*1024], buf[1024];
1617 for(i=1; i<argc; i++)
1619 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1620 && argv[i][0] != '{' )
1621 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1623 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1624 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1627 line[strlen(line)-1] = NULLCHAR;
1631 //--------------------------------------------------------------------------------------------
1633 extern Boolean twoBoards, partnerUp;
1636 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1638 #define BoardSize int
1639 void InitDrawingSizes(BoardSize boardSize, int flags)
1640 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1641 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1643 XtGeometryResult gres;
1646 if(!formWidget) return;
1649 * Enable shell resizing.
1651 shellArgs[0].value = (XtArgVal) &w;
1652 shellArgs[1].value = (XtArgVal) &h;
1653 XtGetValues(shellWidget, shellArgs, 2);
1655 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1656 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1657 XtSetValues(shellWidget, &shellArgs[2], 4);
1659 XtSetArg(args[0], XtNdefaultDistance, &sep);
1660 XtGetValues(formWidget, args, 1);
1662 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1663 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1665 hOffset = boardWidth + 10;
1666 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1667 secondSegments[i] = gridSegments[i];
1668 secondSegments[i].x1 += hOffset;
1669 secondSegments[i].x2 += hOffset;
1672 XtSetArg(args[0], XtNwidth, boardWidth);
1673 XtSetArg(args[1], XtNheight, boardHeight);
1674 XtSetValues(boardWidget, args, 2);
1676 timerWidth = (boardWidth - sep) / 2;
1677 XtSetArg(args[0], XtNwidth, timerWidth);
1678 XtSetValues(whiteTimerWidget, args, 1);
1679 XtSetValues(blackTimerWidget, args, 1);
1681 XawFormDoLayout(formWidget, False);
1683 if (appData.titleInWindow) {
1685 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1686 XtSetArg(args[i], XtNheight, &h); i++;
1687 XtGetValues(titleWidget, args, i);
1689 w = boardWidth - 2*bor;
1691 XtSetArg(args[0], XtNwidth, &w);
1692 XtGetValues(menuBarWidget, args, 1);
1693 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1696 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1697 if (gres != XtGeometryYes && appData.debugMode) {
1699 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1700 programName, gres, w, h, wr, hr);
1704 XawFormDoLayout(formWidget, True);
1707 * Inhibit shell resizing.
1709 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1710 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1711 shellArgs[4].value = shellArgs[2].value = w;
1712 shellArgs[5].value = shellArgs[3].value = h;
1713 XtSetValues(shellWidget, &shellArgs[0], 6);
1715 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1718 for(i=0; i<4; i++) {
1720 for(p=0; p<=(int)WhiteKing; p++)
1721 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1722 if(gameInfo.variant == VariantShogi) {
1723 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1724 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1725 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1726 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1727 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1730 if(gameInfo.variant == VariantGothic) {
1731 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1734 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1735 xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
1736 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1739 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1740 for(p=0; p<=(int)WhiteKing; p++)
1741 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1742 if(gameInfo.variant == VariantShogi) {
1743 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1744 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1745 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1746 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1747 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1750 if(gameInfo.variant == VariantGothic) {
1751 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1754 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1755 ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
1756 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1761 for(i=0; i<2; i++) {
1763 for(p=0; p<=(int)WhiteKing; p++)
1764 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1765 if(gameInfo.variant == VariantShogi) {
1766 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1767 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1768 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1769 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1770 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1773 if(gameInfo.variant == VariantGothic) {
1774 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1777 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1778 pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
1779 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1794 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1795 XSetWindowAttributes window_attributes;
1797 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1798 XrmValue vFrom, vTo;
1799 XtGeometryResult gres;
1802 int forceMono = False;
1804 srandom(time(0)); // [HGM] book: make random truly random
1806 setbuf(stdout, NULL);
1807 setbuf(stderr, NULL);
1810 # if HAVE_LIBREADLINE
1811 /* install gnu-readline handler */
1812 rl_callback_handler_install("> ", ReadlineCompleteHandler);
1813 rl_readline_name="XBoard";
1816 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1817 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1821 programName = strrchr(argv[0], '/');
1822 if (programName == NULL)
1823 programName = argv[0];
1828 XtSetLanguageProc(NULL, NULL, NULL);
1829 bindtextdomain(PACKAGE, LOCALEDIR);
1830 textdomain(PACKAGE);
1834 XtAppInitialize(&appContext, "XBoard", shellOptions,
1835 XtNumber(shellOptions),
1836 &argc, argv, xboardResources, NULL, 0);
1837 appData.boardSize = "";
1838 InitAppData(ConvertToLine(argc, argv));
1840 if (p == NULL) p = "/tmp";
1841 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1842 gameCopyFilename = (char*) malloc(i);
1843 gamePasteFilename = (char*) malloc(i);
1844 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1845 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1847 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1848 clientResources, XtNumber(clientResources),
1851 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1852 static char buf[MSG_SIZ];
1853 EscapeExpand(buf, appData.initString);
1854 appData.initString = strdup(buf);
1855 EscapeExpand(buf, appData.secondInitString);
1856 appData.secondInitString = strdup(buf);
1857 EscapeExpand(buf, appData.firstComputerString);
1858 appData.firstComputerString = strdup(buf);
1859 EscapeExpand(buf, appData.secondComputerString);
1860 appData.secondComputerString = strdup(buf);
1863 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1866 if (chdir(chessDir) != 0) {
1867 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1873 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1874 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1875 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1876 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1879 setbuf(debugFP, NULL);
1882 /* [HGM,HR] make sure board size is acceptable */
1883 if(appData.NrFiles > BOARD_FILES ||
1884 appData.NrRanks > BOARD_RANKS )
1885 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1888 /* This feature does not work; animation needs a rewrite */
1889 appData.highlightDragging = FALSE;
1893 xDisplay = XtDisplay(shellWidget);
1894 xScreen = DefaultScreen(xDisplay);
1895 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1897 gameInfo.variant = StringToVariant(appData.variant);
1898 InitPosition(FALSE);
1901 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1903 if (isdigit(appData.boardSize[0])) {
1904 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1905 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1906 &fontPxlSize, &smallLayout, &tinyLayout);
1908 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1909 programName, appData.boardSize);
1913 /* Find some defaults; use the nearest known size */
1914 SizeDefaults *szd, *nearest;
1915 int distance = 99999;
1916 nearest = szd = sizeDefaults;
1917 while (szd->name != NULL) {
1918 if (abs(szd->squareSize - squareSize) < distance) {
1920 distance = abs(szd->squareSize - squareSize);
1921 if (distance == 0) break;
1925 if (i < 2) lineGap = nearest->lineGap;
1926 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1927 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1928 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1929 if (i < 6) smallLayout = nearest->smallLayout;
1930 if (i < 7) tinyLayout = nearest->tinyLayout;
1933 SizeDefaults *szd = sizeDefaults;
1934 if (*appData.boardSize == NULLCHAR) {
1935 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1936 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1939 if (szd->name == NULL) szd--;
1940 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1942 while (szd->name != NULL &&
1943 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1944 if (szd->name == NULL) {
1945 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1946 programName, appData.boardSize);
1950 squareSize = szd->squareSize;
1951 lineGap = szd->lineGap;
1952 clockFontPxlSize = szd->clockFontPxlSize;
1953 coordFontPxlSize = szd->coordFontPxlSize;
1954 fontPxlSize = szd->fontPxlSize;
1955 smallLayout = szd->smallLayout;
1956 tinyLayout = szd->tinyLayout;
1957 // [HGM] font: use defaults from settings file if available and not overruled
1959 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
1960 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
1961 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
1962 appData.font = fontTable[MESSAGE_FONT][squareSize];
1963 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
1964 appData.coordFont = fontTable[COORD_FONT][squareSize];
1966 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1967 if (strlen(appData.pixmapDirectory) > 0) {
1968 p = ExpandPathName(appData.pixmapDirectory);
1970 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1971 appData.pixmapDirectory);
1974 if (appData.debugMode) {
1975 fprintf(stderr, _("\
1976 XBoard square size (hint): %d\n\
1977 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1979 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1980 if (appData.debugMode) {
1981 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1984 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1986 /* [HR] height treated separately (hacked) */
1987 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1988 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1989 if (appData.showJail == 1) {
1990 /* Jail on top and bottom */
1991 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1992 XtSetArg(boardArgs[2], XtNheight,
1993 boardHeight + 2*(lineGap + squareSize));
1994 } else if (appData.showJail == 2) {
1996 XtSetArg(boardArgs[1], XtNwidth,
1997 boardWidth + 2*(lineGap + squareSize));
1998 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2001 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2002 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2006 * Determine what fonts to use.
2008 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2009 clockFontID = XLoadFont(xDisplay, appData.clockFont);
2010 clockFontStruct = XQueryFont(xDisplay, clockFontID);
2011 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2012 coordFontID = XLoadFont(xDisplay, appData.coordFont);
2013 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2014 appData.font = FindFont(appData.font, fontPxlSize);
2015 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
2016 countFontStruct = XQueryFont(xDisplay, countFontID);
2017 // appData.font = FindFont(appData.font, fontPxlSize);
2019 xdb = XtDatabase(xDisplay);
2020 XrmPutStringResource(&xdb, "*font", appData.font);
2023 * Detect if there are not enough colors available and adapt.
2025 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2026 appData.monoMode = True;
2029 if (!appData.monoMode) {
2030 vFrom.addr = (caddr_t) appData.lightSquareColor;
2031 vFrom.size = strlen(appData.lightSquareColor);
2032 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2033 if (vTo.addr == NULL) {
2034 appData.monoMode = True;
2037 lightSquareColor = *(Pixel *) vTo.addr;
2040 if (!appData.monoMode) {
2041 vFrom.addr = (caddr_t) appData.darkSquareColor;
2042 vFrom.size = strlen(appData.darkSquareColor);
2043 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2044 if (vTo.addr == NULL) {
2045 appData.monoMode = True;
2048 darkSquareColor = *(Pixel *) vTo.addr;
2051 if (!appData.monoMode) {
2052 vFrom.addr = (caddr_t) appData.whitePieceColor;
2053 vFrom.size = strlen(appData.whitePieceColor);
2054 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2055 if (vTo.addr == NULL) {
2056 appData.monoMode = True;
2059 whitePieceColor = *(Pixel *) vTo.addr;
2062 if (!appData.monoMode) {
2063 vFrom.addr = (caddr_t) appData.blackPieceColor;
2064 vFrom.size = strlen(appData.blackPieceColor);
2065 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2066 if (vTo.addr == NULL) {
2067 appData.monoMode = True;
2070 blackPieceColor = *(Pixel *) vTo.addr;
2074 if (!appData.monoMode) {
2075 vFrom.addr = (caddr_t) appData.highlightSquareColor;
2076 vFrom.size = strlen(appData.highlightSquareColor);
2077 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2078 if (vTo.addr == NULL) {
2079 appData.monoMode = True;
2082 highlightSquareColor = *(Pixel *) vTo.addr;
2086 if (!appData.monoMode) {
2087 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
2088 vFrom.size = strlen(appData.premoveHighlightColor);
2089 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2090 if (vTo.addr == NULL) {
2091 appData.monoMode = True;
2094 premoveHighlightColor = *(Pixel *) vTo.addr;
2099 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2102 if (appData.bitmapDirectory == NULL ||
2103 appData.bitmapDirectory[0] == NULLCHAR)
2104 appData.bitmapDirectory = DEF_BITMAP_DIR;
2107 if (appData.lowTimeWarning && !appData.monoMode) {
2108 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2109 vFrom.size = strlen(appData.lowTimeWarningColor);
2110 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2111 if (vTo.addr == NULL)
2112 appData.monoMode = True;
2114 lowTimeWarningColor = *(Pixel *) vTo.addr;
2117 if (appData.monoMode && appData.debugMode) {
2118 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2119 (unsigned long) XWhitePixel(xDisplay, xScreen),
2120 (unsigned long) XBlackPixel(xDisplay, xScreen));
2123 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2124 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2125 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2126 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2127 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2128 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2129 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2130 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2131 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2132 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2134 if (appData.colorize) {
2136 _("%s: can't parse color names; disabling colorization\n"),
2139 appData.colorize = FALSE;
2141 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2142 textColors[ColorNone].attr = 0;
2144 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2150 layoutName = "tinyLayout";
2151 } else if (smallLayout) {
2152 layoutName = "smallLayout";
2154 layoutName = "normalLayout";
2156 /* Outer layoutWidget is there only to provide a name for use in
2157 resources that depend on the layout style */
2159 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2160 layoutArgs, XtNumber(layoutArgs));
2162 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2163 formArgs, XtNumber(formArgs));
2164 XtSetArg(args[0], XtNdefaultDistance, &sep);
2165 XtGetValues(formWidget, args, 1);
2168 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2169 XtSetArg(args[0], XtNtop, XtChainTop);
2170 XtSetArg(args[1], XtNbottom, XtChainTop);
2171 XtSetArg(args[2], XtNright, XtChainLeft);
2172 XtSetValues(menuBarWidget, args, 3);
2174 widgetList[j++] = whiteTimerWidget =
2175 XtCreateWidget("whiteTime", labelWidgetClass,
2176 formWidget, timerArgs, XtNumber(timerArgs));
2177 XtSetArg(args[0], XtNfont, clockFontStruct);
2178 XtSetArg(args[1], XtNtop, XtChainTop);
2179 XtSetArg(args[2], XtNbottom, XtChainTop);
2180 XtSetValues(whiteTimerWidget, args, 3);
2182 widgetList[j++] = blackTimerWidget =
2183 XtCreateWidget("blackTime", labelWidgetClass,
2184 formWidget, timerArgs, XtNumber(timerArgs));
2185 XtSetArg(args[0], XtNfont, clockFontStruct);
2186 XtSetArg(args[1], XtNtop, XtChainTop);
2187 XtSetArg(args[2], XtNbottom, XtChainTop);
2188 XtSetValues(blackTimerWidget, args, 3);
2190 if (appData.titleInWindow) {
2191 widgetList[j++] = titleWidget =
2192 XtCreateWidget("title", labelWidgetClass, formWidget,
2193 titleArgs, XtNumber(titleArgs));
2194 XtSetArg(args[0], XtNtop, XtChainTop);
2195 XtSetArg(args[1], XtNbottom, XtChainTop);
2196 XtSetValues(titleWidget, args, 2);
2199 if (appData.showButtonBar) {
2200 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2201 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2202 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2203 XtSetArg(args[2], XtNtop, XtChainTop);
2204 XtSetArg(args[3], XtNbottom, XtChainTop);
2205 XtSetValues(buttonBarWidget, args, 4);
2208 widgetList[j++] = messageWidget =
2209 XtCreateWidget("message", labelWidgetClass, formWidget,
2210 messageArgs, XtNumber(messageArgs));
2211 XtSetArg(args[0], XtNtop, XtChainTop);
2212 XtSetArg(args[1], XtNbottom, XtChainTop);
2213 XtSetValues(messageWidget, args, 2);
2215 widgetList[j++] = boardWidget =
2216 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2217 XtNumber(boardArgs));
2219 XtManageChildren(widgetList, j);
2221 timerWidth = (boardWidth - sep) / 2;
2222 XtSetArg(args[0], XtNwidth, timerWidth);
2223 XtSetValues(whiteTimerWidget, args, 1);
2224 XtSetValues(blackTimerWidget, args, 1);
2226 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2227 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2228 XtGetValues(whiteTimerWidget, args, 2);
2230 if (appData.showButtonBar) {
2231 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2232 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2233 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2237 * formWidget uses these constraints but they are stored
2241 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2242 XtSetValues(menuBarWidget, args, i);
2243 if (appData.titleInWindow) {
2246 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2247 XtSetValues(whiteTimerWidget, args, i);
2249 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2250 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2251 XtSetValues(blackTimerWidget, args, i);
2253 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2254 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2255 XtSetValues(titleWidget, args, i);
2257 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2258 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2259 XtSetValues(messageWidget, args, i);
2260 if (appData.showButtonBar) {
2262 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2263 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2264 XtSetValues(buttonBarWidget, args, i);
2268 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2269 XtSetValues(whiteTimerWidget, args, i);
2271 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2272 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2273 XtSetValues(blackTimerWidget, args, i);
2275 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2276 XtSetValues(titleWidget, args, i);
2278 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2279 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2280 XtSetValues(messageWidget, args, i);
2281 if (appData.showButtonBar) {
2283 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2284 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2285 XtSetValues(buttonBarWidget, args, i);
2290 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2291 XtSetValues(whiteTimerWidget, args, i);
2293 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2294 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2295 XtSetValues(blackTimerWidget, args, i);
2297 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2298 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2299 XtSetValues(messageWidget, args, i);
2300 if (appData.showButtonBar) {
2302 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2303 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2304 XtSetValues(buttonBarWidget, args, i);
2308 XtSetArg(args[0], XtNfromVert, messageWidget);
2309 XtSetArg(args[1], XtNtop, XtChainTop);
2310 XtSetArg(args[2], XtNbottom, XtChainBottom);
2311 XtSetArg(args[3], XtNleft, XtChainLeft);
2312 XtSetArg(args[4], XtNright, XtChainRight);
2313 XtSetValues(boardWidget, args, 5);
2315 XtRealizeWidget(shellWidget);
2318 XtSetArg(args[0], XtNx, wpMain.x);
2319 XtSetArg(args[1], XtNy, wpMain.y);
2320 XtSetValues(shellWidget, args, 2);
2324 * Correct the width of the message and title widgets.
2325 * It is not known why some systems need the extra fudge term.
2326 * The value "2" is probably larger than needed.
2328 XawFormDoLayout(formWidget, False);
2330 #define WIDTH_FUDGE 2
2332 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2333 XtSetArg(args[i], XtNheight, &h); i++;
2334 XtGetValues(messageWidget, args, i);
2335 if (appData.showButtonBar) {
2337 XtSetArg(args[i], XtNwidth, &w); i++;
2338 XtGetValues(buttonBarWidget, args, i);
2339 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2341 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2344 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2345 if (gres != XtGeometryYes && appData.debugMode) {
2346 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2347 programName, gres, w, h, wr, hr);
2350 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2351 /* The size used for the child widget in layout lags one resize behind
2352 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2354 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2355 if (gres != XtGeometryYes && appData.debugMode) {
2356 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2357 programName, gres, w, h, wr, hr);
2360 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2361 XtSetArg(args[1], XtNright, XtChainRight);
2362 XtSetValues(messageWidget, args, 2);
2364 if (appData.titleInWindow) {
2366 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2367 XtSetArg(args[i], XtNheight, &h); i++;
2368 XtGetValues(titleWidget, args, i);
2370 w = boardWidth - 2*bor;
2372 XtSetArg(args[0], XtNwidth, &w);
2373 XtGetValues(menuBarWidget, args, 1);
2374 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2377 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2378 if (gres != XtGeometryYes && appData.debugMode) {
2380 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2381 programName, gres, w, h, wr, hr);
2384 XawFormDoLayout(formWidget, True);
2386 xBoardWindow = XtWindow(boardWidget);
2388 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2389 // not need to go into InitDrawingSizes().
2393 * Create X checkmark bitmap and initialize option menu checks.
2395 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2396 checkmark_bits, checkmark_width, checkmark_height);
2397 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2398 if (appData.alwaysPromoteToQueen) {
2399 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2402 if (appData.animateDragging) {
2403 XtSetValues(XtNameToWidget(menuBarWidget,
2404 "menuOptions.Animate Dragging"),
2407 if (appData.animate) {
2408 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2411 if (appData.autoComment) {
2412 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2415 if (appData.autoCallFlag) {
2416 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2419 if (appData.autoFlipView) {
2420 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2423 if (appData.autoObserve) {
2424 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2427 if (appData.autoRaiseBoard) {
2428 XtSetValues(XtNameToWidget(menuBarWidget,
2429 "menuOptions.Auto Raise Board"), args, 1);
2431 if (appData.autoSaveGames) {
2432 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2435 if (appData.saveGameFile[0] != NULLCHAR) {
2436 /* Can't turn this off from menu */
2437 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2439 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2443 if (appData.blindfold) {
2444 XtSetValues(XtNameToWidget(menuBarWidget,
2445 "menuOptions.Blindfold"), args, 1);
2447 if (appData.flashCount > 0) {
2448 XtSetValues(XtNameToWidget(menuBarWidget,
2449 "menuOptions.Flash Moves"),
2452 if (appData.getMoveList) {
2453 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2457 if (appData.highlightDragging) {
2458 XtSetValues(XtNameToWidget(menuBarWidget,
2459 "menuOptions.Highlight Dragging"),
2463 if (appData.highlightLastMove) {
2464 XtSetValues(XtNameToWidget(menuBarWidget,
2465 "menuOptions.Highlight Last Move"),
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.oldSaveStyle) {
2477 XtSetValues(XtNameToWidget(menuBarWidget,
2478 "menuOptions.Old Save Style"), 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.quietPlay) {
2501 XtSetValues(XtNameToWidget(menuBarWidget,
2502 "menuOptions.Quiet Play"), args, 1);
2504 if (appData.showCoords) {
2505 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2508 if (appData.hideThinkingFromHuman) {
2509 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2512 if (appData.testLegality) {
2513 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2516 if (saveSettingsOnExit) {
2517 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2524 ReadBitmap(&wIconPixmap, "icon_white.bm",
2525 icon_white_bits, icon_white_width, icon_white_height);
2526 ReadBitmap(&bIconPixmap, "icon_black.bm",
2527 icon_black_bits, icon_black_width, icon_black_height);
2528 iconPixmap = wIconPixmap;
2530 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2531 XtSetValues(shellWidget, args, i);
2534 * Create a cursor for the board widget.
2536 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2537 XChangeWindowAttributes(xDisplay, xBoardWindow,
2538 CWCursor, &window_attributes);
2541 * Inhibit shell resizing.
2543 shellArgs[0].value = (XtArgVal) &w;
2544 shellArgs[1].value = (XtArgVal) &h;
2545 XtGetValues(shellWidget, shellArgs, 2);
2546 shellArgs[4].value = shellArgs[2].value = w;
2547 shellArgs[5].value = shellArgs[3].value = h;
2548 XtSetValues(shellWidget, &shellArgs[2], 4);
2549 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2550 marginH = h - boardHeight;
2552 CatchDeleteWindow(shellWidget, "QuitProc");
2557 if (appData.bitmapDirectory[0] != NULLCHAR) {
2561 CreateXPMBoard(appData.liteBackTextureFile, 1);
2562 CreateXPMBoard(appData.darkBackTextureFile, 0);
2566 /* Create regular pieces */
2567 if (!useImages) CreatePieces();
2572 if (appData.animate || appData.animateDragging)
2575 XtAugmentTranslations(formWidget,
2576 XtParseTranslationTable(globalTranslations));
2577 XtAugmentTranslations(boardWidget,
2578 XtParseTranslationTable(boardTranslations));
2579 XtAugmentTranslations(whiteTimerWidget,
2580 XtParseTranslationTable(whiteTranslations));
2581 XtAugmentTranslations(blackTimerWidget,
2582 XtParseTranslationTable(blackTranslations));
2584 /* Why is the following needed on some versions of X instead
2585 * of a translation? */
2586 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2587 (XtEventHandler) EventProc, NULL);
2590 /* [AS] Restore layout */
2591 if( wpMoveHistory.visible ) {
2595 if( wpEvalGraph.visible )
2600 if( wpEngineOutput.visible ) {
2601 EngineOutputPopUp();
2606 if (errorExitStatus == -1) {
2607 if (appData.icsActive) {
2608 /* We now wait until we see "login:" from the ICS before
2609 sending the logon script (problems with timestamp otherwise) */
2610 /*ICSInitScript();*/
2611 if (appData.icsInputBox) ICSInputBoxPopUp();
2615 signal(SIGWINCH, TermSizeSigHandler);
2617 signal(SIGINT, IntSigHandler);
2618 signal(SIGTERM, IntSigHandler);
2619 if (*appData.cmailGameName != NULLCHAR) {
2620 signal(SIGUSR1, CmailSigHandler);
2623 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2625 XtSetKeyboardFocus(shellWidget, formWidget);
2627 XtAppMainLoop(appContext);
2628 if (appData.debugMode) fclose(debugFP); // [DM] debug
2635 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2636 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2638 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2639 unlink(gameCopyFilename);
2640 unlink(gamePasteFilename);
2642 # if HAVE_LIBREADLINE
2643 /* remove gnu-readline handler. */
2644 rl_callback_handler_remove();
2650 RETSIGTYPE TermSizeSigHandler(int sig)
2663 CmailSigHandler(sig)
2669 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2671 /* Activate call-back function CmailSigHandlerCallBack() */
2672 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2674 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2678 CmailSigHandlerCallBack(isr, closure, message, count, error)
2686 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2688 /**** end signal code ****/
2694 /* try to open the icsLogon script, either in the location given
2695 * or in the users HOME directory
2702 f = fopen(appData.icsLogon, "r");
2705 homedir = getenv("HOME");
2706 if (homedir != NULL)
2708 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2709 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2710 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2711 f = fopen(buf, "r");
2716 ProcessICSInitScript(f);
2718 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2727 EditCommentPopDown();
2742 if (!menuBarWidget) return;
2743 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2745 DisplayError("menuStep.Revert", 0);
2747 XtSetSensitive(w, !grey);
2749 w = XtNameToWidget(menuBarWidget, "menuStep.Annotate");
2751 DisplayError("menuStep.Annotate", 0);
2753 XtSetSensitive(w, !grey);
2758 SetMenuEnables(enab)
2762 if (!menuBarWidget) return;
2763 while (enab->name != NULL) {
2764 w = XtNameToWidget(menuBarWidget, enab->name);
2766 DisplayError(enab->name, 0);
2768 XtSetSensitive(w, enab->value);
2774 Enables icsEnables[] = {
2775 { "menuFile.Mail Move", False },
2776 { "menuFile.Reload CMail Message", False },
2777 { "menuMode.Machine Black", False },
2778 { "menuMode.Machine White", False },
2779 { "menuMode.Analysis Mode", False },
2780 { "menuMode.Analyze File", False },
2781 { "menuMode.Two Machines", False },
2783 { "menuHelp.Hint", False },
2784 { "menuHelp.Book", False },
2785 { "menuStep.Move Now", False },
2786 { "menuOptions.Periodic Updates", False },
2787 { "menuOptions.Hide Thinking", False },
2788 { "menuOptions.Ponder Next Move", False },
2790 { "menuStep.Annotate", False },
2794 Enables ncpEnables[] = {
2795 { "menuFile.Mail Move", False },
2796 { "menuFile.Reload CMail Message", False },
2797 { "menuMode.Machine White", False },
2798 { "menuMode.Machine Black", False },
2799 { "menuMode.Analysis Mode", False },
2800 { "menuMode.Analyze File", False },
2801 { "menuMode.Two Machines", False },
2802 { "menuMode.ICS Client", False },
2803 { "menuMode.ICS Input Box", False },
2804 { "Action", False },
2805 { "menuStep.Revert", False },
2806 { "menuStep.Annotate", False },
2807 { "menuStep.Move Now", False },
2808 { "menuStep.Retract Move", False },
2809 { "menuOptions.Auto Comment", False },
2810 { "menuOptions.Auto Flag", False },
2811 { "menuOptions.Auto Flip View", False },
2812 { "menuOptions.Auto Observe", False },
2813 { "menuOptions.Auto Raise Board", False },
2814 { "menuOptions.Get Move List", False },
2815 { "menuOptions.ICS Alarm", False },
2816 { "menuOptions.Move Sound", False },
2817 { "menuOptions.Quiet Play", False },
2818 { "menuOptions.Hide Thinking", False },
2819 { "menuOptions.Periodic Updates", False },
2820 { "menuOptions.Ponder Next Move", False },
2821 { "menuHelp.Hint", False },
2822 { "menuHelp.Book", False },
2826 Enables gnuEnables[] = {
2827 { "menuMode.ICS Client", False },
2828 { "menuMode.ICS Input Box", False },
2829 { "menuAction.Accept", False },
2830 { "menuAction.Decline", False },
2831 { "menuAction.Rematch", False },
2832 { "menuAction.Adjourn", False },
2833 { "menuAction.Stop Examining", False },
2834 { "menuAction.Stop Observing", False },
2835 { "menuAction.Upload to Examine", False },
2836 { "menuStep.Revert", False },
2837 { "menuStep.Annotate", False },
2838 { "menuOptions.Auto Comment", False },
2839 { "menuOptions.Auto Observe", False },
2840 { "menuOptions.Auto Raise Board", False },
2841 { "menuOptions.Get Move List", False },
2842 { "menuOptions.Premove", False },
2843 { "menuOptions.Quiet Play", False },
2845 /* The next two options rely on SetCmailMode being called *after* */
2846 /* SetGNUMode so that when GNU is being used to give hints these */
2847 /* menu options are still available */
2849 { "menuFile.Mail Move", False },
2850 { "menuFile.Reload CMail Message", False },
2854 Enables cmailEnables[] = {
2856 { "menuAction.Call Flag", False },
2857 { "menuAction.Draw", True },
2858 { "menuAction.Adjourn", False },
2859 { "menuAction.Abort", False },
2860 { "menuAction.Stop Observing", False },
2861 { "menuAction.Stop Examining", False },
2862 { "menuFile.Mail Move", True },
2863 { "menuFile.Reload CMail Message", True },
2867 Enables trainingOnEnables[] = {
2868 { "menuMode.Edit Comment", False },
2869 { "menuMode.Pause", False },
2870 { "menuStep.Forward", False },
2871 { "menuStep.Backward", False },
2872 { "menuStep.Forward to End", False },
2873 { "menuStep.Back to Start", False },
2874 { "menuStep.Move Now", False },
2875 { "menuStep.Truncate Game", False },
2879 Enables trainingOffEnables[] = {
2880 { "menuMode.Edit Comment", True },
2881 { "menuMode.Pause", True },
2882 { "menuStep.Forward", True },
2883 { "menuStep.Backward", True },
2884 { "menuStep.Forward to End", True },
2885 { "menuStep.Back to Start", True },
2886 { "menuStep.Move Now", True },
2887 { "menuStep.Truncate Game", True },
2891 Enables machineThinkingEnables[] = {
2892 { "menuFile.Load Game", False },
2893 { "menuFile.Load Next Game", False },
2894 { "menuFile.Load Previous Game", False },
2895 { "menuFile.Reload Same Game", False },
2896 { "menuFile.Paste Game", False },
2897 { "menuFile.Load Position", False },
2898 { "menuFile.Load Next Position", False },
2899 { "menuFile.Load Previous Position", False },
2900 { "menuFile.Reload Same Position", False },
2901 { "menuFile.Paste Position", False },
2902 { "menuMode.Machine White", False },
2903 { "menuMode.Machine Black", False },
2904 { "menuMode.Two Machines", False },
2905 { "menuStep.Retract Move", False },
2909 Enables userThinkingEnables[] = {
2910 { "menuFile.Load Game", True },
2911 { "menuFile.Load Next Game", True },
2912 { "menuFile.Load Previous Game", True },
2913 { "menuFile.Reload Same Game", True },
2914 { "menuFile.Paste Game", True },
2915 { "menuFile.Load Position", True },
2916 { "menuFile.Load Next Position", True },
2917 { "menuFile.Load Previous Position", True },
2918 { "menuFile.Reload Same Position", True },
2919 { "menuFile.Paste Position", True },
2920 { "menuMode.Machine White", True },
2921 { "menuMode.Machine Black", True },
2922 { "menuMode.Two Machines", True },
2923 { "menuStep.Retract Move", True },
2929 SetMenuEnables(icsEnables);
2932 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2933 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2940 SetMenuEnables(ncpEnables);
2946 SetMenuEnables(gnuEnables);
2952 SetMenuEnables(cmailEnables);
2958 SetMenuEnables(trainingOnEnables);
2959 if (appData.showButtonBar) {
2960 XtSetSensitive(buttonBarWidget, False);
2966 SetTrainingModeOff()
2968 SetMenuEnables(trainingOffEnables);
2969 if (appData.showButtonBar) {
2970 XtSetSensitive(buttonBarWidget, True);
2975 SetUserThinkingEnables()
2977 if (appData.noChessProgram) return;
2978 SetMenuEnables(userThinkingEnables);
2982 SetMachineThinkingEnables()
2984 if (appData.noChessProgram) return;
2985 SetMenuEnables(machineThinkingEnables);
2987 case MachinePlaysBlack:
2988 case MachinePlaysWhite:
2989 case TwoMachinesPlay:
2990 XtSetSensitive(XtNameToWidget(menuBarWidget,
2991 ModeToWidgetName(gameMode)), True);
2998 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2999 #define HISTORY_SIZE 64
\r
3000 static char *history[HISTORY_SIZE];
\r
3001 int histIn = 0, histP = 0;
\r
3004 SaveInHistory(char *cmd)
\r
3006 if (history[histIn] != NULL) {
\r
3007 free(history[histIn]);
\r
3008 history[histIn] = NULL;
\r
3010 if (*cmd == NULLCHAR) return;
\r
3011 history[histIn] = StrSave(cmd);
\r
3012 histIn = (histIn + 1) % HISTORY_SIZE;
\r
3013 if (history[histIn] != NULL) {
\r
3014 free(history[histIn]);
\r
3015 history[histIn] = NULL;
\r
3021 PrevInHistory(char *cmd)
\r
3024 if (histP == histIn) {
\r
3025 if (history[histIn] != NULL) free(history[histIn]);
\r
3026 history[histIn] = StrSave(cmd);
\r
3028 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
3029 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
3031 return history[histP];
\r
3037 if (histP == histIn) return NULL;
\r
3038 histP = (histP + 1) % HISTORY_SIZE;
\r
3039 return history[histP];
\r
3041 // end of borrowed code
\r
3043 #define Abs(n) ((n)<0 ? -(n) : (n))
3046 * Find a font that matches "pattern" that is as close as
3047 * possible to the targetPxlSize. Prefer fonts that are k
3048 * pixels smaller to fonts that are k pixels larger. The
3049 * pattern must be in the X Consortium standard format,
3050 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3051 * The return value should be freed with XtFree when no
3055 FindFont(pattern, targetPxlSize)
3059 char **fonts, *p, *best, *scalable, *scalableTail;
3060 int i, j, nfonts, minerr, err, pxlSize;
3063 char **missing_list;
3065 char *def_string, *base_fnt_lst, strInt[3];
3067 XFontStruct **fnt_list;
3069 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3070 snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
3071 p = strstr(pattern, "--");
3072 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3073 strcat(base_fnt_lst, strInt);
3074 strcat(base_fnt_lst, strchr(p + 2, '-'));
3076 if ((fntSet = XCreateFontSet(xDisplay,
3080 &def_string)) == NULL) {
3082 fprintf(stderr, _("Unable to create font set.\n"));
3086 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3088 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3090 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3091 programName, pattern);
3099 for (i=0; i<nfonts; i++) {
3102 if (*p != '-') continue;
3104 if (*p == NULLCHAR) break;
3105 if (*p++ == '-') j++;
3107 if (j < 7) continue;
3110 scalable = fonts[i];
3113 err = pxlSize - targetPxlSize;
3114 if (Abs(err) < Abs(minerr) ||
3115 (minerr > 0 && err < 0 && -err == minerr)) {
3121 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3122 /* If the error is too big and there is a scalable font,
3123 use the scalable font. */
3124 int headlen = scalableTail - scalable;
3125 p = (char *) XtMalloc(strlen(scalable) + 10);
3126 while (isdigit(*scalableTail)) scalableTail++;
3127 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3129 p = (char *) XtMalloc(strlen(best) + 2);
3130 safeStrCpy(p, best, strlen(best)+1 );
3132 if (appData.debugMode) {
3133 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3134 pattern, targetPxlSize, p);
3137 if (missing_count > 0)
3138 XFreeStringList(missing_list);
3139 XFreeFontSet(xDisplay, fntSet);
3141 XFreeFontNames(fonts);
3148 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3149 | GCBackground | GCFunction | GCPlaneMask;
3150 XGCValues gc_values;
3153 gc_values.plane_mask = AllPlanes;
3154 gc_values.line_width = lineGap;
3155 gc_values.line_style = LineSolid;
3156 gc_values.function = GXcopy;
3158 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3159 gc_values.background = XBlackPixel(xDisplay, xScreen);
3160 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3162 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3163 gc_values.background = XWhitePixel(xDisplay, xScreen);
3164 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3165 XSetFont(xDisplay, coordGC, coordFontID);
3167 // [HGM] make font for holdings counts (white on black0
3168 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3169 gc_values.background = XBlackPixel(xDisplay, xScreen);
3170 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3171 XSetFont(xDisplay, countGC, countFontID);
3173 if (appData.monoMode) {
3174 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3175 gc_values.background = XWhitePixel(xDisplay, xScreen);
3176 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3178 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3179 gc_values.background = XBlackPixel(xDisplay, xScreen);
3180 lightSquareGC = wbPieceGC
3181 = XtGetGC(shellWidget, value_mask, &gc_values);
3183 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3184 gc_values.background = XWhitePixel(xDisplay, xScreen);
3185 darkSquareGC = bwPieceGC
3186 = XtGetGC(shellWidget, value_mask, &gc_values);
3188 if (DefaultDepth(xDisplay, xScreen) == 1) {
3189 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3190 gc_values.function = GXcopyInverted;
3191 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3192 gc_values.function = GXcopy;
3193 if (XBlackPixel(xDisplay, xScreen) == 1) {
3194 bwPieceGC = darkSquareGC;
3195 wbPieceGC = copyInvertedGC;
3197 bwPieceGC = copyInvertedGC;
3198 wbPieceGC = lightSquareGC;
3202 gc_values.foreground = highlightSquareColor;
3203 gc_values.background = highlightSquareColor;
3204 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3206 gc_values.foreground = premoveHighlightColor;
3207 gc_values.background = premoveHighlightColor;
3208 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3210 gc_values.foreground = lightSquareColor;
3211 gc_values.background = darkSquareColor;
3212 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3214 gc_values.foreground = darkSquareColor;
3215 gc_values.background = lightSquareColor;
3216 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3218 gc_values.foreground = jailSquareColor;
3219 gc_values.background = jailSquareColor;
3220 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3222 gc_values.foreground = whitePieceColor;
3223 gc_values.background = darkSquareColor;
3224 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3226 gc_values.foreground = whitePieceColor;
3227 gc_values.background = lightSquareColor;
3228 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3230 gc_values.foreground = whitePieceColor;
3231 gc_values.background = jailSquareColor;
3232 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3234 gc_values.foreground = blackPieceColor;
3235 gc_values.background = darkSquareColor;
3236 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3238 gc_values.foreground = blackPieceColor;
3239 gc_values.background = lightSquareColor;
3240 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3242 gc_values.foreground = blackPieceColor;
3243 gc_values.background = jailSquareColor;
3244 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3248 void loadXIM(xim, xmask, filename, dest, mask)
3261 fp = fopen(filename, "rb");
3263 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3270 for (y=0; y<h; ++y) {
3271 for (x=0; x<h; ++x) {
3276 XPutPixel(xim, x, y, blackPieceColor);
3278 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3281 XPutPixel(xim, x, y, darkSquareColor);
3283 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3286 XPutPixel(xim, x, y, whitePieceColor);
3288 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3291 XPutPixel(xim, x, y, lightSquareColor);
3293 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3299 /* create Pixmap of piece */
3300 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3302 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3305 /* create Pixmap of clipmask
3306 Note: We assume the white/black pieces have the same
3307 outline, so we make only 6 masks. This is okay
3308 since the XPM clipmask routines do the same. */
3310 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3312 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3315 /* now create the 1-bit version */
3316 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3319 values.foreground = 1;
3320 values.background = 0;
3322 /* Don't use XtGetGC, not read only */
3323 maskGC = XCreateGC(xDisplay, *mask,
3324 GCForeground | GCBackground, &values);
3325 XCopyPlane(xDisplay, temp, *mask, maskGC,
3326 0, 0, squareSize, squareSize, 0, 0, 1);
3327 XFreePixmap(xDisplay, temp);
3332 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3334 void CreateXIMPieces()
3339 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3344 /* The XSynchronize calls were copied from CreatePieces.
3345 Not sure if needed, but can't hurt */
3346 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3349 /* temp needed by loadXIM() */
3350 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3351 0, 0, ss, ss, AllPlanes, XYPixmap);
3353 if (strlen(appData.pixmapDirectory) == 0) {
3357 if (appData.monoMode) {
3358 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3362 fprintf(stderr, _("\nLoading XIMs...\n"));
3364 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3365 fprintf(stderr, "%d", piece+1);
3366 for (kind=0; kind<4; kind++) {
3367 fprintf(stderr, ".");
3368 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3369 ExpandPathName(appData.pixmapDirectory),
3370 piece <= (int) WhiteKing ? "" : "w",
3371 pieceBitmapNames[piece],
3373 ximPieceBitmap[kind][piece] =
3374 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3375 0, 0, ss, ss, AllPlanes, XYPixmap);
3376 if (appData.debugMode)
3377 fprintf(stderr, _("(File:%s:) "), buf);
3378 loadXIM(ximPieceBitmap[kind][piece],
3380 &(xpmPieceBitmap2[kind][piece]),
3381 &(ximMaskPm2[piece]));
3382 if(piece <= (int)WhiteKing)
3383 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3385 fprintf(stderr," ");
3387 /* Load light and dark squares */
3388 /* If the LSQ and DSQ pieces don't exist, we will
3389 draw them with solid squares. */
3390 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3391 if (access(buf, 0) != 0) {
3395 fprintf(stderr, _("light square "));
3397 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3398 0, 0, ss, ss, AllPlanes, XYPixmap);
3399 if (appData.debugMode)
3400 fprintf(stderr, _("(File:%s:) "), buf);
3402 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3403 fprintf(stderr, _("dark square "));
3404 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3405 ExpandPathName(appData.pixmapDirectory), ss);
3406 if (appData.debugMode)
3407 fprintf(stderr, _("(File:%s:) "), buf);
3409 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3410 0, 0, ss, ss, AllPlanes, XYPixmap);
3411 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3412 xpmJailSquare = xpmLightSquare;
3414 fprintf(stderr, _("Done.\n"));
3416 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3420 void CreateXPMBoard(char *s, int kind)
3424 if(s == NULL || *s == 0 || *s == '*') return;
3425 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3426 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3430 void CreateXPMPieces()
3434 u_int ss = squareSize;
3436 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3437 XpmColorSymbol symbols[4];
3439 /* The XSynchronize calls were copied from CreatePieces.
3440 Not sure if needed, but can't hurt */
3441 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3443 /* Setup translations so piece colors match square colors */
3444 symbols[0].name = "light_piece";
3445 symbols[0].value = appData.whitePieceColor;
3446 symbols[1].name = "dark_piece";
3447 symbols[1].value = appData.blackPieceColor;
3448 symbols[2].name = "light_square";
3449 symbols[2].value = appData.lightSquareColor;
3450 symbols[3].name = "dark_square";
3451 symbols[3].value = appData.darkSquareColor;
3453 attr.valuemask = XpmColorSymbols;
3454 attr.colorsymbols = symbols;
3455 attr.numsymbols = 4;
3457 if (appData.monoMode) {
3458 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3462 if (strlen(appData.pixmapDirectory) == 0) {
3463 XpmPieces* pieces = builtInXpms;
3466 while (pieces->size != squareSize && pieces->size) pieces++;
3467 if (!pieces->size) {
3468 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3471 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3472 for (kind=0; kind<4; kind++) {
3474 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3475 pieces->xpm[piece][kind],
3476 &(xpmPieceBitmap2[kind][piece]),
3477 NULL, &attr)) != 0) {
3478 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3482 if(piece <= (int) WhiteKing)
3483 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3487 xpmJailSquare = xpmLightSquare;
3491 fprintf(stderr, _("\nLoading XPMs...\n"));
3494 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3495 fprintf(stderr, "%d ", piece+1);
3496 for (kind=0; kind<4; kind++) {
3497 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3498 ExpandPathName(appData.pixmapDirectory),
3499 piece > (int) WhiteKing ? "w" : "",
3500 pieceBitmapNames[piece],
3502 if (appData.debugMode) {
3503 fprintf(stderr, _("(File:%s:) "), buf);
3505 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3506 &(xpmPieceBitmap2[kind][piece]),
3507 NULL, &attr)) != 0) {
3508 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3509 // [HGM] missing: read of unorthodox piece failed; substitute King.
3510 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3511 ExpandPathName(appData.pixmapDirectory),
3513 if (appData.debugMode) {
3514 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3516 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3517 &(xpmPieceBitmap2[kind][piece]),
3521 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3526 if(piece <= (int) WhiteKing)
3527 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3530 /* Load light and dark squares */
3531 /* If the LSQ and DSQ pieces don't exist, we will
3532 draw them with solid squares. */
3533 fprintf(stderr, _("light square "));
3534 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3535 if (access(buf, 0) != 0) {
3539 if (appData.debugMode)
3540 fprintf(stderr, _("(File:%s:) "), buf);
3542 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3543 &xpmLightSquare, NULL, &attr)) != 0) {
3544 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3547 fprintf(stderr, _("dark square "));
3548 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3549 ExpandPathName(appData.pixmapDirectory), ss);
3550 if (appData.debugMode) {
3551 fprintf(stderr, _("(File:%s:) "), buf);
3553 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3554 &xpmDarkSquare, NULL, &attr)) != 0) {
3555 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3559 xpmJailSquare = xpmLightSquare;
3560 fprintf(stderr, _("Done.\n"));
3562 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3565 #endif /* HAVE_LIBXPM */
3568 /* No built-in bitmaps */
3573 u_int ss = squareSize;
3575 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3578 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3579 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3580 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3581 pieceBitmapNames[piece],
3582 ss, kind == SOLID ? 's' : 'o');
3583 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3584 if(piece <= (int)WhiteKing)
3585 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3589 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3593 /* With built-in bitmaps */
3596 BuiltInBits* bib = builtInBits;
3599 u_int ss = squareSize;
3601 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3604 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3606 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3607 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3608 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3609 pieceBitmapNames[piece],
3610 ss, kind == SOLID ? 's' : 'o');
3611 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3612 bib->bits[kind][piece], ss, ss);
3613 if(piece <= (int)WhiteKing)
3614 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3618 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3623 void ReadBitmap(pm, name, bits, wreq, hreq)
3626 unsigned char bits[];
3632 char msg[MSG_SIZ], fullname[MSG_SIZ];
3634 if (*appData.bitmapDirectory != NULLCHAR) {
3635 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3636 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3637 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3638 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3639 &w, &h, pm, &x_hot, &y_hot);
3640 fprintf(stderr, "load %s\n", name);
3641 if (errcode != BitmapSuccess) {
3643 case BitmapOpenFailed:
3644 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3646 case BitmapFileInvalid:
3647 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3649 case BitmapNoMemory:
3650 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3654 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3658 fprintf(stderr, _("%s: %s...using built-in\n"),
3660 } else if (w != wreq || h != hreq) {
3662 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3663 programName, fullname, w, h, wreq, hreq);
3669 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3678 if (lineGap == 0) return;
3680 /* [HR] Split this into 2 loops for non-square boards. */
3682 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3683 gridSegments[i].x1 = 0;
3684 gridSegments[i].x2 =
3685 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3686 gridSegments[i].y1 = gridSegments[i].y2
3687 = lineGap / 2 + (i * (squareSize + lineGap));
3690 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3691 gridSegments[j + i].y1 = 0;
3692 gridSegments[j + i].y2 =
3693 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3694 gridSegments[j + i].x1 = gridSegments[j + i].x2
3695 = lineGap / 2 + (j * (squareSize + lineGap));
3699 static void MenuBarSelect(w, addr, index)
3704 XtActionProc proc = (XtActionProc) addr;
3706 (proc)(NULL, NULL, NULL, NULL);
3709 void CreateMenuBarPopup(parent, name, mb)
3719 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3722 XtSetArg(args[j], XtNleftMargin, 20); j++;
3723 XtSetArg(args[j], XtNrightMargin, 20); j++;
3725 while (mi->string != NULL) {
3726 if (strcmp(mi->string, "----") == 0) {
3727 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3730 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3731 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3733 XtAddCallback(entry, XtNcallback,
3734 (XtCallbackProc) MenuBarSelect,
3735 (caddr_t) mi->proc);
3741 Widget CreateMenuBar(mb)
3745 Widget anchor, menuBar;
3747 char menuName[MSG_SIZ];
3750 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3751 XtSetArg(args[j], XtNvSpace, 0); j++;
3752 XtSetArg(args[j], XtNborderWidth, 0); j++;
3753 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3754 formWidget, args, j);
3756 while (mb->name != NULL) {
3757 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3758 strncat(menuName, mb->name, MSG_SIZ - strlen(menuName) - 1);
3760 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3763 shortName[0] = _(mb->name)[0];
3764 shortName[1] = NULLCHAR;
3765 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3768 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3771 XtSetArg(args[j], XtNborderWidth, 0); j++;
3772 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3774 CreateMenuBarPopup(menuBar, menuName, mb);
3780 Widget CreateButtonBar(mi)
3784 Widget button, buttonBar;
3788 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3790 XtSetArg(args[j], XtNhSpace, 0); j++;
3792 XtSetArg(args[j], XtNborderWidth, 0); j++;
3793 XtSetArg(args[j], XtNvSpace, 0); j++;
3794 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3795 formWidget, args, j);
3797 while (mi->string != NULL) {
3800 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3801 XtSetArg(args[j], XtNborderWidth, 0); j++;
3803 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3804 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3805 buttonBar, args, j);
3806 XtAddCallback(button, XtNcallback,
3807 (XtCallbackProc) MenuBarSelect,
3808 (caddr_t) mi->proc);
3815 CreatePieceMenu(name, color)
3822 ChessSquare selection;
3824 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3825 boardWidget, args, 0);
3827 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3828 String item = pieceMenuStrings[color][i];
3830 if (strcmp(item, "----") == 0) {
3831 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3834 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3835 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3837 selection = pieceMenuTranslation[color][i];
3838 XtAddCallback(entry, XtNcallback,
3839 (XtCallbackProc) PieceMenuSelect,
3840 (caddr_t) selection);
3841 if (selection == WhitePawn || selection == BlackPawn) {
3842 XtSetArg(args[0], XtNpopupOnEntry, entry);
3843 XtSetValues(menu, args, 1);
3856 ChessSquare selection;
3858 whitePieceMenu = CreatePieceMenu("menuW", 0);
3859 blackPieceMenu = CreatePieceMenu("menuB", 1);
3861 XtRegisterGrabAction(PieceMenuPopup, True,
3862 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3863 GrabModeAsync, GrabModeAsync);
3865 XtSetArg(args[0], XtNlabel, _("Drop"));
3866 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3867 boardWidget, args, 1);
3868 for (i = 0; i < DROP_MENU_SIZE; i++) {
3869 String item = dropMenuStrings[i];
3871 if (strcmp(item, "----") == 0) {
3872 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3875 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3876 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3878 selection = dropMenuTranslation[i];
3879 XtAddCallback(entry, XtNcallback,
3880 (XtCallbackProc) DropMenuSelect,
3881 (caddr_t) selection);
3886 void SetupDropMenu()
3894 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3895 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3896 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3897 dmEnables[i].piece);
3898 XtSetSensitive(entry, p != NULL || !appData.testLegality
3899 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3900 && !appData.icsActive));
3902 while (p && *p++ == dmEnables[i].piece) count++;
3903 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3905 XtSetArg(args[j], XtNlabel, label); j++;
3906 XtSetValues(entry, args, j);
3910 void PieceMenuPopup(w, event, params, num_params)
3914 Cardinal *num_params;
3916 String whichMenu; int menuNr;
3917 if (event->type == ButtonRelease)
3918 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3919 else if (event->type == ButtonPress)
3920 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3922 case 0: whichMenu = params[0]; break;
3923 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3925 case -1: if (errorUp) ErrorPopDown();
3928 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3931 static void PieceMenuSelect(w, piece, junk)
3936 if (pmFromX < 0 || pmFromY < 0) return;
3937 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3940 static void DropMenuSelect(w, piece, junk)
3945 if (pmFromX < 0 || pmFromY < 0) return;
3946 DropMenuEvent(piece, pmFromX, pmFromY);
3949 void WhiteClock(w, event, prms, nprms)
3955 if (gameMode == EditPosition || gameMode == IcsExamining) {
3956 SetWhiteToPlayEvent();
3957 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3962 void BlackClock(w, event, prms, nprms)
3968 if (gameMode == EditPosition || gameMode == IcsExamining) {
3969 SetBlackToPlayEvent();
3970 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3977 * If the user selects on a border boundary, return -1; if off the board,
3978 * return -2. Otherwise map the event coordinate to the square.
3980 int EventToSquare(x, limit)
3988 if ((x % (squareSize + lineGap)) >= squareSize)
3990 x /= (squareSize + lineGap);
3996 static void do_flash_delay(msec)
4002 static void drawHighlight(file, rank, gc)
4008 if (lineGap == 0 || appData.blindfold) return;
4011 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
4012 (squareSize + lineGap);
4013 y = lineGap/2 + rank * (squareSize + lineGap);
4015 x = lineGap/2 + file * (squareSize + lineGap);
4016 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
4017 (squareSize + lineGap);
4020 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
4021 squareSize+lineGap, squareSize+lineGap);
4024 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
4025 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4028 SetHighlights(fromX, fromY, toX, toY)
4029 int fromX, fromY, toX, toY;
4031 if (hi1X != fromX || hi1Y != fromY) {
4032 if (hi1X >= 0 && hi1Y >= 0) {
4033 drawHighlight(hi1X, hi1Y, lineGC);
4035 } // [HGM] first erase both, then draw new!
4036 if (hi2X != toX || hi2Y != toY) {
4037 if (hi2X >= 0 && hi2Y >= 0) {
4038 drawHighlight(hi2X, hi2Y, lineGC);
4041 if (hi1X != fromX || hi1Y != fromY) {
4042 if (fromX >= 0 && fromY >= 0) {
4043 drawHighlight(fromX, fromY, highlineGC);
4046 if (hi2X != toX || hi2Y != toY) {
4047 if (toX >= 0 && toY >= 0) {
4048 drawHighlight(toX, toY, highlineGC);
4060 SetHighlights(-1, -1, -1, -1);
4065 SetPremoveHighlights(fromX, fromY, toX, toY)
4066 int fromX, fromY, toX, toY;
4068 if (pm1X != fromX || pm1Y != fromY) {
4069 if (pm1X >= 0 && pm1Y >= 0) {
4070 drawHighlight(pm1X, pm1Y, lineGC);
4072 if (fromX >= 0 && fromY >= 0) {
4073 drawHighlight(fromX, fromY, prelineGC);
4076 if (pm2X != toX || pm2Y != toY) {
4077 if (pm2X >= 0 && pm2Y >= 0) {
4078 drawHighlight(pm2X, pm2Y, lineGC);
4080 if (toX >= 0 && toY >= 0) {
4081 drawHighlight(toX, toY, prelineGC);
4091 ClearPremoveHighlights()
4093 SetPremoveHighlights(-1, -1, -1, -1);
4096 static int CutOutSquare(x, y, x0, y0, kind)
4097 int x, y, *x0, *y0, kind;
4099 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
4100 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
4102 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
4103 if(textureW[kind] < W*squareSize)
4104 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
4106 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
4107 if(textureH[kind] < H*squareSize)
4108 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
4110 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
4114 static void BlankSquare(x, y, color, piece, dest, fac)
4115 int x, y, color, fac;
4118 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
4120 if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
4121 XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
4122 squareSize, squareSize, x*fac, y*fac);
4124 if (useImages && useImageSqs) {
4128 pm = xpmLightSquare;
4133 case 2: /* neutral */
4138 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4139 squareSize, squareSize, x*fac, y*fac);
4149 case 2: /* neutral */
4154 XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
4159 I split out the routines to draw a piece so that I could
4160 make a generic flash routine.
4162 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4164 int square_color, x, y;
4167 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4168 switch (square_color) {
4170 case 2: /* neutral */
4172 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4173 ? *pieceToOutline(piece)
4174 : *pieceToSolid(piece),
4175 dest, bwPieceGC, 0, 0,
4176 squareSize, squareSize, x, y);
4179 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4180 ? *pieceToSolid(piece)
4181 : *pieceToOutline(piece),
4182 dest, wbPieceGC, 0, 0,
4183 squareSize, squareSize, x, y);
4188 static void monoDrawPiece(piece, square_color, x, y, dest)
4190 int square_color, x, y;
4193 switch (square_color) {
4195 case 2: /* neutral */
4197 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4198 ? *pieceToOutline(piece)
4199 : *pieceToSolid(piece),
4200 dest, bwPieceGC, 0, 0,
4201 squareSize, squareSize, x, y, 1);
4204 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4205 ? *pieceToSolid(piece)
4206 : *pieceToOutline(piece),
4207 dest, wbPieceGC, 0, 0,
4208 squareSize, squareSize, x, y, 1);
4213 static void colorDrawPiece(piece, square_color, x, y, dest)
4215 int square_color, x, y;
4218 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4219 switch (square_color) {
4221 XCopyPlane(xDisplay, *pieceToSolid(piece),
4222 dest, (int) piece < (int) BlackPawn
4223 ? wlPieceGC : blPieceGC, 0, 0,
4224 squareSize, squareSize, x, y, 1);
4227 XCopyPlane(xDisplay, *pieceToSolid(piece),
4228 dest, (int) piece < (int) BlackPawn
4229 ? wdPieceGC : bdPieceGC, 0, 0,
4230 squareSize, squareSize, x, y, 1);
4232 case 2: /* neutral */
4234 XCopyPlane(xDisplay, *pieceToSolid(piece),
4235 dest, (int) piece < (int) BlackPawn
4236 ? wjPieceGC : bjPieceGC, 0, 0,
4237 squareSize, squareSize, x, y, 1);
4242 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4244 int square_color, x, y;
4247 int kind, p = piece;
4249 switch (square_color) {
4251 case 2: /* neutral */
4253 if ((int)piece < (int) BlackPawn) {
4261 if ((int)piece < (int) BlackPawn) {
4269 if(appData.upsideDown && flipView) kind ^= 2; // swap white and black pieces
4270 if(useTexture & square_color+1) {
4271 BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
4272 XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
4273 XSetClipOrigin(xDisplay, wlPieceGC, x, y);
4274 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);
4275 XSetClipMask(xDisplay, wlPieceGC, None);
4276 XSetClipOrigin(xDisplay, wlPieceGC, 0, 0);
4278 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4279 dest, wlPieceGC, 0, 0,
4280 squareSize, squareSize, x, y);
4283 typedef void (*DrawFunc)();
4285 DrawFunc ChooseDrawFunc()
4287 if (appData.monoMode) {
4288 if (DefaultDepth(xDisplay, xScreen) == 1) {
4289 return monoDrawPiece_1bit;
4291 return monoDrawPiece;
4295 return colorDrawPieceImage;
4297 return colorDrawPiece;
4301 /* [HR] determine square color depending on chess variant. */
4302 static int SquareColor(row, column)
4307 if (gameInfo.variant == VariantXiangqi) {
4308 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4310 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4312 } else if (row <= 4) {
4318 square_color = ((column + row) % 2) == 1;
4321 /* [hgm] holdings: next line makes all holdings squares light */
4322 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4324 return square_color;
4327 void DrawSquare(row, column, piece, do_flash)
4328 int row, column, do_flash;
4331 int square_color, x, y, direction, font_ascent, font_descent;
4334 XCharStruct overall;
4338 /* Calculate delay in milliseconds (2-delays per complete flash) */
4339 flash_delay = 500 / appData.flashRate;
4342 x = lineGap + ((BOARD_WIDTH-1)-column) *
4343 (squareSize + lineGap);
4344 y = lineGap + row * (squareSize + lineGap);
4346 x = lineGap + column * (squareSize + lineGap);
4347 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4348 (squareSize + lineGap);
4351 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4353 square_color = SquareColor(row, column);
4355 if ( // [HGM] holdings: blank out area between board and holdings
4356 column == BOARD_LEFT-1 || column == BOARD_RGHT
4357 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4358 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4359 BlankSquare(x, y, 2, EmptySquare, xBoardWindow, 1);
4361 // [HGM] print piece counts next to holdings
4362 string[1] = NULLCHAR;
4363 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4364 string[0] = '0' + piece;
4365 XTextExtents(countFontStruct, string, 1, &direction,
4366 &font_ascent, &font_descent, &overall);
4367 if (appData.monoMode) {
4368 XDrawImageString(xDisplay, xBoardWindow, countGC,
4369 x + squareSize - overall.width - 2,
4370 y + font_ascent + 1, string, 1);
4372 XDrawString(xDisplay, xBoardWindow, countGC,
4373 x + squareSize - overall.width - 2,
4374 y + font_ascent + 1, string, 1);
4377 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4378 string[0] = '0' + piece;
4379 XTextExtents(countFontStruct, string, 1, &direction,
4380 &font_ascent, &font_descent, &overall);
4381 if (appData.monoMode) {
4382 XDrawImageString(xDisplay, xBoardWindow, countGC,
4383 x + 2, y + font_ascent + 1, string, 1);
4385 XDrawString(xDisplay, xBoardWindow, countGC,
4386 x + 2, y + font_ascent + 1, string, 1);
4390 if (piece == EmptySquare || appData.blindfold) {
4391 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4393 drawfunc = ChooseDrawFunc();
4394 if (do_flash && appData.flashCount > 0) {
4395 for (i=0; i<appData.flashCount; ++i) {
4397 drawfunc(piece, square_color, x, y, xBoardWindow);
4398 XSync(xDisplay, False);
4399 do_flash_delay(flash_delay);
4401 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4402 XSync(xDisplay, False);
4403 do_flash_delay(flash_delay);
4406 drawfunc(piece, square_color, x, y, xBoardWindow);
4410 string[1] = NULLCHAR;
4411 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4412 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4413 string[0] = 'a' + column - BOARD_LEFT;
4414 XTextExtents(coordFontStruct, string, 1, &direction,
4415 &font_ascent, &font_descent, &overall);
4416 if (appData.monoMode) {
4417 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4418 x + squareSize - overall.width - 2,
4419 y + squareSize - font_descent - 1, string, 1);
4421 XDrawString(xDisplay, xBoardWindow, coordGC,
4422 x + squareSize - overall.width - 2,
4423 y + squareSize - font_descent - 1, string, 1);
4426 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4427 string[0] = ONE + row;
4428 XTextExtents(coordFontStruct, string, 1, &direction,
4429 &font_ascent, &font_descent, &overall);
4430 if (appData.monoMode) {
4431 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4432 x + 2, y + font_ascent + 1, string, 1);
4434 XDrawString(xDisplay, xBoardWindow, coordGC,
4435 x + 2, y + font_ascent + 1, string, 1);
4438 if(!partnerUp && marker[row][column]) {
4439 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4440 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4445 /* Why is this needed on some versions of X? */
4446 void EventProc(widget, unused, event)
4451 if (!XtIsRealized(widget))
4454 switch (event->type) {
4456 if (event->xexpose.count > 0) return; /* no clipping is done */
4457 XDrawPosition(widget, True, NULL);
4458 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4459 flipView = !flipView; partnerUp = !partnerUp;
4460 XDrawPosition(widget, True, NULL);
4461 flipView = !flipView; partnerUp = !partnerUp;
4465 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
\r
4472 void DrawPosition(fullRedraw, board)
4473 /*Boolean*/int fullRedraw;
4476 XDrawPosition(boardWidget, fullRedraw, board);
4479 /* Returns 1 if there are "too many" differences between b1 and b2
4480 (i.e. more than 1 move was made) */
4481 static int too_many_diffs(b1, b2)
4487 for (i=0; i<BOARD_HEIGHT; ++i) {
4488 for (j=0; j<BOARD_WIDTH; ++j) {
4489 if (b1[i][j] != b2[i][j]) {
4490 if (++c > 4) /* Castling causes 4 diffs */
4499 /* Matrix describing castling maneuvers */
4500 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4501 static int castling_matrix[4][5] = {
4502 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4503 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4504 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4505 { 7, 7, 4, 5, 6 } /* 0-0, black */
4508 /* Checks whether castling occurred. If it did, *rrow and *rcol
4509 are set to the destination (row,col) of the rook that moved.
4511 Returns 1 if castling occurred, 0 if not.
4513 Note: Only handles a max of 1 castling move, so be sure
4514 to call too_many_diffs() first.
4516 static int check_castle_draw(newb, oldb, rrow, rcol)
4523 /* For each type of castling... */
4524 for (i=0; i<4; ++i) {
4525 r = castling_matrix[i];
4527 /* Check the 4 squares involved in the castling move */
4529 for (j=1; j<=4; ++j) {
4530 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4537 /* All 4 changed, so it must be a castling move */
4546 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4547 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4549 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4552 void DrawSeekBackground( int left, int top, int right, int bottom )
4554 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4557 void DrawSeekText(char *buf, int x, int y)
4559 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4562 void DrawSeekDot(int x, int y, int colorNr)
4564 int square = colorNr & 0x80;
4567 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4569 XFillRectangle(xDisplay, xBoardWindow, color,
4570 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4572 XFillArc(xDisplay, xBoardWindow, color,
4573 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4576 static int damage[2][BOARD_RANKS][BOARD_FILES];
4579 * event handler for redrawing the board
4581 void XDrawPosition(w, repaint, board)
4583 /*Boolean*/int repaint;
4587 static int lastFlipView = 0;
4588 static int lastBoardValid[2] = {0, 0};
4589 static Board lastBoard[2];
4592 int nr = twoBoards*partnerUp;
4594 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4596 if (board == NULL) {
4597 if (!lastBoardValid[nr]) return;
4598 board = lastBoard[nr];
4600 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4601 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4602 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4607 * It would be simpler to clear the window with XClearWindow()
4608 * but this causes a very distracting flicker.
4611 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4613 /* If too much changes (begin observing new game, etc.), don't
4615 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4617 /* Special check for castling so we don't flash both the king
4618 and the rook (just flash the king). */
4620 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4621 /* Draw rook with NO flashing. King will be drawn flashing later */
4622 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4623 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4627 /* First pass -- Draw (newly) empty squares and repair damage.
4628 This prevents you from having a piece show up twice while it
4629 is flashing on its new square */
4630 for (i = 0; i < BOARD_HEIGHT; i++)
4631 for (j = 0; j < BOARD_WIDTH; j++)
4632 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4633 || damage[nr][i][j]) {
4634 DrawSquare(i, j, board[i][j], 0);
4635 damage[nr][i][j] = False;
4638 /* Second pass -- Draw piece(s) in new position and flash them */
4639 for (i = 0; i < BOARD_HEIGHT; i++)
4640 for (j = 0; j < BOARD_WIDTH; j++)
4641 if (board[i][j] != lastBoard[nr][i][j]) {
4642 DrawSquare(i, j, board[i][j], do_flash);
4646 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4647 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4648 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4650 for (i = 0; i < BOARD_HEIGHT; i++)
4651 for (j = 0; j < BOARD_WIDTH; j++) {
4652 DrawSquare(i, j, board[i][j], 0);
4653 damage[nr][i][j] = False;
4657 CopyBoard(lastBoard[nr], board);
4658 lastBoardValid[nr] = 1;
4659 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4660 lastFlipView = flipView;
4662 /* Draw highlights */
4663 if (pm1X >= 0 && pm1Y >= 0) {
4664 drawHighlight(pm1X, pm1Y, prelineGC);
4666 if (pm2X >= 0 && pm2Y >= 0) {
4667 drawHighlight(pm2X, pm2Y, prelineGC);
4669 if (hi1X >= 0 && hi1Y >= 0) {
4670 drawHighlight(hi1X, hi1Y, highlineGC);
4672 if (hi2X >= 0 && hi2Y >= 0) {
4673 drawHighlight(hi2X, hi2Y, highlineGC);
4676 /* If piece being dragged around board, must redraw that too */
4679 XSync(xDisplay, False);
4684 * event handler for redrawing the board
4686 void DrawPositionProc(w, event, prms, nprms)
4692 XDrawPosition(w, True, NULL);
4697 * event handler for parsing user moves
4699 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4700 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4701 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4702 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4703 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4704 // and at the end FinishMove() to perform the move after optional promotion popups.
4705 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4706 void HandleUserMove(w, event, prms, nprms)
4712 if (w != boardWidget || errorExitStatus != -1) return;
4713 if(nprms) shiftKey = !strcmp(prms[0], "1");
4716 if (event->type == ButtonPress) {
4717 XtPopdown(promotionShell);
4718 XtDestroyWidget(promotionShell);
4719 promotionUp = False;
4727 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4728 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4729 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4732 void AnimateUserMove (Widget w, XEvent * event,
4733 String * params, Cardinal * nParams)
4735 DragPieceMove(event->xmotion.x, event->xmotion.y);
4738 void HandlePV (Widget w, XEvent * event,
4739 String * params, Cardinal * nParams)
4740 { // [HGM] pv: walk PV
4741 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4744 Widget CommentCreate(name, text, mutable, callback, lines)
4746 int /*Boolean*/ mutable;
4747 XtCallbackProc callback;
4751 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4756 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4757 XtGetValues(boardWidget, args, j);
4760 XtSetArg(args[j], XtNresizable, True); j++;
4763 XtCreatePopupShell(name, topLevelShellWidgetClass,
4764 shellWidget, args, j);
4767 XtCreatePopupShell(name, transientShellWidgetClass,
4768 shellWidget, args, j);
4771 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4772 layoutArgs, XtNumber(layoutArgs));
4774 XtCreateManagedWidget("form", formWidgetClass, layout,
4775 formArgs, XtNumber(formArgs));
4779 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4780 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4782 XtSetArg(args[j], XtNstring, text); j++;
4783 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4784 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4785 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4786 XtSetArg(args[j], XtNright, XtChainRight); j++;
4787 XtSetArg(args[j], XtNresizable, True); j++;
4788 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4789 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4790 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4791 XtSetArg(args[j], XtNautoFill, True); j++;
4792 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4794 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4795 XtOverrideTranslations(edit, XtParseTranslationTable(commentTranslations));
4799 XtSetArg(args[j], XtNfromVert, edit); j++;
4800 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4801 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4802 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4803 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4805 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4806 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4809 XtSetArg(args[j], XtNfromVert, edit); j++;
4810 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4811 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4812 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4813 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4814 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4816 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4817 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4820 XtSetArg(args[j], XtNfromVert, edit); j++;
4821 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4822 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4823 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4824 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4825 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4827 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4828 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4831 XtSetArg(args[j], XtNfromVert, edit); j++;
4832 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4833 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4834 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4835 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4837 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4838 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4841 XtSetArg(args[j], XtNfromVert, edit); j++;
4842 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4843 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4844 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4845 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4846 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4848 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4849 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4852 XtRealizeWidget(shell);
4854 if (commentX == -1) {
4857 Dimension pw_height;
4858 Dimension ew_height;
4861 XtSetArg(args[j], XtNheight, &ew_height); j++;
4862 XtGetValues(edit, args, j);
4865 XtSetArg(args[j], XtNheight, &pw_height); j++;
4866 XtGetValues(shell, args, j);
4867 commentH = pw_height + (lines - 1) * ew_height;
4868 commentW = bw_width - 16;
4870 XSync(xDisplay, False);
4872 /* This code seems to tickle an X bug if it is executed too soon
4873 after xboard starts up. The coordinates get transformed as if
4874 the main window was positioned at (0, 0).
4876 XtTranslateCoords(shellWidget,
4877 (bw_width - commentW) / 2, 0 - commentH / 2,
4878 &commentX, &commentY);
4880 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4881 RootWindowOfScreen(XtScreen(shellWidget)),
4882 (bw_width - commentW) / 2, 0 - commentH / 2,
4887 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4890 if(wpComment.width > 0) {
4891 commentX = wpComment.x;
4892 commentY = wpComment.y;
4893 commentW = wpComment.width;
4894 commentH = wpComment.height;
4898 XtSetArg(args[j], XtNheight, commentH); j++;
4899 XtSetArg(args[j], XtNwidth, commentW); j++;
4900 XtSetArg(args[j], XtNx, commentX); j++;
4901 XtSetArg(args[j], XtNy, commentY); j++;
4902 XtSetValues(shell, args, j);
4903 XtSetKeyboardFocus(shell, edit);
4908 /* Used for analysis window and ICS input window */
4909 Widget MiscCreate(name, text, mutable, callback, lines)
4911 int /*Boolean*/ mutable;
4912 XtCallbackProc callback;
4916 Widget shell, layout, form, edit;
4918 Dimension bw_width, pw_height, ew_height, w, h;
4924 XtSetArg(args[j], XtNresizable, True); j++;
4927 XtCreatePopupShell(name, topLevelShellWidgetClass,
4928 shellWidget, args, j);
4931 XtCreatePopupShell(name, transientShellWidgetClass,
4932 shellWidget, args, j);
4935 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4936 layoutArgs, XtNumber(layoutArgs));
4938 XtCreateManagedWidget("form", formWidgetClass, layout,
4939 formArgs, XtNumber(formArgs));
4943 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4944 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4946 XtSetArg(args[j], XtNstring, text); j++;
4947 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4948 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4949 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4950 XtSetArg(args[j], XtNright, XtChainRight); j++;
4951 XtSetArg(args[j], XtNresizable, True); j++;
4952 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4953 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4954 XtSetArg(args[j], XtNautoFill, True); j++;
4955 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4957 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4959 XtRealizeWidget(shell);
4962 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4963 XtGetValues(boardWidget, args, j);
4966 XtSetArg(args[j], XtNheight, &ew_height); j++;
4967 XtGetValues(edit, args, j);
4970 XtSetArg(args[j], XtNheight, &pw_height); j++;
4971 XtGetValues(shell, args, j);
4972 h = pw_height + (lines - 1) * ew_height;
4975 XSync(xDisplay, False);
4977 /* This code seems to tickle an X bug if it is executed too soon
4978 after xboard starts up. The coordinates get transformed as if
4979 the main window was positioned at (0, 0).
4981 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4983 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4984 RootWindowOfScreen(XtScreen(shellWidget)),
4985 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4989 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4992 XtSetArg(args[j], XtNheight, h); j++;
4993 XtSetArg(args[j], XtNwidth, w); j++;
4994 XtSetArg(args[j], XtNx, x); j++;
4995 XtSetArg(args[j], XtNy, y); j++;
4996 XtSetValues(shell, args, j);
5002 static int savedIndex; /* gross that this is global */
5004 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
5007 XawTextPosition index, dummy;
5010 XawTextGetSelectionPos(w, &index, &dummy);
5011 XtSetArg(arg, XtNstring, &val);
5012 XtGetValues(w, &arg, 1);
5013 ReplaceComment(savedIndex, val);
5014 if(savedIndex != currentMove) ToNrEvent(savedIndex);
5015 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
5018 void EditCommentPopUp(index, title, text)
5027 if (text == NULL) text = "";
5029 if (editShell == NULL) {
5031 CommentCreate(title, text, True, EditCommentCallback, 4);
5032 XtRealizeWidget(editShell);
5033 CatchDeleteWindow(editShell, "EditCommentPopDown");
5035 edit = XtNameToWidget(editShell, "*form.text");
5037 XtSetArg(args[j], XtNstring, text); j++;
5038 XtSetValues(edit, args, j);
5040 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5041 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5042 XtSetValues(editShell, args, j);
5045 XtPopup(editShell, XtGrabNone);
5049 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5050 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
5054 void EditCommentCallback(w, client_data, call_data)
5056 XtPointer client_data, call_data;
5064 XtSetArg(args[j], XtNlabel, &name); j++;
5065 XtGetValues(w, args, j);
5067 if (strcmp(name, _("ok")) == 0) {
5068 edit = XtNameToWidget(editShell, "*form.text");
5070 XtSetArg(args[j], XtNstring, &val); j++;
5071 XtGetValues(edit, args, j);
5072 ReplaceComment(savedIndex, val);
5073 EditCommentPopDown();
5074 } else if (strcmp(name, _("cancel")) == 0) {
5075 EditCommentPopDown();
5076 } else if (strcmp(name, _("clear")) == 0) {
5077 edit = XtNameToWidget(editShell, "*form.text");
5078 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5079 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5083 void EditCommentPopDown()
5088 if (!editUp) return;
5090 XtSetArg(args[j], XtNx, &commentX); j++;
5091 XtSetArg(args[j], XtNy, &commentY); j++;
5092 XtSetArg(args[j], XtNheight, &commentH); j++;
5093 XtSetArg(args[j], XtNwidth, &commentW); j++;
5094 XtGetValues(editShell, args, j);
5095 XtPopdown(editShell);
5098 XtSetArg(args[j], XtNleftBitmap, None); j++;
5099 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
5103 void ICSInputBoxPopUp()
5108 char *title = _("ICS Input");
5111 if (ICSInputShell == NULL) {
5112 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
5113 tr = XtParseTranslationTable(ICSInputTranslations);
5114 edit = XtNameToWidget(ICSInputShell, "*form.text");
5115 XtOverrideTranslations(edit, tr);
5116 XtRealizeWidget(ICSInputShell);
5117 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
5120 edit = XtNameToWidget(ICSInputShell, "*form.text");
5122 XtSetArg(args[j], XtNstring, ""); j++;
5123 XtSetValues(edit, args, j);
5125 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5126 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5127 XtSetValues(ICSInputShell, args, j);
5130 XtPopup(ICSInputShell, XtGrabNone);
5131 XtSetKeyboardFocus(ICSInputShell, edit);
5133 ICSInputBoxUp = True;
5135 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5136 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
5140 void ICSInputSendText()
5147 edit = XtNameToWidget(ICSInputShell, "*form.text");
5149 XtSetArg(args[j], XtNstring, &val); j++;
5150 XtGetValues(edit, args, j);
5152 SendMultiLineToICS(val);
5153 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5154 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5157 void ICSInputBoxPopDown()
5162 if (!ICSInputBoxUp) return;
5164 XtPopdown(ICSInputShell);
5165 ICSInputBoxUp = False;
5167 XtSetArg(args[j], XtNleftBitmap, None); j++;
5168 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
5172 void CommentPopUp(title, text)
5179 savedIndex = currentMove; // [HGM] vari
5180 if (commentShell == NULL) {
5182 CommentCreate(title, text, False, CommentCallback, 4);
5183 XtRealizeWidget(commentShell);
5184 CatchDeleteWindow(commentShell, "CommentPopDown");
5186 edit = XtNameToWidget(commentShell, "*form.text");
5188 XtSetArg(args[j], XtNstring, text); j++;
5189 XtSetValues(edit, args, j);
5191 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5192 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5193 XtSetValues(commentShell, args, j);
5196 XtPopup(commentShell, XtGrabNone);
5197 XSync(xDisplay, False);
5202 void CommentCallback(w, client_data, call_data)
5204 XtPointer client_data, call_data;
5211 XtSetArg(args[j], XtNlabel, &name); j++;
5212 XtGetValues(w, args, j);
5214 if (strcmp(name, _("close")) == 0) {
5216 } else if (strcmp(name, _("edit")) == 0) {
5223 void CommentPopDown()
5228 if (!commentUp) return;
5230 XtSetArg(args[j], XtNx, &commentX); j++;
5231 XtSetArg(args[j], XtNy, &commentY); j++;
5232 XtSetArg(args[j], XtNwidth, &commentW); j++;
5233 XtSetArg(args[j], XtNheight, &commentH); j++;
5234 XtGetValues(commentShell, args, j);
5235 XtPopdown(commentShell);
5236 XSync(xDisplay, False);
5240 void FileNamePopUp(label, def, proc, openMode)
5246 fileProc = proc; /* I can't see a way not */
5247 fileOpenMode = openMode; /* to use globals here */
5248 { // [HGM] use file-selector dialog stolen from Ghostview
5250 int index; // this is not supported yet
5252 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5253 def, openMode, NULL, &name))
5254 (void) (*fileProc)(f, index=0, name);
5258 void FileNamePopDown()
5260 if (!filenameUp) return;
5261 XtPopdown(fileNameShell);
5262 XtDestroyWidget(fileNameShell);
5267 void FileNameCallback(w, client_data, call_data)
5269 XtPointer client_data, call_data;
5274 XtSetArg(args[0], XtNlabel, &name);
5275 XtGetValues(w, args, 1);
5277 if (strcmp(name, _("cancel")) == 0) {
5282 FileNameAction(w, NULL, NULL, NULL);
5285 void FileNameAction(w, event, prms, nprms)
5297 name = XawDialogGetValueString(w = XtParent(w));
5299 if ((name != NULL) && (*name != NULLCHAR)) {
5300 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
5301 XtPopdown(w = XtParent(XtParent(w)));
5305 p = strrchr(buf, ' ');
5312 fullname = ExpandPathName(buf);
5314 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5317 f = fopen(fullname, fileOpenMode);
5319 DisplayError(_("Failed to open file"), errno);
5321 (void) (*fileProc)(f, index, buf);
5328 XtPopdown(w = XtParent(XtParent(w)));
5334 void PromotionPopUp()
5337 Widget dialog, layout;
5339 Dimension bw_width, pw_width;
5343 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5344 XtGetValues(boardWidget, args, j);
5347 XtSetArg(args[j], XtNresizable, True); j++;
5348 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5350 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5351 shellWidget, args, j);
5353 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5354 layoutArgs, XtNumber(layoutArgs));
5357 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5358 XtSetArg(args[j], XtNborderWidth, 0); j++;
5359 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5362 if(gameInfo.variant != VariantShogi) {
5363 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5364 (XtPointer) dialog);
5365 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5366 (XtPointer) dialog);
5367 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5368 (XtPointer) dialog);
5369 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5370 (XtPointer) dialog);
5371 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5372 gameInfo.variant == VariantGiveaway) {
5373 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5374 (XtPointer) dialog);
5376 if(gameInfo.variant == VariantCapablanca ||
5377 gameInfo.variant == VariantGothic ||
5378 gameInfo.variant == VariantCapaRandom) {
5379 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5380 (XtPointer) dialog);
5381 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5382 (XtPointer) dialog);
5384 } else // [HGM] shogi
5386 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5387 (XtPointer) dialog);
5388 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5389 (XtPointer) dialog);
5391 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5392 (XtPointer) dialog);
5394 XtRealizeWidget(promotionShell);
5395 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5398 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5399 XtGetValues(promotionShell, args, j);
5401 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5402 lineGap + squareSize/3 +
5403 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5404 0 : 6*(squareSize + lineGap)), &x, &y);
5407 XtSetArg(args[j], XtNx, x); j++;
5408 XtSetArg(args[j], XtNy, y); j++;
5409 XtSetValues(promotionShell, args, j);
5411 XtPopup(promotionShell, XtGrabNone);
5416 void PromotionPopDown()
5418 if (!promotionUp) return;
5419 XtPopdown(promotionShell);
5420 XtDestroyWidget(promotionShell);
5421 promotionUp = False;
5424 void PromotionCallback(w, client_data, call_data)
5426 XtPointer client_data, call_data;
5432 XtSetArg(args[0], XtNlabel, &name);
5433 XtGetValues(w, args, 1);
5437 if (fromX == -1) return;
5439 if (strcmp(name, _("cancel")) == 0) {
5443 } else if (strcmp(name, _("Knight")) == 0) {
5445 } else if (strcmp(name, _("Promote")) == 0) {
5447 } else if (strcmp(name, _("Defer")) == 0) {
5450 promoChar = ToLower(name[0]);
5453 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5455 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5456 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5461 void ErrorCallback(w, client_data, call_data)
5463 XtPointer client_data, call_data;
5466 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5468 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5474 if (!errorUp) return;
5476 XtPopdown(errorShell);
5477 XtDestroyWidget(errorShell);
5478 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5481 void ErrorPopUp(title, label, modal)
5482 char *title, *label;
5486 Widget dialog, layout;
5490 Dimension bw_width, pw_width;
5491 Dimension pw_height;
5495 XtSetArg(args[i], XtNresizable, True); i++;
5496 XtSetArg(args[i], XtNtitle, title); i++;
5498 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5499 shellWidget, args, i);
5501 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5502 layoutArgs, XtNumber(layoutArgs));
5505 XtSetArg(args[i], XtNlabel, label); i++;
5506 XtSetArg(args[i], XtNborderWidth, 0); i++;
5507 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5510 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5512 XtRealizeWidget(errorShell);
5513 CatchDeleteWindow(errorShell, "ErrorPopDown");
5516 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5517 XtGetValues(boardWidget, args, i);
5519 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5520 XtSetArg(args[i], XtNheight, &pw_height); i++;
5521 XtGetValues(errorShell, args, i);
5524 /* This code seems to tickle an X bug if it is executed too soon
5525 after xboard starts up. The coordinates get transformed as if
5526 the main window was positioned at (0, 0).
5528 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5529 0 - pw_height + squareSize / 3, &x, &y);
5531 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5532 RootWindowOfScreen(XtScreen(boardWidget)),
5533 (bw_width - pw_width) / 2,
5534 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5538 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5541 XtSetArg(args[i], XtNx, x); i++;
5542 XtSetArg(args[i], XtNy, y); i++;
5543 XtSetValues(errorShell, args, i);
5546 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5549 /* Disable all user input other than deleting the window */
5550 static int frozen = 0;
5554 /* Grab by a widget that doesn't accept input */
5555 XtAddGrab(messageWidget, TRUE, FALSE);
5559 /* Undo a FreezeUI */
5562 if (!frozen) return;
5563 XtRemoveGrab(messageWidget);
5567 char *ModeToWidgetName(mode)
5571 case BeginningOfGame:
5572 if (appData.icsActive)
5573 return "menuMode.ICS Client";
5574 else if (appData.noChessProgram ||
5575 *appData.cmailGameName != NULLCHAR)
5576 return "menuMode.Edit Game";
5578 return "menuMode.Machine Black";
5579 case MachinePlaysBlack:
5580 return "menuMode.Machine Black";
5581 case MachinePlaysWhite:
5582 return "menuMode.Machine White";
5584 return "menuMode.Analysis Mode";
5586 return "menuMode.Analyze File";
5587 case TwoMachinesPlay:
5588 return "menuMode.Two Machines";
5590 return "menuMode.Edit Game";
5591 case PlayFromGameFile:
5592 return "menuFile.Load Game";
5594 return "menuMode.Edit Position";
5596 return "menuMode.Training";
5597 case IcsPlayingWhite:
5598 case IcsPlayingBlack:
5602 return "menuMode.ICS Client";
5609 void ModeHighlight()
5612 static int oldPausing = FALSE;
5613 static GameMode oldmode = (GameMode) -1;
5616 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5618 if (pausing != oldPausing) {
5619 oldPausing = pausing;
5621 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5623 XtSetArg(args[0], XtNleftBitmap, None);
5625 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5628 if (appData.showButtonBar) {
5629 /* Always toggle, don't set. Previous code messes up when
5630 invoked while the button is pressed, as releasing it
5631 toggles the state again. */
5634 XtSetArg(args[0], XtNbackground, &oldbg);
5635 XtSetArg(args[1], XtNforeground, &oldfg);
5636 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5638 XtSetArg(args[0], XtNbackground, oldfg);
5639 XtSetArg(args[1], XtNforeground, oldbg);
5641 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5645 wname = ModeToWidgetName(oldmode);
5646 if (wname != NULL) {
5647 XtSetArg(args[0], XtNleftBitmap, None);
5648 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5650 wname = ModeToWidgetName(gameMode);
5651 if (wname != NULL) {
5652 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5653 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5657 /* Maybe all the enables should be handled here, not just this one */
5658 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5659 gameMode == Training || gameMode == PlayFromGameFile);
5664 * Button/menu procedures
5666 void ResetProc(w, event, prms, nprms)
5675 int LoadGamePopUp(f, gameNumber, title)
5680 cmailMsgLoaded = FALSE;
5681 if (gameNumber == 0) {
5682 int error = GameListBuild(f);
5684 DisplayError(_("Cannot build game list"), error);
5685 } else if (!ListEmpty(&gameList) &&
5686 ((ListGame *) gameList.tailPred)->number > 1) {
5687 GameListPopUp(f, title);
5693 return LoadGame(f, gameNumber, title, FALSE);
5696 void LoadGameProc(w, event, prms, nprms)
5702 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5705 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5708 void LoadNextGameProc(w, event, prms, nprms)
5717 void LoadPrevGameProc(w, event, prms, nprms)
5726 void ReloadGameProc(w, event, prms, nprms)
5735 void LoadNextPositionProc(w, event, prms, nprms)
5744 void LoadPrevPositionProc(w, event, prms, nprms)
5753 void ReloadPositionProc(w, event, prms, nprms)
5762 void LoadPositionProc(w, event, prms, nprms)
5768 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5771 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5774 void SaveGameProc(w, event, prms, nprms)
5780 FileNamePopUp(_("Save game file name?"),
5781 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5785 void SavePositionProc(w, event, prms, nprms)
5791 FileNamePopUp(_("Save position file name?"),
5792 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5796 void ReloadCmailMsgProc(w, event, prms, nprms)
5802 ReloadCmailMsgEvent(FALSE);
5805 void MailMoveProc(w, event, prms, nprms)
5814 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5815 char *selected_fen_position=NULL;
5818 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5819 Atom *type_return, XtPointer *value_return,
5820 unsigned long *length_return, int *format_return)
5822 char *selection_tmp;
5824 if (!selected_fen_position) return False; /* should never happen */
5825 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5826 /* note: since no XtSelectionDoneProc was registered, Xt will
5827 * automatically call XtFree on the value returned. So have to
5828 * make a copy of it allocated with XtMalloc */
5829 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5830 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
5832 *value_return=selection_tmp;
5833 *length_return=strlen(selection_tmp);
5834 *type_return=*target;
5835 *format_return = 8; /* bits per byte */
5837 } else if (*target == XA_TARGETS(xDisplay)) {
5838 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5839 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5840 targets_tmp[1] = XA_STRING;
5841 *value_return = targets_tmp;
5842 *type_return = XA_ATOM;
5844 *format_return = 8 * sizeof(Atom);
5845 if (*format_return > 32) {
5846 *length_return *= *format_return / 32;
5847 *format_return = 32;
5855 /* note: when called from menu all parameters are NULL, so no clue what the
5856 * Widget which was clicked on was, or what the click event was
5858 void CopyPositionProc(w, event, prms, nprms)
5865 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5866 * have a notion of a position that is selected but not copied.
5867 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5869 if(gameMode == EditPosition) EditPositionDone(TRUE);
5870 if (selected_fen_position) free(selected_fen_position);
5871 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5872 if (!selected_fen_position) return;
5873 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5875 SendPositionSelection,
5876 NULL/* lose_ownership_proc */ ,
5877 NULL/* transfer_done_proc */);
5878 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5880 SendPositionSelection,
5881 NULL/* lose_ownership_proc */ ,
5882 NULL/* transfer_done_proc */);
5885 /* function called when the data to Paste is ready */
5887 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5888 Atom *type, XtPointer value, unsigned long *len, int *format)
5891 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5892 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5893 EditPositionPasteFEN(fenstr);
5897 /* called when Paste Position button is pressed,
5898 * all parameters will be NULL */
5899 void PastePositionProc(w, event, prms, nprms)
5905 XtGetSelectionValue(menuBarWidget,
5906 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5907 /* (XtSelectionCallbackProc) */ PastePositionCB,
5908 NULL, /* client_data passed to PastePositionCB */
5910 /* better to use the time field from the event that triggered the
5911 * call to this function, but that isn't trivial to get
5919 SendGameSelection(Widget w, Atom *selection, Atom *target,
5920 Atom *type_return, XtPointer *value_return,
5921 unsigned long *length_return, int *format_return)
5923 char *selection_tmp;
5925 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5926 FILE* f = fopen(gameCopyFilename, "r");
5929 if (f == NULL) return False;
5933 selection_tmp = XtMalloc(len + 1);
5934 count = fread(selection_tmp, 1, len, f);
5936 XtFree(selection_tmp);
5939 selection_tmp[len] = NULLCHAR;
5940 *value_return = selection_tmp;
5941 *length_return = len;
5942 *type_return = *target;
5943 *format_return = 8; /* bits per byte */
5945 } else if (*target == XA_TARGETS(xDisplay)) {
5946 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5947 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5948 targets_tmp[1] = XA_STRING;
5949 *value_return = targets_tmp;
5950 *type_return = XA_ATOM;
5952 *format_return = 8 * sizeof(Atom);
5953 if (*format_return > 32) {
5954 *length_return *= *format_return / 32;
5955 *format_return = 32;
5963 /* note: when called from menu all parameters are NULL, so no clue what the
5964 * Widget which was clicked on was, or what the click event was
5966 void CopyGameProc(w, event, prms, nprms)
5974 ret = SaveGameToFile(gameCopyFilename, FALSE);
5978 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5979 * have a notion of a game that is selected but not copied.
5980 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5982 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5985 NULL/* lose_ownership_proc */ ,
5986 NULL/* transfer_done_proc */);
5987 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5990 NULL/* lose_ownership_proc */ ,
5991 NULL/* transfer_done_proc */);
5994 /* function called when the data to Paste is ready */
5996 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5997 Atom *type, XtPointer value, unsigned long *len, int *format)
6000 if (value == NULL || *len == 0) {
6001 return; /* nothing had been selected to copy */
6003 f = fopen(gamePasteFilename, "w");
6005 DisplayError(_("Can't open temp file"), errno);
6008 fwrite(value, 1, *len, f);
6011 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
6014 /* called when Paste Game button is pressed,
6015 * all parameters will be NULL */
6016 void PasteGameProc(w, event, prms, nprms)
6022 XtGetSelectionValue(menuBarWidget,
6023 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
6024 /* (XtSelectionCallbackProc) */ PasteGameCB,
6025 NULL, /* client_data passed to PasteGameCB */
6027 /* better to use the time field from the event that triggered the
6028 * call to this function, but that isn't trivial to get
6038 SaveGameProc(NULL, NULL, NULL, NULL);
6042 void QuitProc(w, event, prms, nprms)
6051 void PauseProc(w, event, prms, nprms)
6061 void MachineBlackProc(w, event, prms, nprms)
6067 MachineBlackEvent();
6070 void MachineWhiteProc(w, event, prms, nprms)
6076 MachineWhiteEvent();
6079 void AnalyzeModeProc(w, event, prms, nprms)
6087 if (!first.analysisSupport) {
6088 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6089 DisplayError(buf, 0);
6092 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
6093 if (appData.icsActive) {
6094 if (gameMode != IcsObserving) {
6095 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
6096 DisplayError(buf, 0);
6098 if (appData.icsEngineAnalyze) {
6099 if (appData.debugMode)
6100 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
6106 /* if enable, use want disable icsEngineAnalyze */
6107 if (appData.icsEngineAnalyze) {
6112 appData.icsEngineAnalyze = TRUE;
6113 if (appData.debugMode)
6114 fprintf(debugFP, _("ICS engine analyze starting... \n"));
6116 if (!appData.showThinking)
6117 ShowThinkingProc(w,event,prms,nprms);
6122 void AnalyzeFileProc(w, event, prms, nprms)
6128 if (!first.analysisSupport) {
6130 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6131 DisplayError(buf, 0);
6136 if (!appData.showThinking)
6137 ShowThinkingProc(w,event,prms,nprms);
6140 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
6141 AnalysisPeriodicEvent(1);
6144 void TwoMachinesProc(w, event, prms, nprms)
6153 void IcsClientProc(w, event, prms, nprms)
6162 void EditGameProc(w, event, prms, nprms)
6171 void EditPositionProc(w, event, prms, nprms)
6177 EditPositionEvent();
6180 void TrainingProc(w, event, prms, nprms)
6189 void EditCommentProc(w, event, prms, nprms)
6196 EditCommentPopDown();
6202 void IcsInputBoxProc(w, event, prms, nprms)
6208 if (ICSInputBoxUp) {
6209 ICSInputBoxPopDown();
6215 void AcceptProc(w, event, prms, nprms)
6224 void DeclineProc(w, event, prms, nprms)
6233 void RematchProc(w, event, prms, nprms)
6242 void CallFlagProc(w, event, prms, nprms)
6251 void DrawProc(w, event, prms, nprms)
6260 void AbortProc(w, event, prms, nprms)
6269 void AdjournProc(w, event, prms, nprms)
6278 void ResignProc(w, event, prms, nprms)
6287 void AdjuWhiteProc(w, event, prms, nprms)
6293 UserAdjudicationEvent(+1);
6296 void AdjuBlackProc(w, event, prms, nprms)
6302 UserAdjudicationEvent(-1);
6305 void AdjuDrawProc(w, event, prms, nprms)
6311 UserAdjudicationEvent(0);
6314 void EnterKeyProc(w, event, prms, nprms)
6320 if (ICSInputBoxUp == True)
6324 void UpKeyProc(w, event, prms, nprms)
6329 { // [HGM] input: let up-arrow recall previous line from history
6336 if (!ICSInputBoxUp) return;
6337 edit = XtNameToWidget(ICSInputShell, "*form.text");
6339 XtSetArg(args[j], XtNstring, &val); j++;
6340 XtGetValues(edit, args, j);
6341 val = PrevInHistory(val);
6342 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6343 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6345 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6346 XawTextReplace(edit, 0, 0, &t);
6347 XawTextSetInsertionPoint(edit, 9999);
6351 void DownKeyProc(w, event, prms, nprms)
6356 { // [HGM] input: let down-arrow recall next line from history
6361 if (!ICSInputBoxUp) return;
6362 edit = XtNameToWidget(ICSInputShell, "*form.text");
6363 val = NextInHistory();
6364 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6365 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6367 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6368 XawTextReplace(edit, 0, 0, &t);
6369 XawTextSetInsertionPoint(edit, 9999);
6373 void StopObservingProc(w, event, prms, nprms)
6379 StopObservingEvent();
6382 void StopExaminingProc(w, event, prms, nprms)
6388 StopExaminingEvent();
6391 void UploadProc(w, event, prms, nprms)
6401 void ForwardProc(w, event, prms, nprms)
6411 void BackwardProc(w, event, prms, nprms)
6420 void ToStartProc(w, event, prms, nprms)
6429 void ToEndProc(w, event, prms, nprms)
6438 void RevertProc(w, event, prms, nprms)
6447 void AnnotateProc(w, event, prms, nprms)
6456 void TruncateGameProc(w, event, prms, nprms)
6462 TruncateGameEvent();
6464 void RetractMoveProc(w, event, prms, nprms)
6473 void MoveNowProc(w, event, prms, nprms)
6483 void AlwaysQueenProc(w, event, prms, nprms)
6491 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6493 if (appData.alwaysPromoteToQueen) {
6494 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6496 XtSetArg(args[0], XtNleftBitmap, None);
6498 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6502 void AnimateDraggingProc(w, event, prms, nprms)
6510 appData.animateDragging = !appData.animateDragging;
6512 if (appData.animateDragging) {
6513 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6516 XtSetArg(args[0], XtNleftBitmap, None);
6518 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6522 void AnimateMovingProc(w, event, prms, nprms)
6530 appData.animate = !appData.animate;
6532 if (appData.animate) {
6533 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6536 XtSetArg(args[0], XtNleftBitmap, None);
6538 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6542 void AutocommProc(w, event, prms, nprms)
6550 appData.autoComment = !appData.autoComment;
6552 if (appData.autoComment) {
6553 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6555 XtSetArg(args[0], XtNleftBitmap, None);
6557 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6562 void AutoflagProc(w, event, prms, nprms)
6570 appData.autoCallFlag = !appData.autoCallFlag;
6572 if (appData.autoCallFlag) {
6573 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6575 XtSetArg(args[0], XtNleftBitmap, None);
6577 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6581 void AutoflipProc(w, event, prms, nprms)
6589 appData.autoFlipView = !appData.autoFlipView;
6591 if (appData.autoFlipView) {
6592 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6594 XtSetArg(args[0], XtNleftBitmap, None);
6596 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6600 void AutobsProc(w, event, prms, nprms)
6608 appData.autoObserve = !appData.autoObserve;
6610 if (appData.autoObserve) {
6611 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6613 XtSetArg(args[0], XtNleftBitmap, None);
6615 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6619 void AutoraiseProc(w, event, prms, nprms)
6627 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6629 if (appData.autoRaiseBoard) {
6630 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6632 XtSetArg(args[0], XtNleftBitmap, None);
6634 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6638 void AutosaveProc(w, event, prms, nprms)
6646 appData.autoSaveGames = !appData.autoSaveGames;
6648 if (appData.autoSaveGames) {
6649 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6651 XtSetArg(args[0], XtNleftBitmap, None);
6653 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6657 void BlindfoldProc(w, event, prms, nprms)
6665 appData.blindfold = !appData.blindfold;
6667 if (appData.blindfold) {
6668 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6670 XtSetArg(args[0], XtNleftBitmap, None);
6672 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6675 DrawPosition(True, NULL);
6678 void TestLegalityProc(w, event, prms, nprms)
6686 appData.testLegality = !appData.testLegality;
6688 if (appData.testLegality) {
6689 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6691 XtSetArg(args[0], XtNleftBitmap, None);
6693 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6698 void FlashMovesProc(w, event, prms, nprms)
6706 if (appData.flashCount == 0) {
6707 appData.flashCount = 3;
6709 appData.flashCount = -appData.flashCount;
6712 if (appData.flashCount > 0) {
6713 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6715 XtSetArg(args[0], XtNleftBitmap, None);
6717 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6721 void FlipViewProc(w, event, prms, nprms)
6727 flipView = !flipView;
6728 DrawPosition(True, NULL);
6731 void GetMoveListProc(w, event, prms, nprms)
6739 appData.getMoveList = !appData.getMoveList;
6741 if (appData.getMoveList) {
6742 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6745 XtSetArg(args[0], XtNleftBitmap, None);
6747 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6752 void HighlightDraggingProc(w, event, prms, nprms)
6760 appData.highlightDragging = !appData.highlightDragging;
6762 if (appData.highlightDragging) {
6763 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6765 XtSetArg(args[0], XtNleftBitmap, None);
6767 XtSetValues(XtNameToWidget(menuBarWidget,
6768 "menuOptions.Highlight Dragging"), args, 1);
6772 void HighlightLastMoveProc(w, event, prms, nprms)
6780 appData.highlightLastMove = !appData.highlightLastMove;
6782 if (appData.highlightLastMove) {
6783 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6785 XtSetArg(args[0], XtNleftBitmap, None);
6787 XtSetValues(XtNameToWidget(menuBarWidget,
6788 "menuOptions.Highlight Last Move"), args, 1);
6791 void IcsAlarmProc(w, event, prms, nprms)
6799 appData.icsAlarm = !appData.icsAlarm;
6801 if (appData.icsAlarm) {
6802 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6804 XtSetArg(args[0], XtNleftBitmap, None);
6806 XtSetValues(XtNameToWidget(menuBarWidget,
6807 "menuOptions.ICS Alarm"), args, 1);
6810 void MoveSoundProc(w, event, prms, nprms)
6818 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6820 if (appData.ringBellAfterMoves) {
6821 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6823 XtSetArg(args[0], XtNleftBitmap, None);
6825 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6830 void OldSaveStyleProc(w, event, prms, nprms)
6838 appData.oldSaveStyle = !appData.oldSaveStyle;
6840 if (appData.oldSaveStyle) {
6841 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6843 XtSetArg(args[0], XtNleftBitmap, None);
6845 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6849 void PeriodicUpdatesProc(w, event, prms, nprms)
6857 PeriodicUpdatesEvent(!appData.periodicUpdates);
6859 if (appData.periodicUpdates) {
6860 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6862 XtSetArg(args[0], XtNleftBitmap, None);
6864 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6868 void PonderNextMoveProc(w, event, prms, nprms)
6876 PonderNextMoveEvent(!appData.ponderNextMove);
6878 if (appData.ponderNextMove) {
6879 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6881 XtSetArg(args[0], XtNleftBitmap, None);
6883 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6887 void PopupExitMessageProc(w, event, prms, nprms)
6895 appData.popupExitMessage = !appData.popupExitMessage;
6897 if (appData.popupExitMessage) {
6898 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6900 XtSetArg(args[0], XtNleftBitmap, None);
6902 XtSetValues(XtNameToWidget(menuBarWidget,
6903 "menuOptions.Popup Exit Message"), args, 1);
6906 void PopupMoveErrorsProc(w, event, prms, nprms)
6914 appData.popupMoveErrors = !appData.popupMoveErrors;
6916 if (appData.popupMoveErrors) {
6917 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6919 XtSetArg(args[0], XtNleftBitmap, None);
6921 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6925 void PremoveProc(w, event, prms, nprms)
6933 appData.premove = !appData.premove;
6935 if (appData.premove) {
6936 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6938 XtSetArg(args[0], XtNleftBitmap, None);
6940 XtSetValues(XtNameToWidget(menuBarWidget,
6941 "menuOptions.Premove"), args, 1);
6944 void QuietPlayProc(w, event, prms, nprms)
6952 appData.quietPlay = !appData.quietPlay;
6954 if (appData.quietPlay) {
6955 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6957 XtSetArg(args[0], XtNleftBitmap, None);
6959 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6963 void ShowCoordsProc(w, event, prms, nprms)
6971 appData.showCoords = !appData.showCoords;
6973 if (appData.showCoords) {
6974 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6976 XtSetArg(args[0], XtNleftBitmap, None);
6978 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6981 DrawPosition(True, NULL);
6984 void ShowThinkingProc(w, event, prms, nprms)
6990 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6991 ShowThinkingEvent();
6994 void HideThinkingProc(w, event, prms, nprms)
7002 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
7003 ShowThinkingEvent();
7005 if (appData.hideThinkingFromHuman) {
7006 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
7008 XtSetArg(args[0], XtNleftBitmap, None);
7010 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
7014 void SaveOnExitProc(w, event, prms, nprms)
7022 saveSettingsOnExit = !saveSettingsOnExit;
7024 if (saveSettingsOnExit) {
7025 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
7027 XtSetArg(args[0], XtNleftBitmap, None);
7029 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
7033 void SaveSettingsProc(w, event, prms, nprms)
7039 SaveSettings(settingsFileName);
7042 void InfoProc(w, event, prms, nprms)
7049 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
7054 void ManProc(w, event, prms, nprms)
7062 if (nprms && *nprms > 0)
7066 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
7070 void HintProc(w, event, prms, nprms)
7079 void BookProc(w, event, prms, nprms)
7088 void AboutProc(w, event, prms, nprms)
7096 char *zippy = " (with Zippy code)";
7100 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
7101 programVersion, zippy,
7102 "Copyright 1991 Digital Equipment Corporation",
7103 "Enhancements Copyright 1992-2009 Free Software Foundation",
7104 "Enhancements Copyright 2005 Alessandro Scotti",
7105 PACKAGE, " is free software and carries NO WARRANTY;",
7106 "see the file COPYING for more information.");
7107 ErrorPopUp(_("About XBoard"), buf, FALSE);
7110 void DebugProc(w, event, prms, nprms)
7116 appData.debugMode = !appData.debugMode;
7119 void AboutGameProc(w, event, prms, nprms)
7128 void NothingProc(w, event, prms, nprms)
7137 void Iconify(w, event, prms, nprms)
7146 XtSetArg(args[0], XtNiconic, True);
7147 XtSetValues(shellWidget, args, 1);
7150 void DisplayMessage(message, extMessage)
7151 char *message, *extMessage;
7153 /* display a message in the message widget */
7162 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
7167 message = extMessage;
7171 /* need to test if messageWidget already exists, since this function
7172 can also be called during the startup, if for example a Xresource
7173 is not set up correctly */
7176 XtSetArg(arg, XtNlabel, message);
7177 XtSetValues(messageWidget, &arg, 1);
7183 void DisplayTitle(text)
7188 char title[MSG_SIZ];
7191 if (text == NULL) text = "";
7193 if (appData.titleInWindow) {
7195 XtSetArg(args[i], XtNlabel, text); i++;
7196 XtSetValues(titleWidget, args, i);
7199 if (*text != NULLCHAR) {
7200 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
7201 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
7202 } else if (appData.icsActive) {
7203 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7204 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7205 } else if (appData.cmailGameName[0] != NULLCHAR) {
7206 snprintf(icon, sizeof(icon), "%s", "CMail");
7207 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7209 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7210 } else if (gameInfo.variant == VariantGothic) {
7211 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7212 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
7215 } else if (gameInfo.variant == VariantFalcon) {
7216 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7217 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
7219 } else if (appData.noChessProgram) {
7220 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7221 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
7223 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
7224 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7227 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7228 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7229 XtSetValues(shellWidget, args, i);
7234 DisplayError(message, error)
7241 if (appData.debugMode || appData.matchMode) {
7242 fprintf(stderr, "%s: %s\n", programName, message);
7245 if (appData.debugMode || appData.matchMode) {
7246 fprintf(stderr, "%s: %s: %s\n",
7247 programName, message, strerror(error));
7249 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7252 ErrorPopUp(_("Error"), message, FALSE);
7256 void DisplayMoveError(message)
7261 DrawPosition(FALSE, NULL);
7262 if (appData.debugMode || appData.matchMode) {
7263 fprintf(stderr, "%s: %s\n", programName, message);
7265 if (appData.popupMoveErrors) {
7266 ErrorPopUp(_("Error"), message, FALSE);
7268 DisplayMessage(message, "");
7273 void DisplayFatalError(message, error, status)
7279 errorExitStatus = status;
7281 fprintf(stderr, "%s: %s\n", programName, message);
7283 fprintf(stderr, "%s: %s: %s\n",
7284 programName, message, strerror(error));
7285 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7288 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7289 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7295 void DisplayInformation(message)
7299 ErrorPopUp(_("Information"), message, TRUE);
7302 void DisplayNote(message)
7306 ErrorPopUp(_("Note"), message, FALSE);
7310 NullXErrorCheck(dpy, error_event)
7312 XErrorEvent *error_event;
7317 void DisplayIcsInteractionTitle(message)
7320 if (oldICSInteractionTitle == NULL) {
7321 /* Magic to find the old window title, adapted from vim */
7322 char *wina = getenv("WINDOWID");
7324 Window win = (Window) atoi(wina);
7325 Window root, parent, *children;
7326 unsigned int nchildren;
7327 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7329 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7330 if (!XQueryTree(xDisplay, win, &root, &parent,
7331 &children, &nchildren)) break;
7332 if (children) XFree((void *)children);
7333 if (parent == root || parent == 0) break;
7336 XSetErrorHandler(oldHandler);
7338 if (oldICSInteractionTitle == NULL) {
7339 oldICSInteractionTitle = "xterm";
7342 printf("\033]0;%s\007", message);
7346 char pendingReplyPrefix[MSG_SIZ];
7347 ProcRef pendingReplyPR;
7349 void AskQuestionProc(w, event, prms, nprms)
7356 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7360 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7363 void AskQuestionPopDown()
7365 if (!askQuestionUp) return;
7366 XtPopdown(askQuestionShell);
7367 XtDestroyWidget(askQuestionShell);
7368 askQuestionUp = False;
7371 void AskQuestionReplyAction(w, event, prms, nprms)
7381 reply = XawDialogGetValueString(w = XtParent(w));
7382 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
7383 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
7384 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
7385 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
7386 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7387 AskQuestionPopDown();
7389 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7392 void AskQuestionCallback(w, client_data, call_data)
7394 XtPointer client_data, call_data;
7399 XtSetArg(args[0], XtNlabel, &name);
7400 XtGetValues(w, args, 1);
7402 if (strcmp(name, _("cancel")) == 0) {
7403 AskQuestionPopDown();
7405 AskQuestionReplyAction(w, NULL, NULL, NULL);
7409 void AskQuestion(title, question, replyPrefix, pr)
7410 char *title, *question, *replyPrefix;
7414 Widget popup, layout, dialog, edit;
7420 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
7421 pendingReplyPR = pr;
7424 XtSetArg(args[i], XtNresizable, True); i++;
7425 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7426 askQuestionShell = popup =
7427 XtCreatePopupShell(title, transientShellWidgetClass,
7428 shellWidget, args, i);
7431 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7432 layoutArgs, XtNumber(layoutArgs));
7435 XtSetArg(args[i], XtNlabel, question); i++;
7436 XtSetArg(args[i], XtNvalue, ""); i++;
7437 XtSetArg(args[i], XtNborderWidth, 0); i++;
7438 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7441 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7442 (XtPointer) dialog);
7443 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7444 (XtPointer) dialog);
7446 XtRealizeWidget(popup);
7447 CatchDeleteWindow(popup, "AskQuestionPopDown");
7449 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7450 &x, &y, &win_x, &win_y, &mask);
7452 XtSetArg(args[0], XtNx, x - 10);
7453 XtSetArg(args[1], XtNy, y - 30);
7454 XtSetValues(popup, args, 2);
7456 XtPopup(popup, XtGrabExclusive);
7457 askQuestionUp = True;
7459 edit = XtNameToWidget(dialog, "*value");
7460 XtSetKeyboardFocus(popup, edit);
7468 if (*name == NULLCHAR) {
7470 } else if (strcmp(name, "$") == 0) {
7471 putc(BELLCHAR, stderr);
7474 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7482 PlaySound(appData.soundMove);
7488 PlaySound(appData.soundIcsWin);
7494 PlaySound(appData.soundIcsLoss);
7500 PlaySound(appData.soundIcsDraw);
7504 PlayIcsUnfinishedSound()
7506 PlaySound(appData.soundIcsUnfinished);
7512 PlaySound(appData.soundIcsAlarm);
7518 system("stty echo");
7524 system("stty -echo");
7528 Colorize(cc, continuation)
7533 int count, outCount, error;
7535 if (textColors[(int)cc].bg > 0) {
7536 if (textColors[(int)cc].fg > 0) {
7537 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7538 textColors[(int)cc].fg, textColors[(int)cc].bg);
7540 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7541 textColors[(int)cc].bg);
7544 if (textColors[(int)cc].fg > 0) {
7545 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7546 textColors[(int)cc].fg);
7548 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7551 count = strlen(buf);
7552 outCount = OutputToProcess(NoProc, buf, count, &error);
7553 if (outCount < count) {
7554 DisplayFatalError(_("Error writing to display"), error, 1);
7557 if (continuation) return;
7560 PlaySound(appData.soundShout);
7563 PlaySound(appData.soundSShout);
7566 PlaySound(appData.soundChannel1);
7569 PlaySound(appData.soundChannel);
7572 PlaySound(appData.soundKibitz);
7575 PlaySound(appData.soundTell);
7577 case ColorChallenge:
7578 PlaySound(appData.soundChallenge);
7581 PlaySound(appData.soundRequest);
7584 PlaySound(appData.soundSeek);
7595 return getpwuid(getuid())->pw_name;
7599 ExpandPathName(path)
7602 static char static_buf[4*MSG_SIZ];
7603 char *d, *s, buf[4*MSG_SIZ];
7609 while (*s && isspace(*s))
7618 if (*(s+1) == '/') {
7619 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7623 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7624 { char *p; if(p = strchr(buf, '/')) *p = 0; }
7625 pwd = getpwnam(buf);
7628 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7632 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7633 strcat(d, strchr(s+1, '/'));
7637 safeStrCpy(d, s, 4*MSG_SIZ );
7644 static char host_name[MSG_SIZ];
7646 #if HAVE_GETHOSTNAME
7647 gethostname(host_name, MSG_SIZ);
7649 #else /* not HAVE_GETHOSTNAME */
7650 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7651 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7653 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7655 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7656 #endif /* not HAVE_GETHOSTNAME */
7659 XtIntervalId delayedEventTimerXID = 0;
7660 DelayedEventCallback delayedEventCallback = 0;
7665 delayedEventTimerXID = 0;
7666 delayedEventCallback();
7670 ScheduleDelayedEvent(cb, millisec)
7671 DelayedEventCallback cb; long millisec;
7673 if(delayedEventTimerXID && delayedEventCallback == cb)
7674 // [HGM] alive: replace, rather than add or flush identical event
7675 XtRemoveTimeOut(delayedEventTimerXID);
7676 delayedEventCallback = cb;
7677 delayedEventTimerXID =
7678 XtAppAddTimeOut(appContext, millisec,
7679 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7682 DelayedEventCallback
7685 if (delayedEventTimerXID) {
7686 return delayedEventCallback;
7693 CancelDelayedEvent()
7695 if (delayedEventTimerXID) {
7696 XtRemoveTimeOut(delayedEventTimerXID);
7697 delayedEventTimerXID = 0;
7701 XtIntervalId loadGameTimerXID = 0;
7703 int LoadGameTimerRunning()
7705 return loadGameTimerXID != 0;
7708 int StopLoadGameTimer()
7710 if (loadGameTimerXID != 0) {
7711 XtRemoveTimeOut(loadGameTimerXID);
7712 loadGameTimerXID = 0;
7720 LoadGameTimerCallback(arg, id)
7724 loadGameTimerXID = 0;
7729 StartLoadGameTimer(millisec)
7733 XtAppAddTimeOut(appContext, millisec,
7734 (XtTimerCallbackProc) LoadGameTimerCallback,
7738 XtIntervalId analysisClockXID = 0;
7741 AnalysisClockCallback(arg, id)
7745 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7746 || appData.icsEngineAnalyze) { // [DM]
7747 AnalysisPeriodicEvent(0);
7748 StartAnalysisClock();
7753 StartAnalysisClock()
7756 XtAppAddTimeOut(appContext, 2000,
7757 (XtTimerCallbackProc) AnalysisClockCallback,
7761 XtIntervalId clockTimerXID = 0;
7763 int ClockTimerRunning()
7765 return clockTimerXID != 0;
7768 int StopClockTimer()
7770 if (clockTimerXID != 0) {
7771 XtRemoveTimeOut(clockTimerXID);
7780 ClockTimerCallback(arg, id)
7789 StartClockTimer(millisec)
7793 XtAppAddTimeOut(appContext, millisec,
7794 (XtTimerCallbackProc) ClockTimerCallback,
7799 DisplayTimerLabel(w, color, timer, highlight)
7808 /* check for low time warning */
7809 Pixel foregroundOrWarningColor = timerForegroundPixel;
7812 appData.lowTimeWarning &&
7813 (timer / 1000) < appData.icsAlarmTime)
7814 foregroundOrWarningColor = lowTimeWarningColor;
7816 if (appData.clockMode) {
7817 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7818 XtSetArg(args[0], XtNlabel, buf);
7820 snprintf(buf, MSG_SIZ, "%s ", color);
7821 XtSetArg(args[0], XtNlabel, buf);
7826 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7827 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7829 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7830 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7833 XtSetValues(w, args, 3);
7837 DisplayWhiteClock(timeRemaining, highlight)
7843 if(appData.noGUI) return;
7844 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7845 if (highlight && iconPixmap == bIconPixmap) {
7846 iconPixmap = wIconPixmap;
7847 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7848 XtSetValues(shellWidget, args, 1);
7853 DisplayBlackClock(timeRemaining, highlight)
7859 if(appData.noGUI) return;
7860 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7861 if (highlight && iconPixmap == wIconPixmap) {
7862 iconPixmap = bIconPixmap;
7863 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7864 XtSetValues(shellWidget, args, 1);
7882 int StartChildProcess(cmdLine, dir, pr)
7889 int to_prog[2], from_prog[2];
7893 if (appData.debugMode) {
7894 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7897 /* We do NOT feed the cmdLine to the shell; we just
7898 parse it into blank-separated arguments in the
7899 most simple-minded way possible.
7902 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7905 while(*p == ' ') p++;
7907 if(*p == '"' || *p == '\'')
7908 p = strchr(++argv[i-1], *p);
7909 else p = strchr(p, ' ');
7910 if (p == NULL) break;
7915 SetUpChildIO(to_prog, from_prog);
7917 if ((pid = fork()) == 0) {
7919 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7920 close(to_prog[1]); // first close the unused pipe ends
7921 close(from_prog[0]);
7922 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7923 dup2(from_prog[1], 1);
7924 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7925 close(from_prog[1]); // and closing again loses one of the pipes!
7926 if(fileno(stderr) >= 2) // better safe than sorry...
7927 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7929 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7934 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7936 execvp(argv[0], argv);
7938 /* If we get here, exec failed */
7943 /* Parent process */
7945 close(from_prog[1]);
7947 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7950 cp->fdFrom = from_prog[0];
7951 cp->fdTo = to_prog[1];
7956 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7957 static RETSIGTYPE AlarmCallBack(int n)
7963 DestroyChildProcess(pr, signalType)
7967 ChildProc *cp = (ChildProc *) pr;
7969 if (cp->kind != CPReal) return;
7971 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7972 signal(SIGALRM, AlarmCallBack);
7974 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7975 kill(cp->pid, SIGKILL); // kill it forcefully
7976 wait((int *) 0); // and wait again
7980 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7982 /* Process is exiting either because of the kill or because of
7983 a quit command sent by the backend; either way, wait for it to die.
7992 InterruptChildProcess(pr)
7995 ChildProc *cp = (ChildProc *) pr;
7997 if (cp->kind != CPReal) return;
7998 (void) kill(cp->pid, SIGINT); /* stop it thinking */
8001 int OpenTelnet(host, port, pr)
8006 char cmdLine[MSG_SIZ];
8008 if (port[0] == NULLCHAR) {
8009 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
8011 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
8013 return StartChildProcess(cmdLine, "", pr);
8016 int OpenTCP(host, port, pr)
8022 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
8023 #else /* !OMIT_SOCKETS */
8025 struct sockaddr_in sa;
8027 unsigned short uport;
8030 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
8034 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
8035 sa.sin_family = AF_INET;
8036 sa.sin_addr.s_addr = INADDR_ANY;
8037 uport = (unsigned short) 0;
8038 sa.sin_port = htons(uport);
8039 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
8043 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
8044 if (!(hp = gethostbyname(host))) {
8046 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
8047 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
8048 hp->h_addrtype = AF_INET;
8050 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
8051 hp->h_addr_list[0] = (char *) malloc(4);
8052 hp->h_addr_list[0][0] = b0;
8053 hp->h_addr_list[0][1] = b1;
8054 hp->h_addr_list[0][2] = b2;
8055 hp->h_addr_list[0][3] = b3;
8060 sa.sin_family = hp->h_addrtype;
8061 uport = (unsigned short) atoi(port);
8062 sa.sin_port = htons(uport);
8063 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
8065 if (connect(s, (struct sockaddr *) &sa,
8066 sizeof(struct sockaddr_in)) < 0) {
8070 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8077 #endif /* !OMIT_SOCKETS */
8082 int OpenCommPort(name, pr)
8089 fd = open(name, 2, 0);
8090 if (fd < 0) return errno;
8092 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8102 int OpenLoopback(pr)
8108 SetUpChildIO(to, from);
8110 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8113 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
8120 int OpenRcmd(host, user, cmd, pr)
8121 char *host, *user, *cmd;
8124 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
8128 #define INPUT_SOURCE_BUF_SIZE 8192
8137 char buf[INPUT_SOURCE_BUF_SIZE];
8142 DoInputCallback(closure, source, xid)
8147 InputSource *is = (InputSource *) closure;
8152 if (is->lineByLine) {
8153 count = read(is->fd, is->unused,
8154 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
8156 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
8159 is->unused += count;
8161 while (p < is->unused) {
8162 q = memchr(p, '\n', is->unused - p);
8163 if (q == NULL) break;
8165 (is->func)(is, is->closure, p, q - p, 0);
8169 while (p < is->unused) {
8174 # if HAVE_LIBREADLINE
8175 /* check if input is from stdin, if yes, use gnu-readline */
8176 if( is->fd==fileno(stdin) )
8178 /* to clear the line */
8181 /* read from stdin */
8182 rl_callback_read_char();
8184 /* redisplay the current line, check special case for login and password */
8185 if(sending_ICS_password)
8187 int i; char buf[MSG_SIZ];
8191 /* blank the password */
8192 count = strlen(rl_line_buffer);
8195 printf("PROBLEM with readline\n");
8198 for(i=0;i<count;i++)
8202 printf("\rpassword: %s",buf);
8204 else if (sending_ICS_login)
8206 /* show login prompt */
8207 count = strlen(rl_line_buffer);
8208 printf("\rlogin: %s",rl_line_buffer);
8211 rl_reset_line_state();
8213 if(readline_complete)
8215 /* copy into XBoards buffer */
8216 count = strlen(readline_buffer);
8217 if (count>INPUT_SOURCE_BUF_SIZE-1)
8219 printf("PROBLEM with readline\n");
8220 count = INPUT_SOURCE_BUF_SIZE;
8222 strncpy(is->buf,readline_buffer,count);
8223 is->buf[count]='\n';count++;
8225 /* reset gnu-readline state */
8226 free(readline_buffer);
8227 readline_buffer=NULL;
8228 readline_complete=0;
8234 (is->func)(is, is->closure, is->buf, count, error);
8236 /* are we done with the password? */
8237 if(sending_ICS_password)
8238 sending_ICS_password=0;
8239 if(sending_ICS_login)
8240 sending_ICS_login=0;
8245 /* input not from stdin, use default method */
8246 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8251 (is->func)(is, is->closure, is->buf, count, error);
8253 #else /* no readline support */
8254 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8259 (is->func)(is, is->closure, is->buf, count, error);
8265 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8272 ChildProc *cp = (ChildProc *) pr;
8274 is = (InputSource *) calloc(1, sizeof(InputSource));
8275 is->lineByLine = lineByLine;
8279 is->fd = fileno(stdin);
8281 is->kind = cp->kind;
8282 is->fd = cp->fdFrom;
8285 is->unused = is->buf;
8288 is->xid = XtAppAddInput(appContext, is->fd,
8289 (XtPointer) (XtInputReadMask),
8290 (XtInputCallbackProc) DoInputCallback,
8292 is->closure = closure;
8293 return (InputSourceRef) is;
8297 RemoveInputSource(isr)
8300 InputSource *is = (InputSource *) isr;
8302 if (is->xid == 0) return;
8303 XtRemoveInput(is->xid);
8307 int OutputToProcess(pr, message, count, outError)
8313 static int line = 0;
8314 ChildProc *cp = (ChildProc *) pr;
8320 if (appData.noJoin || !appData.useInternalWrap)
8321 outCount = fwrite(message, 1, count, stdout);
8324 int width = get_term_width();
8325 int len = wrap(NULL, message, count, width, &line);
8326 char *msg = malloc(len);
8330 outCount = fwrite(message, 1, count, stdout);
8333 dbgchk = wrap(msg, message, count, width, &line);
8334 if (dbgchk != len && appData.debugMode)
8335 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8336 outCount = fwrite(msg, 1, dbgchk, stdout);
8341 # if HAVE_LIBREADLINE
8342 /* readline support */
8343 if(strlen(rl_line_buffer))
8344 printf("\n> %s",rl_line_buffer);
8349 outCount = write(cp->fdTo, message, count);
8359 /* Output message to process, with "ms" milliseconds of delay
8360 between each character. This is needed when sending the logon
8361 script to ICC, which for some reason doesn't like the
8362 instantaneous send. */
8363 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8370 ChildProc *cp = (ChildProc *) pr;
8375 r = write(cp->fdTo, message++, 1);
8388 /**** Animation code by Hugh Fisher, DCS, ANU.
8390 Known problem: if a window overlapping the board is
8391 moved away while a piece is being animated underneath,
8392 the newly exposed area won't be updated properly.
8393 I can live with this.
8395 Known problem: if you look carefully at the animation
8396 of pieces in mono mode, they are being drawn as solid
8397 shapes without interior detail while moving. Fixing
8398 this would be a major complication for minimal return.
8401 /* Masks for XPM pieces. Black and white pieces can have
8402 different shapes, but in the interest of retaining my
8403 sanity pieces must have the same outline on both light
8404 and dark squares, and all pieces must use the same
8405 background square colors/images. */
8407 static int xpmDone = 0;
8410 CreateAnimMasks (pieceDepth)
8417 unsigned long plane;
8420 /* Need a bitmap just to get a GC with right depth */
8421 buf = XCreatePixmap(xDisplay, xBoardWindow,
8423 values.foreground = 1;
8424 values.background = 0;
8425 /* Don't use XtGetGC, not read only */
8426 maskGC = XCreateGC(xDisplay, buf,
8427 GCForeground | GCBackground, &values);
8428 XFreePixmap(xDisplay, buf);
8430 buf = XCreatePixmap(xDisplay, xBoardWindow,
8431 squareSize, squareSize, pieceDepth);
8432 values.foreground = XBlackPixel(xDisplay, xScreen);
8433 values.background = XWhitePixel(xDisplay, xScreen);
8434 bufGC = XCreateGC(xDisplay, buf,
8435 GCForeground | GCBackground, &values);
8437 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8438 /* Begin with empty mask */
8439 if(!xpmDone) // [HGM] pieces: keep using existing
8440 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8441 squareSize, squareSize, 1);
8442 XSetFunction(xDisplay, maskGC, GXclear);
8443 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8444 0, 0, squareSize, squareSize);
8446 /* Take a copy of the piece */
8451 XSetFunction(xDisplay, bufGC, GXcopy);
8452 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8454 0, 0, squareSize, squareSize, 0, 0);
8456 /* XOR the background (light) over the piece */
8457 XSetFunction(xDisplay, bufGC, GXxor);
8459 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8460 0, 0, squareSize, squareSize, 0, 0);
8462 XSetForeground(xDisplay, bufGC, lightSquareColor);
8463 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8466 /* We now have an inverted piece image with the background
8467 erased. Construct mask by just selecting all the non-zero
8468 pixels - no need to reconstruct the original image. */
8469 XSetFunction(xDisplay, maskGC, GXor);
8471 /* Might be quicker to download an XImage and create bitmap
8472 data from it rather than this N copies per piece, but it
8473 only takes a fraction of a second and there is a much
8474 longer delay for loading the pieces. */
8475 for (n = 0; n < pieceDepth; n ++) {
8476 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8477 0, 0, squareSize, squareSize,
8483 XFreePixmap(xDisplay, buf);
8484 XFreeGC(xDisplay, bufGC);
8485 XFreeGC(xDisplay, maskGC);
8489 InitAnimState (anim, info)
8491 XWindowAttributes * info;
8496 /* Each buffer is square size, same depth as window */
8497 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8498 squareSize, squareSize, info->depth);
8499 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8500 squareSize, squareSize, info->depth);
8502 /* Create a plain GC for blitting */
8503 mask = GCForeground | GCBackground | GCFunction |
8504 GCPlaneMask | GCGraphicsExposures;
8505 values.foreground = XBlackPixel(xDisplay, xScreen);
8506 values.background = XWhitePixel(xDisplay, xScreen);
8507 values.function = GXcopy;
8508 values.plane_mask = AllPlanes;
8509 values.graphics_exposures = False;
8510 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8512 /* Piece will be copied from an existing context at
8513 the start of each new animation/drag. */
8514 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8516 /* Outline will be a read-only copy of an existing */
8517 anim->outlineGC = None;
8523 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8524 XWindowAttributes info;
8526 if (xpmDone && gameInfo.variant == old) return;
8527 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8528 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8530 InitAnimState(&game, &info);
8531 InitAnimState(&player, &info);
8533 /* For XPM pieces, we need bitmaps to use as masks. */
8535 CreateAnimMasks(info.depth);
8541 static Boolean frameWaiting;
8543 static RETSIGTYPE FrameAlarm (sig)
8546 frameWaiting = False;
8547 /* In case System-V style signals. Needed?? */
8548 signal(SIGALRM, FrameAlarm);
8555 struct itimerval delay;
8557 XSync(xDisplay, False);
8560 frameWaiting = True;
8561 signal(SIGALRM, FrameAlarm);
8562 delay.it_interval.tv_sec =
8563 delay.it_value.tv_sec = time / 1000;
8564 delay.it_interval.tv_usec =
8565 delay.it_value.tv_usec = (time % 1000) * 1000;
8566 setitimer(ITIMER_REAL, &delay, NULL);
8567 while (frameWaiting) pause();
8568 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8569 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8570 setitimer(ITIMER_REAL, &delay, NULL);
8580 XSync(xDisplay, False);
8582 usleep(time * 1000);
8587 /* Convert board position to corner of screen rect and color */
8590 ScreenSquare(column, row, pt, color)
8591 int column; int row; XPoint * pt; int * color;
8594 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8595 pt->y = lineGap + row * (squareSize + lineGap);
8597 pt->x = lineGap + column * (squareSize + lineGap);
8598 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8600 *color = SquareColor(row, column);
8603 /* Convert window coords to square */
8606 BoardSquare(x, y, column, row)
8607 int x; int y; int * column; int * row;
8609 *column = EventToSquare(x, BOARD_WIDTH);
8610 if (flipView && *column >= 0)
8611 *column = BOARD_WIDTH - 1 - *column;
8612 *row = EventToSquare(y, BOARD_HEIGHT);
8613 if (!flipView && *row >= 0)
8614 *row = BOARD_HEIGHT - 1 - *row;
8619 #undef Max /* just in case */
8621 #define Max(a, b) ((a) > (b) ? (a) : (b))
8622 #define Min(a, b) ((a) < (b) ? (a) : (b))
8625 SetRect(rect, x, y, width, height)
8626 XRectangle * rect; int x; int y; int width; int height;
8630 rect->width = width;
8631 rect->height = height;
8634 /* Test if two frames overlap. If they do, return
8635 intersection rect within old and location of
8636 that rect within new. */
8639 Intersect(old, new, size, area, pt)
8640 XPoint * old; XPoint * new;
8641 int size; XRectangle * area; XPoint * pt;
8643 if (old->x > new->x + size || new->x > old->x + size ||
8644 old->y > new->y + size || new->y > old->y + size) {
8647 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8648 size - abs(old->x - new->x), size - abs(old->y - new->y));
8649 pt->x = Max(old->x - new->x, 0);
8650 pt->y = Max(old->y - new->y, 0);
8655 /* For two overlapping frames, return the rect(s)
8656 in the old that do not intersect with the new. */
8659 CalcUpdateRects(old, new, size, update, nUpdates)
8660 XPoint * old; XPoint * new; int size;
8661 XRectangle update[]; int * nUpdates;
8665 /* If old = new (shouldn't happen) then nothing to draw */
8666 if (old->x == new->x && old->y == new->y) {
8670 /* Work out what bits overlap. Since we know the rects
8671 are the same size we don't need a full intersect calc. */
8673 /* Top or bottom edge? */
8674 if (new->y > old->y) {
8675 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8677 } else if (old->y > new->y) {
8678 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8679 size, old->y - new->y);
8682 /* Left or right edge - don't overlap any update calculated above. */
8683 if (new->x > old->x) {
8684 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8685 new->x - old->x, size - abs(new->y - old->y));
8687 } else if (old->x > new->x) {
8688 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8689 old->x - new->x, size - abs(new->y - old->y));
8696 /* Generate a series of frame coords from start->mid->finish.
8697 The movement rate doubles until the half way point is
8698 reached, then halves back down to the final destination,
8699 which gives a nice slow in/out effect. The algorithmn
8700 may seem to generate too many intermediates for short
8701 moves, but remember that the purpose is to attract the
8702 viewers attention to the piece about to be moved and
8703 then to where it ends up. Too few frames would be less
8707 Tween(start, mid, finish, factor, frames, nFrames)
8708 XPoint * start; XPoint * mid;
8709 XPoint * finish; int factor;
8710 XPoint frames[]; int * nFrames;
8712 int fraction, n, count;
8716 /* Slow in, stepping 1/16th, then 1/8th, ... */
8718 for (n = 0; n < factor; n++)
8720 for (n = 0; n < factor; n++) {
8721 frames[count].x = start->x + (mid->x - start->x) / fraction;
8722 frames[count].y = start->y + (mid->y - start->y) / fraction;
8724 fraction = fraction / 2;
8728 frames[count] = *mid;
8731 /* Slow out, stepping 1/2, then 1/4, ... */
8733 for (n = 0; n < factor; n++) {
8734 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8735 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8737 fraction = fraction * 2;
8742 /* Draw a piece on the screen without disturbing what's there */
8745 SelectGCMask(piece, clip, outline, mask)
8746 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8750 /* Bitmap for piece being moved. */
8751 if (appData.monoMode) {
8752 *mask = *pieceToSolid(piece);
8753 } else if (useImages) {
8755 *mask = xpmMask[piece];
8757 *mask = ximMaskPm[piece];
8760 *mask = *pieceToSolid(piece);
8763 /* GC for piece being moved. Square color doesn't matter, but
8764 since it gets modified we make a copy of the original. */
8766 if (appData.monoMode)
8771 if (appData.monoMode)
8776 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8778 /* Outline only used in mono mode and is not modified */
8780 *outline = bwPieceGC;
8782 *outline = wbPieceGC;
8786 OverlayPiece(piece, clip, outline, dest)
8787 ChessSquare piece; GC clip; GC outline; Drawable dest;
8792 /* Draw solid rectangle which will be clipped to shape of piece */
8793 XFillRectangle(xDisplay, dest, clip,
8794 0, 0, squareSize, squareSize);
8795 if (appData.monoMode)
8796 /* Also draw outline in contrasting color for black
8797 on black / white on white cases */
8798 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8799 0, 0, squareSize, squareSize, 0, 0, 1);
8801 /* Copy the piece */
8806 if(appData.upsideDown && flipView) kind ^= 2;
8807 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8809 0, 0, squareSize, squareSize,
8814 /* Animate the movement of a single piece */
8817 BeginAnimation(anim, piece, startColor, start)
8825 /* The old buffer is initialised with the start square (empty) */
8826 BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0);
8827 anim->prevFrame = *start;
8829 /* The piece will be drawn using its own bitmap as a matte */
8830 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8831 XSetClipMask(xDisplay, anim->pieceGC, mask);
8835 AnimationFrame(anim, frame, piece)
8840 XRectangle updates[4];
8845 /* Save what we are about to draw into the new buffer */
8846 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8847 frame->x, frame->y, squareSize, squareSize,
8850 /* Erase bits of the previous frame */
8851 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8852 /* Where the new frame overlapped the previous,
8853 the contents in newBuf are wrong. */
8854 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8855 overlap.x, overlap.y,
8856 overlap.width, overlap.height,
8858 /* Repaint the areas in the old that don't overlap new */
8859 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8860 for (i = 0; i < count; i++)
8861 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8862 updates[i].x - anim->prevFrame.x,
8863 updates[i].y - anim->prevFrame.y,
8864 updates[i].width, updates[i].height,
8865 updates[i].x, updates[i].y);
8867 /* Easy when no overlap */
8868 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8869 0, 0, squareSize, squareSize,
8870 anim->prevFrame.x, anim->prevFrame.y);
8873 /* Save this frame for next time round */
8874 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8875 0, 0, squareSize, squareSize,
8877 anim->prevFrame = *frame;
8879 /* Draw piece over original screen contents, not current,
8880 and copy entire rect. Wipes out overlapping piece images. */
8881 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8882 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8883 0, 0, squareSize, squareSize,
8884 frame->x, frame->y);
8888 EndAnimation (anim, finish)
8892 XRectangle updates[4];
8897 /* The main code will redraw the final square, so we
8898 only need to erase the bits that don't overlap. */
8899 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8900 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8901 for (i = 0; i < count; i++)
8902 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8903 updates[i].x - anim->prevFrame.x,
8904 updates[i].y - anim->prevFrame.y,
8905 updates[i].width, updates[i].height,
8906 updates[i].x, updates[i].y);
8908 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8909 0, 0, squareSize, squareSize,
8910 anim->prevFrame.x, anim->prevFrame.y);
8915 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8917 ChessSquare piece; int startColor;
8918 XPoint * start; XPoint * finish;
8919 XPoint frames[]; int nFrames;
8923 BeginAnimation(anim, piece, startColor, start);
8924 for (n = 0; n < nFrames; n++) {
8925 AnimationFrame(anim, &(frames[n]), piece);
8926 FrameDelay(appData.animSpeed);
8928 EndAnimation(anim, finish);
8932 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
8935 ChessSquare piece = board[fromY][toY];
8936 board[fromY][toY] = EmptySquare;
8937 DrawPosition(FALSE, board);
8939 x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap);
8940 y = lineGap + toY * (squareSize + lineGap);
8942 x = lineGap + toX * (squareSize + lineGap);
8943 y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap);
8945 for(i=1; i<4*kFactor; i++) {
8946 int r = squareSize * 9 * i/(20*kFactor - 5);
8947 XFillArc(xDisplay, xBoardWindow, highlineGC,
8948 x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360);
8949 FrameDelay(appData.animSpeed);
8951 board[fromY][toY] = piece;
8954 /* Main control logic for deciding what to animate and how */
8957 AnimateMove(board, fromX, fromY, toX, toY)
8966 XPoint start, finish, mid;
8967 XPoint frames[kFactor * 2 + 1];
8968 int nFrames, startColor, endColor;
8970 /* Are we animating? */
8971 if (!appData.animate || appData.blindfold)
8974 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8975 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8976 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8978 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8979 piece = board[fromY][fromX];
8980 if (piece >= EmptySquare) return;
8985 hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1;
8988 if (appData.debugMode) {
8989 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8990 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8991 piece, fromX, fromY, toX, toY); }
8993 ScreenSquare(fromX, fromY, &start, &startColor);
8994 ScreenSquare(toX, toY, &finish, &endColor);
8997 /* Knight: make straight movement then diagonal */
8998 if (abs(toY - fromY) < abs(toX - fromX)) {
8999 mid.x = start.x + (finish.x - start.x) / 2;
9003 mid.y = start.y + (finish.y - start.y) / 2;
9006 mid.x = start.x + (finish.x - start.x) / 2;
9007 mid.y = start.y + (finish.y - start.y) / 2;
9010 /* Don't use as many frames for very short moves */
9011 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
9012 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
9014 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
9015 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
9016 if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
9018 for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
9019 if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
9022 /* Be sure end square is redrawn */
9023 damage[0][toY][toX] = True;
9027 DragPieceBegin(x, y)
9030 int boardX, boardY, color;
9033 /* Are we animating? */
9034 if (!appData.animateDragging || appData.blindfold)
9037 /* Figure out which square we start in and the
9038 mouse position relative to top left corner. */
9039 BoardSquare(x, y, &boardX, &boardY);
9040 player.startBoardX = boardX;
9041 player.startBoardY = boardY;
9042 ScreenSquare(boardX, boardY, &corner, &color);
9043 player.startSquare = corner;
9044 player.startColor = color;
9045 /* As soon as we start dragging, the piece will jump slightly to
9046 be centered over the mouse pointer. */
9047 player.mouseDelta.x = squareSize/2;
9048 player.mouseDelta.y = squareSize/2;
9049 /* Initialise animation */
9050 player.dragPiece = PieceForSquare(boardX, boardY);
9052 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
9053 player.dragActive = True;
9054 BeginAnimation(&player, player.dragPiece, color, &corner);
9055 /* Mark this square as needing to be redrawn. Note that
9056 we don't remove the piece though, since logically (ie
9057 as seen by opponent) the move hasn't been made yet. */
9058 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
9059 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
9060 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
9061 corner.x, corner.y, squareSize, squareSize,
9062 0, 0); // [HGM] zh: unstack in stead of grab
9063 if(gatingPiece != EmptySquare) {
9064 /* Kludge alert: When gating we want the introduced
9065 piece to appear on the from square. To generate an
9066 image of it, we draw it on the board, copy the image,
9067 and draw the original piece again. */
9068 ChessSquare piece = boards[currentMove][boardY][boardX];
9069 DrawSquare(boardY, boardX, gatingPiece, 0);
9070 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
9071 corner.x, corner.y, squareSize, squareSize, 0, 0);
9072 DrawSquare(boardY, boardX, piece, 0);
9074 damage[0][boardY][boardX] = True;
9076 player.dragActive = False;
9086 /* Are we animating? */
9087 if (!appData.animateDragging || appData.blindfold)
9091 if (! player.dragActive)
9093 /* Move piece, maintaining same relative position
9094 of mouse within square */
9095 corner.x = x - player.mouseDelta.x;
9096 corner.y = y - player.mouseDelta.y;
9097 AnimationFrame(&player, &corner, player.dragPiece);
9099 if (appData.highlightDragging) {
9101 BoardSquare(x, y, &boardX, &boardY);
9102 SetHighlights(fromX, fromY, boardX, boardY);
9111 int boardX, boardY, color;
9114 /* Are we animating? */
9115 if (!appData.animateDragging || appData.blindfold)
9119 if (! player.dragActive)
9121 /* Last frame in sequence is square piece is
9122 placed on, which may not match mouse exactly. */
9123 BoardSquare(x, y, &boardX, &boardY);
9124 ScreenSquare(boardX, boardY, &corner, &color);
9125 EndAnimation(&player, &corner);
9127 /* Be sure end square is redrawn */
9128 damage[0][boardY][boardX] = True;
9130 /* This prevents weird things happening with fast successive
9131 clicks which on my Sun at least can cause motion events
9132 without corresponding press/release. */
9133 player.dragActive = False;
9136 /* Handle expose event while piece being dragged */
9141 if (!player.dragActive || appData.blindfold)
9144 /* What we're doing: logically, the move hasn't been made yet,
9145 so the piece is still in it's original square. But visually
9146 it's being dragged around the board. So we erase the square
9147 that the piece is on and draw it at the last known drag point. */
9148 BlankSquare(player.startSquare.x, player.startSquare.y,
9149 player.startColor, EmptySquare, xBoardWindow, 1);
9150 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
9151 damage[0][player.startBoardY][player.startBoardX] = TRUE;
9154 #include <sys/ioctl.h>
9155 int get_term_width()
9157 int fd, default_width;
9160 default_width = 79; // this is FICS default anyway...
9162 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
9164 if (!ioctl(fd, TIOCGSIZE, &win))
9165 default_width = win.ts_cols;
9166 #elif defined(TIOCGWINSZ)
9168 if (!ioctl(fd, TIOCGWINSZ, &win))
9169 default_width = win.ws_col;
9171 return default_width;
9177 static int old_width = 0;
9178 int new_width = get_term_width();
9180 if (old_width != new_width)
9181 ics_printf("set width %d\n", new_width);
9182 old_width = new_width;
9185 void NotifyFrontendLogin()
9190 # if HAVE_LIBREADLINE
9192 ReadlineCompleteHandler(char* ptr)
9194 /* make gnu-readline keep the history */
9195 readline_buffer = ptr;
9196 readline_complete = 1;
9198 if (ptr && *ptr && !sending_ICS_password && !sending_ICS_login)