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];
1735 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1736 for(p=0; p<=(int)WhiteKing; p++)
1737 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1738 if(gameInfo.variant == VariantShogi) {
1739 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1740 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1741 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1742 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1743 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1746 if(gameInfo.variant == VariantGothic) {
1747 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1753 for(i=0; i<2; i++) {
1755 for(p=0; p<=(int)WhiteKing; p++)
1756 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1757 if(gameInfo.variant == VariantShogi) {
1758 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1759 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1760 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1761 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1762 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1765 if(gameInfo.variant == VariantGothic) {
1766 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1782 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1783 XSetWindowAttributes window_attributes;
1785 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1786 XrmValue vFrom, vTo;
1787 XtGeometryResult gres;
1790 int forceMono = False;
1792 srandom(time(0)); // [HGM] book: make random truly random
1794 setbuf(stdout, NULL);
1795 setbuf(stderr, NULL);
1798 # if HAVE_LIBREADLINE
1799 /* install gnu-readline handler */
1800 rl_callback_handler_install("> ", ReadlineCompleteHandler);
1801 rl_readline_name="XBoard";
1804 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1805 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1809 programName = strrchr(argv[0], '/');
1810 if (programName == NULL)
1811 programName = argv[0];
1816 XtSetLanguageProc(NULL, NULL, NULL);
1817 bindtextdomain(PACKAGE, LOCALEDIR);
1818 textdomain(PACKAGE);
1822 XtAppInitialize(&appContext, "XBoard", shellOptions,
1823 XtNumber(shellOptions),
1824 &argc, argv, xboardResources, NULL, 0);
1825 appData.boardSize = "";
1826 InitAppData(ConvertToLine(argc, argv));
1828 if (p == NULL) p = "/tmp";
1829 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1830 gameCopyFilename = (char*) malloc(i);
1831 gamePasteFilename = (char*) malloc(i);
1832 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1833 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1835 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1836 clientResources, XtNumber(clientResources),
1839 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1840 static char buf[MSG_SIZ];
1841 EscapeExpand(buf, appData.initString);
1842 appData.initString = strdup(buf);
1843 EscapeExpand(buf, appData.secondInitString);
1844 appData.secondInitString = strdup(buf);
1845 EscapeExpand(buf, appData.firstComputerString);
1846 appData.firstComputerString = strdup(buf);
1847 EscapeExpand(buf, appData.secondComputerString);
1848 appData.secondComputerString = strdup(buf);
1851 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1854 if (chdir(chessDir) != 0) {
1855 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1861 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1862 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1863 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1864 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1867 setbuf(debugFP, NULL);
1870 /* [HGM,HR] make sure board size is acceptable */
1871 if(appData.NrFiles > BOARD_FILES ||
1872 appData.NrRanks > BOARD_RANKS )
1873 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1876 /* This feature does not work; animation needs a rewrite */
1877 appData.highlightDragging = FALSE;
1881 xDisplay = XtDisplay(shellWidget);
1882 xScreen = DefaultScreen(xDisplay);
1883 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1885 gameInfo.variant = StringToVariant(appData.variant);
1886 InitPosition(FALSE);
1889 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1891 if (isdigit(appData.boardSize[0])) {
1892 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1893 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1894 &fontPxlSize, &smallLayout, &tinyLayout);
1896 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1897 programName, appData.boardSize);
1901 /* Find some defaults; use the nearest known size */
1902 SizeDefaults *szd, *nearest;
1903 int distance = 99999;
1904 nearest = szd = sizeDefaults;
1905 while (szd->name != NULL) {
1906 if (abs(szd->squareSize - squareSize) < distance) {
1908 distance = abs(szd->squareSize - squareSize);
1909 if (distance == 0) break;
1913 if (i < 2) lineGap = nearest->lineGap;
1914 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1915 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1916 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1917 if (i < 6) smallLayout = nearest->smallLayout;
1918 if (i < 7) tinyLayout = nearest->tinyLayout;
1921 SizeDefaults *szd = sizeDefaults;
1922 if (*appData.boardSize == NULLCHAR) {
1923 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1924 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1927 if (szd->name == NULL) szd--;
1928 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1930 while (szd->name != NULL &&
1931 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1932 if (szd->name == NULL) {
1933 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1934 programName, appData.boardSize);
1938 squareSize = szd->squareSize;
1939 lineGap = szd->lineGap;
1940 clockFontPxlSize = szd->clockFontPxlSize;
1941 coordFontPxlSize = szd->coordFontPxlSize;
1942 fontPxlSize = szd->fontPxlSize;
1943 smallLayout = szd->smallLayout;
1944 tinyLayout = szd->tinyLayout;
1945 // [HGM] font: use defaults from settings file if available and not overruled
1947 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
1948 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
1949 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
1950 appData.font = fontTable[MESSAGE_FONT][squareSize];
1951 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
1952 appData.coordFont = fontTable[COORD_FONT][squareSize];
1954 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1955 if (strlen(appData.pixmapDirectory) > 0) {
1956 p = ExpandPathName(appData.pixmapDirectory);
1958 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1959 appData.pixmapDirectory);
1962 if (appData.debugMode) {
1963 fprintf(stderr, _("\
1964 XBoard square size (hint): %d\n\
1965 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1967 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1968 if (appData.debugMode) {
1969 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1972 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1974 /* [HR] height treated separately (hacked) */
1975 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1976 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1977 if (appData.showJail == 1) {
1978 /* Jail on top and bottom */
1979 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1980 XtSetArg(boardArgs[2], XtNheight,
1981 boardHeight + 2*(lineGap + squareSize));
1982 } else if (appData.showJail == 2) {
1984 XtSetArg(boardArgs[1], XtNwidth,
1985 boardWidth + 2*(lineGap + squareSize));
1986 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1989 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1990 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1994 * Determine what fonts to use.
1996 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1997 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1998 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1999 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2000 coordFontID = XLoadFont(xDisplay, appData.coordFont);
2001 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2002 appData.font = FindFont(appData.font, fontPxlSize);
2003 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
2004 countFontStruct = XQueryFont(xDisplay, countFontID);
2005 // appData.font = FindFont(appData.font, fontPxlSize);
2007 xdb = XtDatabase(xDisplay);
2008 XrmPutStringResource(&xdb, "*font", appData.font);
2011 * Detect if there are not enough colors available and adapt.
2013 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2014 appData.monoMode = True;
2017 if (!appData.monoMode) {
2018 vFrom.addr = (caddr_t) appData.lightSquareColor;
2019 vFrom.size = strlen(appData.lightSquareColor);
2020 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2021 if (vTo.addr == NULL) {
2022 appData.monoMode = True;
2025 lightSquareColor = *(Pixel *) vTo.addr;
2028 if (!appData.monoMode) {
2029 vFrom.addr = (caddr_t) appData.darkSquareColor;
2030 vFrom.size = strlen(appData.darkSquareColor);
2031 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2032 if (vTo.addr == NULL) {
2033 appData.monoMode = True;
2036 darkSquareColor = *(Pixel *) vTo.addr;
2039 if (!appData.monoMode) {
2040 vFrom.addr = (caddr_t) appData.whitePieceColor;
2041 vFrom.size = strlen(appData.whitePieceColor);
2042 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2043 if (vTo.addr == NULL) {
2044 appData.monoMode = True;
2047 whitePieceColor = *(Pixel *) vTo.addr;
2050 if (!appData.monoMode) {
2051 vFrom.addr = (caddr_t) appData.blackPieceColor;
2052 vFrom.size = strlen(appData.blackPieceColor);
2053 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2054 if (vTo.addr == NULL) {
2055 appData.monoMode = True;
2058 blackPieceColor = *(Pixel *) vTo.addr;
2062 if (!appData.monoMode) {
2063 vFrom.addr = (caddr_t) appData.highlightSquareColor;
2064 vFrom.size = strlen(appData.highlightSquareColor);
2065 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2066 if (vTo.addr == NULL) {
2067 appData.monoMode = True;
2070 highlightSquareColor = *(Pixel *) vTo.addr;
2074 if (!appData.monoMode) {
2075 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
2076 vFrom.size = strlen(appData.premoveHighlightColor);
2077 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2078 if (vTo.addr == NULL) {
2079 appData.monoMode = True;
2082 premoveHighlightColor = *(Pixel *) vTo.addr;
2087 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2090 if (appData.bitmapDirectory == NULL ||
2091 appData.bitmapDirectory[0] == NULLCHAR)
2092 appData.bitmapDirectory = DEF_BITMAP_DIR;
2095 if (appData.lowTimeWarning && !appData.monoMode) {
2096 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2097 vFrom.size = strlen(appData.lowTimeWarningColor);
2098 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2099 if (vTo.addr == NULL)
2100 appData.monoMode = True;
2102 lowTimeWarningColor = *(Pixel *) vTo.addr;
2105 if (appData.monoMode && appData.debugMode) {
2106 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2107 (unsigned long) XWhitePixel(xDisplay, xScreen),
2108 (unsigned long) XBlackPixel(xDisplay, xScreen));
2111 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2112 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2113 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2114 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2115 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2116 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2117 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2118 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2119 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2120 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2122 if (appData.colorize) {
2124 _("%s: can't parse color names; disabling colorization\n"),
2127 appData.colorize = FALSE;
2129 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2130 textColors[ColorNone].attr = 0;
2132 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2138 layoutName = "tinyLayout";
2139 } else if (smallLayout) {
2140 layoutName = "smallLayout";
2142 layoutName = "normalLayout";
2144 /* Outer layoutWidget is there only to provide a name for use in
2145 resources that depend on the layout style */
2147 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2148 layoutArgs, XtNumber(layoutArgs));
2150 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2151 formArgs, XtNumber(formArgs));
2152 XtSetArg(args[0], XtNdefaultDistance, &sep);
2153 XtGetValues(formWidget, args, 1);
2156 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2157 XtSetArg(args[0], XtNtop, XtChainTop);
2158 XtSetArg(args[1], XtNbottom, XtChainTop);
2159 XtSetArg(args[2], XtNright, XtChainLeft);
2160 XtSetValues(menuBarWidget, args, 3);
2162 widgetList[j++] = whiteTimerWidget =
2163 XtCreateWidget("whiteTime", labelWidgetClass,
2164 formWidget, timerArgs, XtNumber(timerArgs));
2165 XtSetArg(args[0], XtNfont, clockFontStruct);
2166 XtSetArg(args[1], XtNtop, XtChainTop);
2167 XtSetArg(args[2], XtNbottom, XtChainTop);
2168 XtSetValues(whiteTimerWidget, args, 3);
2170 widgetList[j++] = blackTimerWidget =
2171 XtCreateWidget("blackTime", labelWidgetClass,
2172 formWidget, timerArgs, XtNumber(timerArgs));
2173 XtSetArg(args[0], XtNfont, clockFontStruct);
2174 XtSetArg(args[1], XtNtop, XtChainTop);
2175 XtSetArg(args[2], XtNbottom, XtChainTop);
2176 XtSetValues(blackTimerWidget, args, 3);
2178 if (appData.titleInWindow) {
2179 widgetList[j++] = titleWidget =
2180 XtCreateWidget("title", labelWidgetClass, formWidget,
2181 titleArgs, XtNumber(titleArgs));
2182 XtSetArg(args[0], XtNtop, XtChainTop);
2183 XtSetArg(args[1], XtNbottom, XtChainTop);
2184 XtSetValues(titleWidget, args, 2);
2187 if (appData.showButtonBar) {
2188 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2189 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2190 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2191 XtSetArg(args[2], XtNtop, XtChainTop);
2192 XtSetArg(args[3], XtNbottom, XtChainTop);
2193 XtSetValues(buttonBarWidget, args, 4);
2196 widgetList[j++] = messageWidget =
2197 XtCreateWidget("message", labelWidgetClass, formWidget,
2198 messageArgs, XtNumber(messageArgs));
2199 XtSetArg(args[0], XtNtop, XtChainTop);
2200 XtSetArg(args[1], XtNbottom, XtChainTop);
2201 XtSetValues(messageWidget, args, 2);
2203 widgetList[j++] = boardWidget =
2204 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2205 XtNumber(boardArgs));
2207 XtManageChildren(widgetList, j);
2209 timerWidth = (boardWidth - sep) / 2;
2210 XtSetArg(args[0], XtNwidth, timerWidth);
2211 XtSetValues(whiteTimerWidget, args, 1);
2212 XtSetValues(blackTimerWidget, args, 1);
2214 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2215 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2216 XtGetValues(whiteTimerWidget, args, 2);
2218 if (appData.showButtonBar) {
2219 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2220 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2221 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2225 * formWidget uses these constraints but they are stored
2229 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2230 XtSetValues(menuBarWidget, args, i);
2231 if (appData.titleInWindow) {
2234 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2235 XtSetValues(whiteTimerWidget, args, i);
2237 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2238 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2239 XtSetValues(blackTimerWidget, args, i);
2241 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2242 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2243 XtSetValues(titleWidget, args, i);
2245 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2246 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2247 XtSetValues(messageWidget, args, i);
2248 if (appData.showButtonBar) {
2250 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2251 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2252 XtSetValues(buttonBarWidget, args, i);
2256 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2257 XtSetValues(whiteTimerWidget, args, i);
2259 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2260 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2261 XtSetValues(blackTimerWidget, args, i);
2263 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2264 XtSetValues(titleWidget, args, i);
2266 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2267 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2268 XtSetValues(messageWidget, args, i);
2269 if (appData.showButtonBar) {
2271 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2272 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2273 XtSetValues(buttonBarWidget, args, i);
2278 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2279 XtSetValues(whiteTimerWidget, args, i);
2281 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2282 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2283 XtSetValues(blackTimerWidget, args, i);
2285 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2286 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2287 XtSetValues(messageWidget, args, i);
2288 if (appData.showButtonBar) {
2290 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2291 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2292 XtSetValues(buttonBarWidget, args, i);
2296 XtSetArg(args[0], XtNfromVert, messageWidget);
2297 XtSetArg(args[1], XtNtop, XtChainTop);
2298 XtSetArg(args[2], XtNbottom, XtChainBottom);
2299 XtSetArg(args[3], XtNleft, XtChainLeft);
2300 XtSetArg(args[4], XtNright, XtChainRight);
2301 XtSetValues(boardWidget, args, 5);
2303 XtRealizeWidget(shellWidget);
2306 XtSetArg(args[0], XtNx, wpMain.x);
2307 XtSetArg(args[1], XtNy, wpMain.y);
2308 XtSetValues(shellWidget, args, 2);
2312 * Correct the width of the message and title widgets.
2313 * It is not known why some systems need the extra fudge term.
2314 * The value "2" is probably larger than needed.
2316 XawFormDoLayout(formWidget, False);
2318 #define WIDTH_FUDGE 2
2320 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2321 XtSetArg(args[i], XtNheight, &h); i++;
2322 XtGetValues(messageWidget, args, i);
2323 if (appData.showButtonBar) {
2325 XtSetArg(args[i], XtNwidth, &w); i++;
2326 XtGetValues(buttonBarWidget, args, i);
2327 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2329 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2332 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2333 if (gres != XtGeometryYes && appData.debugMode) {
2334 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2335 programName, gres, w, h, wr, hr);
2338 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2339 /* The size used for the child widget in layout lags one resize behind
2340 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2342 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2343 if (gres != XtGeometryYes && appData.debugMode) {
2344 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2345 programName, gres, w, h, wr, hr);
2348 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2349 XtSetArg(args[1], XtNright, XtChainRight);
2350 XtSetValues(messageWidget, args, 2);
2352 if (appData.titleInWindow) {
2354 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2355 XtSetArg(args[i], XtNheight, &h); i++;
2356 XtGetValues(titleWidget, args, i);
2358 w = boardWidth - 2*bor;
2360 XtSetArg(args[0], XtNwidth, &w);
2361 XtGetValues(menuBarWidget, args, 1);
2362 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2365 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2366 if (gres != XtGeometryYes && appData.debugMode) {
2368 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2369 programName, gres, w, h, wr, hr);
2372 XawFormDoLayout(formWidget, True);
2374 xBoardWindow = XtWindow(boardWidget);
2376 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2377 // not need to go into InitDrawingSizes().
2381 * Create X checkmark bitmap and initialize option menu checks.
2383 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2384 checkmark_bits, checkmark_width, checkmark_height);
2385 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2386 if (appData.alwaysPromoteToQueen) {
2387 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2390 if (appData.animateDragging) {
2391 XtSetValues(XtNameToWidget(menuBarWidget,
2392 "menuOptions.Animate Dragging"),
2395 if (appData.animate) {
2396 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2399 if (appData.autoComment) {
2400 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2403 if (appData.autoCallFlag) {
2404 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2407 if (appData.autoFlipView) {
2408 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2411 if (appData.autoObserve) {
2412 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2415 if (appData.autoRaiseBoard) {
2416 XtSetValues(XtNameToWidget(menuBarWidget,
2417 "menuOptions.Auto Raise Board"), args, 1);
2419 if (appData.autoSaveGames) {
2420 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2423 if (appData.saveGameFile[0] != NULLCHAR) {
2424 /* Can't turn this off from menu */
2425 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2427 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2431 if (appData.blindfold) {
2432 XtSetValues(XtNameToWidget(menuBarWidget,
2433 "menuOptions.Blindfold"), args, 1);
2435 if (appData.flashCount > 0) {
2436 XtSetValues(XtNameToWidget(menuBarWidget,
2437 "menuOptions.Flash Moves"),
2440 if (appData.getMoveList) {
2441 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2445 if (appData.highlightDragging) {
2446 XtSetValues(XtNameToWidget(menuBarWidget,
2447 "menuOptions.Highlight Dragging"),
2451 if (appData.highlightLastMove) {
2452 XtSetValues(XtNameToWidget(menuBarWidget,
2453 "menuOptions.Highlight Last Move"),
2456 if (appData.icsAlarm) {
2457 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2460 if (appData.ringBellAfterMoves) {
2461 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2464 if (appData.oldSaveStyle) {
2465 XtSetValues(XtNameToWidget(menuBarWidget,
2466 "menuOptions.Old Save Style"), args, 1);
2468 if (appData.periodicUpdates) {
2469 XtSetValues(XtNameToWidget(menuBarWidget,
2470 "menuOptions.Periodic Updates"), args, 1);
2472 if (appData.ponderNextMove) {
2473 XtSetValues(XtNameToWidget(menuBarWidget,
2474 "menuOptions.Ponder Next Move"), args, 1);
2476 if (appData.popupExitMessage) {
2477 XtSetValues(XtNameToWidget(menuBarWidget,
2478 "menuOptions.Popup Exit Message"), args, 1);
2480 if (appData.popupMoveErrors) {
2481 XtSetValues(XtNameToWidget(menuBarWidget,
2482 "menuOptions.Popup Move Errors"), args, 1);
2484 if (appData.premove) {
2485 XtSetValues(XtNameToWidget(menuBarWidget,
2486 "menuOptions.Premove"), args, 1);
2488 if (appData.quietPlay) {
2489 XtSetValues(XtNameToWidget(menuBarWidget,
2490 "menuOptions.Quiet Play"), args, 1);
2492 if (appData.showCoords) {
2493 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2496 if (appData.hideThinkingFromHuman) {
2497 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2500 if (appData.testLegality) {
2501 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2504 if (saveSettingsOnExit) {
2505 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2512 ReadBitmap(&wIconPixmap, "icon_white.bm",
2513 icon_white_bits, icon_white_width, icon_white_height);
2514 ReadBitmap(&bIconPixmap, "icon_black.bm",
2515 icon_black_bits, icon_black_width, icon_black_height);
2516 iconPixmap = wIconPixmap;
2518 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2519 XtSetValues(shellWidget, args, i);
2522 * Create a cursor for the board widget.
2524 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2525 XChangeWindowAttributes(xDisplay, xBoardWindow,
2526 CWCursor, &window_attributes);
2529 * Inhibit shell resizing.
2531 shellArgs[0].value = (XtArgVal) &w;
2532 shellArgs[1].value = (XtArgVal) &h;
2533 XtGetValues(shellWidget, shellArgs, 2);
2534 shellArgs[4].value = shellArgs[2].value = w;
2535 shellArgs[5].value = shellArgs[3].value = h;
2536 XtSetValues(shellWidget, &shellArgs[2], 4);
2537 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2538 marginH = h - boardHeight;
2540 CatchDeleteWindow(shellWidget, "QuitProc");
2545 if (appData.bitmapDirectory[0] != NULLCHAR) {
2549 CreateXPMBoard(appData.liteBackTextureFile, 1);
2550 CreateXPMBoard(appData.darkBackTextureFile, 0);
2554 /* Create regular pieces */
2555 if (!useImages) CreatePieces();
2560 if (appData.animate || appData.animateDragging)
2563 XtAugmentTranslations(formWidget,
2564 XtParseTranslationTable(globalTranslations));
2565 XtAugmentTranslations(boardWidget,
2566 XtParseTranslationTable(boardTranslations));
2567 XtAugmentTranslations(whiteTimerWidget,
2568 XtParseTranslationTable(whiteTranslations));
2569 XtAugmentTranslations(blackTimerWidget,
2570 XtParseTranslationTable(blackTranslations));
2572 /* Why is the following needed on some versions of X instead
2573 * of a translation? */
2574 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2575 (XtEventHandler) EventProc, NULL);
2578 /* [AS] Restore layout */
2579 if( wpMoveHistory.visible ) {
2583 if( wpEvalGraph.visible )
2588 if( wpEngineOutput.visible ) {
2589 EngineOutputPopUp();
2594 if (errorExitStatus == -1) {
2595 if (appData.icsActive) {
2596 /* We now wait until we see "login:" from the ICS before
2597 sending the logon script (problems with timestamp otherwise) */
2598 /*ICSInitScript();*/
2599 if (appData.icsInputBox) ICSInputBoxPopUp();
2603 signal(SIGWINCH, TermSizeSigHandler);
2605 signal(SIGINT, IntSigHandler);
2606 signal(SIGTERM, IntSigHandler);
2607 if (*appData.cmailGameName != NULLCHAR) {
2608 signal(SIGUSR1, CmailSigHandler);
2611 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2613 XtSetKeyboardFocus(shellWidget, formWidget);
2615 XtAppMainLoop(appContext);
2616 if (appData.debugMode) fclose(debugFP); // [DM] debug
2623 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2624 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2626 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2627 unlink(gameCopyFilename);
2628 unlink(gamePasteFilename);
2630 # if HAVE_LIBREADLINE
2631 /* remove gnu-readline handler. */
2632 rl_callback_handler_remove();
2638 RETSIGTYPE TermSizeSigHandler(int sig)
2651 CmailSigHandler(sig)
2657 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2659 /* Activate call-back function CmailSigHandlerCallBack() */
2660 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2662 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2666 CmailSigHandlerCallBack(isr, closure, message, count, error)
2674 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2676 /**** end signal code ****/
2682 /* try to open the icsLogon script, either in the location given
2683 * or in the users HOME directory
2690 f = fopen(appData.icsLogon, "r");
2693 homedir = getenv("HOME");
2694 if (homedir != NULL)
2696 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2697 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2698 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2699 f = fopen(buf, "r");
2704 ProcessICSInitScript(f);
2706 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2715 EditCommentPopDown();
2730 if (!menuBarWidget) return;
2731 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2733 DisplayError("menuStep.Revert", 0);
2735 XtSetSensitive(w, !grey);
2737 w = XtNameToWidget(menuBarWidget, "menuStep.Annotate");
2739 DisplayError("menuStep.Annotate", 0);
2741 XtSetSensitive(w, !grey);
2746 SetMenuEnables(enab)
2750 if (!menuBarWidget) return;
2751 while (enab->name != NULL) {
2752 w = XtNameToWidget(menuBarWidget, enab->name);
2754 DisplayError(enab->name, 0);
2756 XtSetSensitive(w, enab->value);
2762 Enables icsEnables[] = {
2763 { "menuFile.Mail Move", False },
2764 { "menuFile.Reload CMail Message", False },
2765 { "menuMode.Machine Black", False },
2766 { "menuMode.Machine White", False },
2767 { "menuMode.Analysis Mode", False },
2768 { "menuMode.Analyze File", False },
2769 { "menuMode.Two Machines", False },
2771 { "menuHelp.Hint", False },
2772 { "menuHelp.Book", False },
2773 { "menuStep.Move Now", False },
2774 { "menuOptions.Periodic Updates", False },
2775 { "menuOptions.Hide Thinking", False },
2776 { "menuOptions.Ponder Next Move", False },
2778 { "menuStep.Annotate", False },
2782 Enables ncpEnables[] = {
2783 { "menuFile.Mail Move", False },
2784 { "menuFile.Reload CMail Message", False },
2785 { "menuMode.Machine White", False },
2786 { "menuMode.Machine Black", False },
2787 { "menuMode.Analysis Mode", False },
2788 { "menuMode.Analyze File", False },
2789 { "menuMode.Two Machines", False },
2790 { "menuMode.ICS Client", False },
2791 { "menuMode.ICS Input Box", False },
2792 { "Action", False },
2793 { "menuStep.Revert", False },
2794 { "menuStep.Annotate", False },
2795 { "menuStep.Move Now", False },
2796 { "menuStep.Retract Move", False },
2797 { "menuOptions.Auto Comment", False },
2798 { "menuOptions.Auto Flag", False },
2799 { "menuOptions.Auto Flip View", False },
2800 { "menuOptions.Auto Observe", False },
2801 { "menuOptions.Auto Raise Board", False },
2802 { "menuOptions.Get Move List", False },
2803 { "menuOptions.ICS Alarm", False },
2804 { "menuOptions.Move Sound", False },
2805 { "menuOptions.Quiet Play", False },
2806 { "menuOptions.Hide Thinking", False },
2807 { "menuOptions.Periodic Updates", False },
2808 { "menuOptions.Ponder Next Move", False },
2809 { "menuHelp.Hint", False },
2810 { "menuHelp.Book", False },
2814 Enables gnuEnables[] = {
2815 { "menuMode.ICS Client", False },
2816 { "menuMode.ICS Input Box", False },
2817 { "menuAction.Accept", False },
2818 { "menuAction.Decline", False },
2819 { "menuAction.Rematch", False },
2820 { "menuAction.Adjourn", False },
2821 { "menuAction.Stop Examining", False },
2822 { "menuAction.Stop Observing", False },
2823 { "menuAction.Upload to Examine", False },
2824 { "menuStep.Revert", False },
2825 { "menuStep.Annotate", False },
2826 { "menuOptions.Auto Comment", False },
2827 { "menuOptions.Auto Observe", False },
2828 { "menuOptions.Auto Raise Board", False },
2829 { "menuOptions.Get Move List", False },
2830 { "menuOptions.Premove", False },
2831 { "menuOptions.Quiet Play", False },
2833 /* The next two options rely on SetCmailMode being called *after* */
2834 /* SetGNUMode so that when GNU is being used to give hints these */
2835 /* menu options are still available */
2837 { "menuFile.Mail Move", False },
2838 { "menuFile.Reload CMail Message", False },
2842 Enables cmailEnables[] = {
2844 { "menuAction.Call Flag", False },
2845 { "menuAction.Draw", True },
2846 { "menuAction.Adjourn", False },
2847 { "menuAction.Abort", False },
2848 { "menuAction.Stop Observing", False },
2849 { "menuAction.Stop Examining", False },
2850 { "menuFile.Mail Move", True },
2851 { "menuFile.Reload CMail Message", True },
2855 Enables trainingOnEnables[] = {
2856 { "menuMode.Edit Comment", False },
2857 { "menuMode.Pause", False },
2858 { "menuStep.Forward", False },
2859 { "menuStep.Backward", False },
2860 { "menuStep.Forward to End", False },
2861 { "menuStep.Back to Start", False },
2862 { "menuStep.Move Now", False },
2863 { "menuStep.Truncate Game", False },
2867 Enables trainingOffEnables[] = {
2868 { "menuMode.Edit Comment", True },
2869 { "menuMode.Pause", True },
2870 { "menuStep.Forward", True },
2871 { "menuStep.Backward", True },
2872 { "menuStep.Forward to End", True },
2873 { "menuStep.Back to Start", True },
2874 { "menuStep.Move Now", True },
2875 { "menuStep.Truncate Game", True },
2879 Enables machineThinkingEnables[] = {
2880 { "menuFile.Load Game", False },
2881 { "menuFile.Load Next Game", False },
2882 { "menuFile.Load Previous Game", False },
2883 { "menuFile.Reload Same Game", False },
2884 { "menuFile.Paste Game", False },
2885 { "menuFile.Load Position", False },
2886 { "menuFile.Load Next Position", False },
2887 { "menuFile.Load Previous Position", False },
2888 { "menuFile.Reload Same Position", False },
2889 { "menuFile.Paste Position", False },
2890 { "menuMode.Machine White", False },
2891 { "menuMode.Machine Black", False },
2892 { "menuMode.Two Machines", False },
2893 { "menuStep.Retract Move", False },
2897 Enables userThinkingEnables[] = {
2898 { "menuFile.Load Game", True },
2899 { "menuFile.Load Next Game", True },
2900 { "menuFile.Load Previous Game", True },
2901 { "menuFile.Reload Same Game", True },
2902 { "menuFile.Paste Game", True },
2903 { "menuFile.Load Position", True },
2904 { "menuFile.Load Next Position", True },
2905 { "menuFile.Load Previous Position", True },
2906 { "menuFile.Reload Same Position", True },
2907 { "menuFile.Paste Position", True },
2908 { "menuMode.Machine White", True },
2909 { "menuMode.Machine Black", True },
2910 { "menuMode.Two Machines", True },
2911 { "menuStep.Retract Move", True },
2917 SetMenuEnables(icsEnables);
2920 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2921 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2928 SetMenuEnables(ncpEnables);
2934 SetMenuEnables(gnuEnables);
2940 SetMenuEnables(cmailEnables);
2946 SetMenuEnables(trainingOnEnables);
2947 if (appData.showButtonBar) {
2948 XtSetSensitive(buttonBarWidget, False);
2954 SetTrainingModeOff()
2956 SetMenuEnables(trainingOffEnables);
2957 if (appData.showButtonBar) {
2958 XtSetSensitive(buttonBarWidget, True);
2963 SetUserThinkingEnables()
2965 if (appData.noChessProgram) return;
2966 SetMenuEnables(userThinkingEnables);
2970 SetMachineThinkingEnables()
2972 if (appData.noChessProgram) return;
2973 SetMenuEnables(machineThinkingEnables);
2975 case MachinePlaysBlack:
2976 case MachinePlaysWhite:
2977 case TwoMachinesPlay:
2978 XtSetSensitive(XtNameToWidget(menuBarWidget,
2979 ModeToWidgetName(gameMode)), True);
2986 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2987 #define HISTORY_SIZE 64
\r
2988 static char *history[HISTORY_SIZE];
\r
2989 int histIn = 0, histP = 0;
\r
2992 SaveInHistory(char *cmd)
\r
2994 if (history[histIn] != NULL) {
\r
2995 free(history[histIn]);
\r
2996 history[histIn] = NULL;
\r
2998 if (*cmd == NULLCHAR) return;
\r
2999 history[histIn] = StrSave(cmd);
\r
3000 histIn = (histIn + 1) % HISTORY_SIZE;
\r
3001 if (history[histIn] != NULL) {
\r
3002 free(history[histIn]);
\r
3003 history[histIn] = NULL;
\r
3009 PrevInHistory(char *cmd)
\r
3012 if (histP == histIn) {
\r
3013 if (history[histIn] != NULL) free(history[histIn]);
\r
3014 history[histIn] = StrSave(cmd);
\r
3016 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
3017 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
3019 return history[histP];
\r
3025 if (histP == histIn) return NULL;
\r
3026 histP = (histP + 1) % HISTORY_SIZE;
\r
3027 return history[histP];
\r
3029 // end of borrowed code
\r
3031 #define Abs(n) ((n)<0 ? -(n) : (n))
3034 * Find a font that matches "pattern" that is as close as
3035 * possible to the targetPxlSize. Prefer fonts that are k
3036 * pixels smaller to fonts that are k pixels larger. The
3037 * pattern must be in the X Consortium standard format,
3038 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3039 * The return value should be freed with XtFree when no
3043 FindFont(pattern, targetPxlSize)
3047 char **fonts, *p, *best, *scalable, *scalableTail;
3048 int i, j, nfonts, minerr, err, pxlSize;
3051 char **missing_list;
3053 char *def_string, *base_fnt_lst, strInt[3];
3055 XFontStruct **fnt_list;
3057 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3058 snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
3059 p = strstr(pattern, "--");
3060 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3061 strcat(base_fnt_lst, strInt);
3062 strcat(base_fnt_lst, strchr(p + 2, '-'));
3064 if ((fntSet = XCreateFontSet(xDisplay,
3068 &def_string)) == NULL) {
3070 fprintf(stderr, _("Unable to create font set.\n"));
3074 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3076 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3078 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3079 programName, pattern);
3087 for (i=0; i<nfonts; i++) {
3090 if (*p != '-') continue;
3092 if (*p == NULLCHAR) break;
3093 if (*p++ == '-') j++;
3095 if (j < 7) continue;
3098 scalable = fonts[i];
3101 err = pxlSize - targetPxlSize;
3102 if (Abs(err) < Abs(minerr) ||
3103 (minerr > 0 && err < 0 && -err == minerr)) {
3109 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3110 /* If the error is too big and there is a scalable font,
3111 use the scalable font. */
3112 int headlen = scalableTail - scalable;
3113 p = (char *) XtMalloc(strlen(scalable) + 10);
3114 while (isdigit(*scalableTail)) scalableTail++;
3115 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3117 p = (char *) XtMalloc(strlen(best) + 2);
3118 safeStrCpy(p, best, strlen(best)+1 );
3120 if (appData.debugMode) {
3121 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3122 pattern, targetPxlSize, p);
3125 if (missing_count > 0)
3126 XFreeStringList(missing_list);
3127 XFreeFontSet(xDisplay, fntSet);
3129 XFreeFontNames(fonts);
3136 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3137 | GCBackground | GCFunction | GCPlaneMask;
3138 XGCValues gc_values;
3141 gc_values.plane_mask = AllPlanes;
3142 gc_values.line_width = lineGap;
3143 gc_values.line_style = LineSolid;
3144 gc_values.function = GXcopy;
3146 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3147 gc_values.background = XBlackPixel(xDisplay, xScreen);
3148 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3150 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3151 gc_values.background = XWhitePixel(xDisplay, xScreen);
3152 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3153 XSetFont(xDisplay, coordGC, coordFontID);
3155 // [HGM] make font for holdings counts (white on black0
3156 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3157 gc_values.background = XBlackPixel(xDisplay, xScreen);
3158 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3159 XSetFont(xDisplay, countGC, countFontID);
3161 if (appData.monoMode) {
3162 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3163 gc_values.background = XWhitePixel(xDisplay, xScreen);
3164 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3166 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3167 gc_values.background = XBlackPixel(xDisplay, xScreen);
3168 lightSquareGC = wbPieceGC
3169 = XtGetGC(shellWidget, value_mask, &gc_values);
3171 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3172 gc_values.background = XWhitePixel(xDisplay, xScreen);
3173 darkSquareGC = bwPieceGC
3174 = XtGetGC(shellWidget, value_mask, &gc_values);
3176 if (DefaultDepth(xDisplay, xScreen) == 1) {
3177 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3178 gc_values.function = GXcopyInverted;
3179 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3180 gc_values.function = GXcopy;
3181 if (XBlackPixel(xDisplay, xScreen) == 1) {
3182 bwPieceGC = darkSquareGC;
3183 wbPieceGC = copyInvertedGC;
3185 bwPieceGC = copyInvertedGC;
3186 wbPieceGC = lightSquareGC;
3190 gc_values.foreground = highlightSquareColor;
3191 gc_values.background = highlightSquareColor;
3192 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3194 gc_values.foreground = premoveHighlightColor;
3195 gc_values.background = premoveHighlightColor;
3196 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3198 gc_values.foreground = lightSquareColor;
3199 gc_values.background = darkSquareColor;
3200 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3202 gc_values.foreground = darkSquareColor;
3203 gc_values.background = lightSquareColor;
3204 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3206 gc_values.foreground = jailSquareColor;
3207 gc_values.background = jailSquareColor;
3208 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3210 gc_values.foreground = whitePieceColor;
3211 gc_values.background = darkSquareColor;
3212 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3214 gc_values.foreground = whitePieceColor;
3215 gc_values.background = lightSquareColor;
3216 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3218 gc_values.foreground = whitePieceColor;
3219 gc_values.background = jailSquareColor;
3220 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3222 gc_values.foreground = blackPieceColor;
3223 gc_values.background = darkSquareColor;
3224 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3226 gc_values.foreground = blackPieceColor;
3227 gc_values.background = lightSquareColor;
3228 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3230 gc_values.foreground = blackPieceColor;
3231 gc_values.background = jailSquareColor;
3232 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3236 void loadXIM(xim, xmask, filename, dest, mask)
3249 fp = fopen(filename, "rb");
3251 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3258 for (y=0; y<h; ++y) {
3259 for (x=0; x<h; ++x) {
3264 XPutPixel(xim, x, y, blackPieceColor);
3266 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3269 XPutPixel(xim, x, y, darkSquareColor);
3271 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3274 XPutPixel(xim, x, y, whitePieceColor);
3276 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3279 XPutPixel(xim, x, y, lightSquareColor);
3281 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3287 /* create Pixmap of piece */
3288 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3290 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3293 /* create Pixmap of clipmask
3294 Note: We assume the white/black pieces have the same
3295 outline, so we make only 6 masks. This is okay
3296 since the XPM clipmask routines do the same. */
3298 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3300 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3303 /* now create the 1-bit version */
3304 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3307 values.foreground = 1;
3308 values.background = 0;
3310 /* Don't use XtGetGC, not read only */
3311 maskGC = XCreateGC(xDisplay, *mask,
3312 GCForeground | GCBackground, &values);
3313 XCopyPlane(xDisplay, temp, *mask, maskGC,
3314 0, 0, squareSize, squareSize, 0, 0, 1);
3315 XFreePixmap(xDisplay, temp);
3320 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3322 void CreateXIMPieces()
3327 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3332 /* The XSynchronize calls were copied from CreatePieces.
3333 Not sure if needed, but can't hurt */
3334 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3337 /* temp needed by loadXIM() */
3338 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3339 0, 0, ss, ss, AllPlanes, XYPixmap);
3341 if (strlen(appData.pixmapDirectory) == 0) {
3345 if (appData.monoMode) {
3346 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3350 fprintf(stderr, _("\nLoading XIMs...\n"));
3352 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3353 fprintf(stderr, "%d", piece+1);
3354 for (kind=0; kind<4; kind++) {
3355 fprintf(stderr, ".");
3356 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3357 ExpandPathName(appData.pixmapDirectory),
3358 piece <= (int) WhiteKing ? "" : "w",
3359 pieceBitmapNames[piece],
3361 ximPieceBitmap[kind][piece] =
3362 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3363 0, 0, ss, ss, AllPlanes, XYPixmap);
3364 if (appData.debugMode)
3365 fprintf(stderr, _("(File:%s:) "), buf);
3366 loadXIM(ximPieceBitmap[kind][piece],
3368 &(xpmPieceBitmap2[kind][piece]),
3369 &(ximMaskPm2[piece]));
3370 if(piece <= (int)WhiteKing)
3371 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3373 fprintf(stderr," ");
3375 /* Load light and dark squares */
3376 /* If the LSQ and DSQ pieces don't exist, we will
3377 draw them with solid squares. */
3378 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3379 if (access(buf, 0) != 0) {
3383 fprintf(stderr, _("light square "));
3385 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3386 0, 0, ss, ss, AllPlanes, XYPixmap);
3387 if (appData.debugMode)
3388 fprintf(stderr, _("(File:%s:) "), buf);
3390 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3391 fprintf(stderr, _("dark square "));
3392 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3393 ExpandPathName(appData.pixmapDirectory), ss);
3394 if (appData.debugMode)
3395 fprintf(stderr, _("(File:%s:) "), buf);
3397 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3398 0, 0, ss, ss, AllPlanes, XYPixmap);
3399 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3400 xpmJailSquare = xpmLightSquare;
3402 fprintf(stderr, _("Done.\n"));
3404 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3408 void CreateXPMBoard(char *s, int kind)
3412 if(s == NULL || *s == 0 || *s == '*') return;
3413 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3414 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3418 void CreateXPMPieces()
3422 u_int ss = squareSize;
3424 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3425 XpmColorSymbol symbols[4];
3427 /* The XSynchronize calls were copied from CreatePieces.
3428 Not sure if needed, but can't hurt */
3429 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3431 /* Setup translations so piece colors match square colors */
3432 symbols[0].name = "light_piece";
3433 symbols[0].value = appData.whitePieceColor;
3434 symbols[1].name = "dark_piece";
3435 symbols[1].value = appData.blackPieceColor;
3436 symbols[2].name = "light_square";
3437 symbols[2].value = appData.lightSquareColor;
3438 symbols[3].name = "dark_square";
3439 symbols[3].value = appData.darkSquareColor;
3441 attr.valuemask = XpmColorSymbols;
3442 attr.colorsymbols = symbols;
3443 attr.numsymbols = 4;
3445 if (appData.monoMode) {
3446 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3450 if (strlen(appData.pixmapDirectory) == 0) {
3451 XpmPieces* pieces = builtInXpms;
3454 while (pieces->size != squareSize && pieces->size) pieces++;
3455 if (!pieces->size) {
3456 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3459 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3460 for (kind=0; kind<4; kind++) {
3462 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3463 pieces->xpm[piece][kind],
3464 &(xpmPieceBitmap2[kind][piece]),
3465 NULL, &attr)) != 0) {
3466 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3470 if(piece <= (int) WhiteKing)
3471 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3475 xpmJailSquare = xpmLightSquare;
3479 fprintf(stderr, _("\nLoading XPMs...\n"));
3482 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3483 fprintf(stderr, "%d ", piece+1);
3484 for (kind=0; kind<4; kind++) {
3485 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3486 ExpandPathName(appData.pixmapDirectory),
3487 piece > (int) WhiteKing ? "w" : "",
3488 pieceBitmapNames[piece],
3490 if (appData.debugMode) {
3491 fprintf(stderr, _("(File:%s:) "), buf);
3493 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3494 &(xpmPieceBitmap2[kind][piece]),
3495 NULL, &attr)) != 0) {
3496 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3497 // [HGM] missing: read of unorthodox piece failed; substitute King.
3498 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3499 ExpandPathName(appData.pixmapDirectory),
3501 if (appData.debugMode) {
3502 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3504 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3505 &(xpmPieceBitmap2[kind][piece]),
3509 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3514 if(piece <= (int) WhiteKing)
3515 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3518 /* Load light and dark squares */
3519 /* If the LSQ and DSQ pieces don't exist, we will
3520 draw them with solid squares. */
3521 fprintf(stderr, _("light square "));
3522 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3523 if (access(buf, 0) != 0) {
3527 if (appData.debugMode)
3528 fprintf(stderr, _("(File:%s:) "), buf);
3530 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3531 &xpmLightSquare, NULL, &attr)) != 0) {
3532 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3535 fprintf(stderr, _("dark square "));
3536 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3537 ExpandPathName(appData.pixmapDirectory), ss);
3538 if (appData.debugMode) {
3539 fprintf(stderr, _("(File:%s:) "), buf);
3541 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3542 &xpmDarkSquare, NULL, &attr)) != 0) {
3543 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3547 xpmJailSquare = xpmLightSquare;
3548 fprintf(stderr, _("Done.\n"));
3550 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3553 #endif /* HAVE_LIBXPM */
3556 /* No built-in bitmaps */
3561 u_int ss = squareSize;
3563 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3566 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3567 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3568 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3569 pieceBitmapNames[piece],
3570 ss, kind == SOLID ? 's' : 'o');
3571 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3572 if(piece <= (int)WhiteKing)
3573 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3577 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3581 /* With built-in bitmaps */
3584 BuiltInBits* bib = builtInBits;
3587 u_int ss = squareSize;
3589 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3592 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3594 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3595 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3596 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3597 pieceBitmapNames[piece],
3598 ss, kind == SOLID ? 's' : 'o');
3599 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3600 bib->bits[kind][piece], ss, ss);
3601 if(piece <= (int)WhiteKing)
3602 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3606 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3611 void ReadBitmap(pm, name, bits, wreq, hreq)
3614 unsigned char bits[];
3620 char msg[MSG_SIZ], fullname[MSG_SIZ];
3622 if (*appData.bitmapDirectory != NULLCHAR) {
3623 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3624 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3625 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3626 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3627 &w, &h, pm, &x_hot, &y_hot);
3628 fprintf(stderr, "load %s\n", name);
3629 if (errcode != BitmapSuccess) {
3631 case BitmapOpenFailed:
3632 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3634 case BitmapFileInvalid:
3635 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3637 case BitmapNoMemory:
3638 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3642 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3646 fprintf(stderr, _("%s: %s...using built-in\n"),
3648 } else if (w != wreq || h != hreq) {
3650 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3651 programName, fullname, w, h, wreq, hreq);
3657 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3666 if (lineGap == 0) return;
3668 /* [HR] Split this into 2 loops for non-square boards. */
3670 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3671 gridSegments[i].x1 = 0;
3672 gridSegments[i].x2 =
3673 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3674 gridSegments[i].y1 = gridSegments[i].y2
3675 = lineGap / 2 + (i * (squareSize + lineGap));
3678 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3679 gridSegments[j + i].y1 = 0;
3680 gridSegments[j + i].y2 =
3681 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3682 gridSegments[j + i].x1 = gridSegments[j + i].x2
3683 = lineGap / 2 + (j * (squareSize + lineGap));
3687 static void MenuBarSelect(w, addr, index)
3692 XtActionProc proc = (XtActionProc) addr;
3694 (proc)(NULL, NULL, NULL, NULL);
3697 void CreateMenuBarPopup(parent, name, mb)
3707 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3710 XtSetArg(args[j], XtNleftMargin, 20); j++;
3711 XtSetArg(args[j], XtNrightMargin, 20); j++;
3713 while (mi->string != NULL) {
3714 if (strcmp(mi->string, "----") == 0) {
3715 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3718 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3719 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3721 XtAddCallback(entry, XtNcallback,
3722 (XtCallbackProc) MenuBarSelect,
3723 (caddr_t) mi->proc);
3729 Widget CreateMenuBar(mb)
3733 Widget anchor, menuBar;
3735 char menuName[MSG_SIZ];
3738 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3739 XtSetArg(args[j], XtNvSpace, 0); j++;
3740 XtSetArg(args[j], XtNborderWidth, 0); j++;
3741 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3742 formWidget, args, j);
3744 while (mb->name != NULL) {
3745 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3746 strncat(menuName, mb->name, MSG_SIZ - strlen(menuName) - 1);
3748 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3751 shortName[0] = _(mb->name)[0];
3752 shortName[1] = NULLCHAR;
3753 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3756 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3759 XtSetArg(args[j], XtNborderWidth, 0); j++;
3760 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3762 CreateMenuBarPopup(menuBar, menuName, mb);
3768 Widget CreateButtonBar(mi)
3772 Widget button, buttonBar;
3776 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3778 XtSetArg(args[j], XtNhSpace, 0); j++;
3780 XtSetArg(args[j], XtNborderWidth, 0); j++;
3781 XtSetArg(args[j], XtNvSpace, 0); j++;
3782 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3783 formWidget, args, j);
3785 while (mi->string != NULL) {
3788 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3789 XtSetArg(args[j], XtNborderWidth, 0); j++;
3791 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3792 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3793 buttonBar, args, j);
3794 XtAddCallback(button, XtNcallback,
3795 (XtCallbackProc) MenuBarSelect,
3796 (caddr_t) mi->proc);
3803 CreatePieceMenu(name, color)
3810 ChessSquare selection;
3812 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3813 boardWidget, args, 0);
3815 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3816 String item = pieceMenuStrings[color][i];
3818 if (strcmp(item, "----") == 0) {
3819 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3822 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3823 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3825 selection = pieceMenuTranslation[color][i];
3826 XtAddCallback(entry, XtNcallback,
3827 (XtCallbackProc) PieceMenuSelect,
3828 (caddr_t) selection);
3829 if (selection == WhitePawn || selection == BlackPawn) {
3830 XtSetArg(args[0], XtNpopupOnEntry, entry);
3831 XtSetValues(menu, args, 1);
3844 ChessSquare selection;
3846 whitePieceMenu = CreatePieceMenu("menuW", 0);
3847 blackPieceMenu = CreatePieceMenu("menuB", 1);
3849 XtRegisterGrabAction(PieceMenuPopup, True,
3850 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3851 GrabModeAsync, GrabModeAsync);
3853 XtSetArg(args[0], XtNlabel, _("Drop"));
3854 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3855 boardWidget, args, 1);
3856 for (i = 0; i < DROP_MENU_SIZE; i++) {
3857 String item = dropMenuStrings[i];
3859 if (strcmp(item, "----") == 0) {
3860 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3863 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3864 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3866 selection = dropMenuTranslation[i];
3867 XtAddCallback(entry, XtNcallback,
3868 (XtCallbackProc) DropMenuSelect,
3869 (caddr_t) selection);
3874 void SetupDropMenu()
3882 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3883 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3884 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3885 dmEnables[i].piece);
3886 XtSetSensitive(entry, p != NULL || !appData.testLegality
3887 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3888 && !appData.icsActive));
3890 while (p && *p++ == dmEnables[i].piece) count++;
3891 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3893 XtSetArg(args[j], XtNlabel, label); j++;
3894 XtSetValues(entry, args, j);
3898 void PieceMenuPopup(w, event, params, num_params)
3902 Cardinal *num_params;
3904 String whichMenu; int menuNr;
3905 if (event->type == ButtonRelease)
3906 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3907 else if (event->type == ButtonPress)
3908 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3910 case 0: whichMenu = params[0]; break;
3911 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3913 case -1: if (errorUp) ErrorPopDown();
3916 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3919 static void PieceMenuSelect(w, piece, junk)
3924 if (pmFromX < 0 || pmFromY < 0) return;
3925 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3928 static void DropMenuSelect(w, piece, junk)
3933 if (pmFromX < 0 || pmFromY < 0) return;
3934 DropMenuEvent(piece, pmFromX, pmFromY);
3937 void WhiteClock(w, event, prms, nprms)
3943 if (gameMode == EditPosition || gameMode == IcsExamining) {
3944 SetWhiteToPlayEvent();
3945 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3950 void BlackClock(w, event, prms, nprms)
3956 if (gameMode == EditPosition || gameMode == IcsExamining) {
3957 SetBlackToPlayEvent();
3958 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3965 * If the user selects on a border boundary, return -1; if off the board,
3966 * return -2. Otherwise map the event coordinate to the square.
3968 int EventToSquare(x, limit)
3976 if ((x % (squareSize + lineGap)) >= squareSize)
3978 x /= (squareSize + lineGap);
3984 static void do_flash_delay(msec)
3990 static void drawHighlight(file, rank, gc)
3996 if (lineGap == 0 || appData.blindfold) return;
3999 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
4000 (squareSize + lineGap);
4001 y = lineGap/2 + rank * (squareSize + lineGap);
4003 x = lineGap/2 + file * (squareSize + lineGap);
4004 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
4005 (squareSize + lineGap);
4008 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
4009 squareSize+lineGap, squareSize+lineGap);
4012 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
4013 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4016 SetHighlights(fromX, fromY, toX, toY)
4017 int fromX, fromY, toX, toY;
4019 if (hi1X != fromX || hi1Y != fromY) {
4020 if (hi1X >= 0 && hi1Y >= 0) {
4021 drawHighlight(hi1X, hi1Y, lineGC);
4023 } // [HGM] first erase both, then draw new!
4024 if (hi2X != toX || hi2Y != toY) {
4025 if (hi2X >= 0 && hi2Y >= 0) {
4026 drawHighlight(hi2X, hi2Y, lineGC);
4029 if (hi1X != fromX || hi1Y != fromY) {
4030 if (fromX >= 0 && fromY >= 0) {
4031 drawHighlight(fromX, fromY, highlineGC);
4034 if (hi2X != toX || hi2Y != toY) {
4035 if (toX >= 0 && toY >= 0) {
4036 drawHighlight(toX, toY, highlineGC);
4048 SetHighlights(-1, -1, -1, -1);
4053 SetPremoveHighlights(fromX, fromY, toX, toY)
4054 int fromX, fromY, toX, toY;
4056 if (pm1X != fromX || pm1Y != fromY) {
4057 if (pm1X >= 0 && pm1Y >= 0) {
4058 drawHighlight(pm1X, pm1Y, lineGC);
4060 if (fromX >= 0 && fromY >= 0) {
4061 drawHighlight(fromX, fromY, prelineGC);
4064 if (pm2X != toX || pm2Y != toY) {
4065 if (pm2X >= 0 && pm2Y >= 0) {
4066 drawHighlight(pm2X, pm2Y, lineGC);
4068 if (toX >= 0 && toY >= 0) {
4069 drawHighlight(toX, toY, prelineGC);
4079 ClearPremoveHighlights()
4081 SetPremoveHighlights(-1, -1, -1, -1);
4084 static int CutOutSquare(x, y, x0, y0, kind)
4085 int x, y, *x0, *y0, kind;
4087 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
4088 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
4090 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
4091 if(textureW[kind] < W*squareSize)
4092 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
4094 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
4095 if(textureH[kind] < H*squareSize)
4096 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
4098 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
4102 static void BlankSquare(x, y, color, piece, dest, fac)
4103 int x, y, color, fac;
4106 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
4108 if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
4109 XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
4110 squareSize, squareSize, x*fac, y*fac);
4112 if (useImages && useImageSqs) {
4116 pm = xpmLightSquare;
4121 case 2: /* neutral */
4126 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4127 squareSize, squareSize, x*fac, y*fac);
4137 case 2: /* neutral */
4142 XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
4147 I split out the routines to draw a piece so that I could
4148 make a generic flash routine.
4150 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4152 int square_color, x, y;
4155 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4156 switch (square_color) {
4158 case 2: /* neutral */
4160 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4161 ? *pieceToOutline(piece)
4162 : *pieceToSolid(piece),
4163 dest, bwPieceGC, 0, 0,
4164 squareSize, squareSize, x, y);
4167 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4168 ? *pieceToSolid(piece)
4169 : *pieceToOutline(piece),
4170 dest, wbPieceGC, 0, 0,
4171 squareSize, squareSize, x, y);
4176 static void monoDrawPiece(piece, square_color, x, y, dest)
4178 int square_color, x, y;
4181 switch (square_color) {
4183 case 2: /* neutral */
4185 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4186 ? *pieceToOutline(piece)
4187 : *pieceToSolid(piece),
4188 dest, bwPieceGC, 0, 0,
4189 squareSize, squareSize, x, y, 1);
4192 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4193 ? *pieceToSolid(piece)
4194 : *pieceToOutline(piece),
4195 dest, wbPieceGC, 0, 0,
4196 squareSize, squareSize, x, y, 1);
4201 static void colorDrawPiece(piece, square_color, x, y, dest)
4203 int square_color, x, y;
4206 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4207 switch (square_color) {
4209 XCopyPlane(xDisplay, *pieceToSolid(piece),
4210 dest, (int) piece < (int) BlackPawn
4211 ? wlPieceGC : blPieceGC, 0, 0,
4212 squareSize, squareSize, x, y, 1);
4215 XCopyPlane(xDisplay, *pieceToSolid(piece),
4216 dest, (int) piece < (int) BlackPawn
4217 ? wdPieceGC : bdPieceGC, 0, 0,
4218 squareSize, squareSize, x, y, 1);
4220 case 2: /* neutral */
4222 XCopyPlane(xDisplay, *pieceToSolid(piece),
4223 dest, (int) piece < (int) BlackPawn
4224 ? wjPieceGC : bjPieceGC, 0, 0,
4225 squareSize, squareSize, x, y, 1);
4230 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4232 int square_color, x, y;
4235 int kind, p = piece;
4237 switch (square_color) {
4239 case 2: /* neutral */
4241 if ((int)piece < (int) BlackPawn) {
4249 if ((int)piece < (int) BlackPawn) {
4257 if(appData.upsideDown && flipView) kind ^= 2; // swap white and black pieces
4258 if(useTexture & square_color+1) {
4259 BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
4260 XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
4261 XSetClipOrigin(xDisplay, wlPieceGC, x, y);
4262 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);
4263 XSetClipMask(xDisplay, wlPieceGC, None);
4264 XSetClipOrigin(xDisplay, wlPieceGC, 0, 0);
4266 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4267 dest, wlPieceGC, 0, 0,
4268 squareSize, squareSize, x, y);
4271 typedef void (*DrawFunc)();
4273 DrawFunc ChooseDrawFunc()
4275 if (appData.monoMode) {
4276 if (DefaultDepth(xDisplay, xScreen) == 1) {
4277 return monoDrawPiece_1bit;
4279 return monoDrawPiece;
4283 return colorDrawPieceImage;
4285 return colorDrawPiece;
4289 /* [HR] determine square color depending on chess variant. */
4290 static int SquareColor(row, column)
4295 if (gameInfo.variant == VariantXiangqi) {
4296 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4298 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4300 } else if (row <= 4) {
4306 square_color = ((column + row) % 2) == 1;
4309 /* [hgm] holdings: next line makes all holdings squares light */
4310 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4312 return square_color;
4315 void DrawSquare(row, column, piece, do_flash)
4316 int row, column, do_flash;
4319 int square_color, x, y, direction, font_ascent, font_descent;
4322 XCharStruct overall;
4326 /* Calculate delay in milliseconds (2-delays per complete flash) */
4327 flash_delay = 500 / appData.flashRate;
4330 x = lineGap + ((BOARD_WIDTH-1)-column) *
4331 (squareSize + lineGap);
4332 y = lineGap + row * (squareSize + lineGap);
4334 x = lineGap + column * (squareSize + lineGap);
4335 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4336 (squareSize + lineGap);
4339 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4341 square_color = SquareColor(row, column);
4343 if ( // [HGM] holdings: blank out area between board and holdings
4344 column == BOARD_LEFT-1 || column == BOARD_RGHT
4345 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4346 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4347 BlankSquare(x, y, 2, EmptySquare, xBoardWindow, 1);
4349 // [HGM] print piece counts next to holdings
4350 string[1] = NULLCHAR;
4351 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4352 string[0] = '0' + piece;
4353 XTextExtents(countFontStruct, string, 1, &direction,
4354 &font_ascent, &font_descent, &overall);
4355 if (appData.monoMode) {
4356 XDrawImageString(xDisplay, xBoardWindow, countGC,
4357 x + squareSize - overall.width - 2,
4358 y + font_ascent + 1, string, 1);
4360 XDrawString(xDisplay, xBoardWindow, countGC,
4361 x + squareSize - overall.width - 2,
4362 y + font_ascent + 1, string, 1);
4365 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4366 string[0] = '0' + piece;
4367 XTextExtents(countFontStruct, string, 1, &direction,
4368 &font_ascent, &font_descent, &overall);
4369 if (appData.monoMode) {
4370 XDrawImageString(xDisplay, xBoardWindow, countGC,
4371 x + 2, y + font_ascent + 1, string, 1);
4373 XDrawString(xDisplay, xBoardWindow, countGC,
4374 x + 2, y + font_ascent + 1, string, 1);
4378 if (piece == EmptySquare || appData.blindfold) {
4379 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4381 drawfunc = ChooseDrawFunc();
4382 if (do_flash && appData.flashCount > 0) {
4383 for (i=0; i<appData.flashCount; ++i) {
4385 drawfunc(piece, square_color, x, y, xBoardWindow);
4386 XSync(xDisplay, False);
4387 do_flash_delay(flash_delay);
4389 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4390 XSync(xDisplay, False);
4391 do_flash_delay(flash_delay);
4394 drawfunc(piece, square_color, x, y, xBoardWindow);
4398 string[1] = NULLCHAR;
4399 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4400 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4401 string[0] = 'a' + column - BOARD_LEFT;
4402 XTextExtents(coordFontStruct, string, 1, &direction,
4403 &font_ascent, &font_descent, &overall);
4404 if (appData.monoMode) {
4405 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4406 x + squareSize - overall.width - 2,
4407 y + squareSize - font_descent - 1, string, 1);
4409 XDrawString(xDisplay, xBoardWindow, coordGC,
4410 x + squareSize - overall.width - 2,
4411 y + squareSize - font_descent - 1, string, 1);
4414 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4415 string[0] = ONE + row;
4416 XTextExtents(coordFontStruct, string, 1, &direction,
4417 &font_ascent, &font_descent, &overall);
4418 if (appData.monoMode) {
4419 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4420 x + 2, y + font_ascent + 1, string, 1);
4422 XDrawString(xDisplay, xBoardWindow, coordGC,
4423 x + 2, y + font_ascent + 1, string, 1);
4426 if(!partnerUp && marker[row][column]) {
4427 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4428 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4433 /* Why is this needed on some versions of X? */
4434 void EventProc(widget, unused, event)
4439 if (!XtIsRealized(widget))
4442 switch (event->type) {
4444 if (event->xexpose.count > 0) return; /* no clipping is done */
4445 XDrawPosition(widget, True, NULL);
4446 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4447 flipView = !flipView; partnerUp = !partnerUp;
4448 XDrawPosition(widget, True, NULL);
4449 flipView = !flipView; partnerUp = !partnerUp;
4453 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
\r
4460 void DrawPosition(fullRedraw, board)
4461 /*Boolean*/int fullRedraw;
4464 XDrawPosition(boardWidget, fullRedraw, board);
4467 /* Returns 1 if there are "too many" differences between b1 and b2
4468 (i.e. more than 1 move was made) */
4469 static int too_many_diffs(b1, b2)
4475 for (i=0; i<BOARD_HEIGHT; ++i) {
4476 for (j=0; j<BOARD_WIDTH; ++j) {
4477 if (b1[i][j] != b2[i][j]) {
4478 if (++c > 4) /* Castling causes 4 diffs */
4487 /* Matrix describing castling maneuvers */
4488 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4489 static int castling_matrix[4][5] = {
4490 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4491 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4492 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4493 { 7, 7, 4, 5, 6 } /* 0-0, black */
4496 /* Checks whether castling occurred. If it did, *rrow and *rcol
4497 are set to the destination (row,col) of the rook that moved.
4499 Returns 1 if castling occurred, 0 if not.
4501 Note: Only handles a max of 1 castling move, so be sure
4502 to call too_many_diffs() first.
4504 static int check_castle_draw(newb, oldb, rrow, rcol)
4511 /* For each type of castling... */
4512 for (i=0; i<4; ++i) {
4513 r = castling_matrix[i];
4515 /* Check the 4 squares involved in the castling move */
4517 for (j=1; j<=4; ++j) {
4518 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4525 /* All 4 changed, so it must be a castling move */
4534 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4535 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4537 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4540 void DrawSeekBackground( int left, int top, int right, int bottom )
4542 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4545 void DrawSeekText(char *buf, int x, int y)
4547 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4550 void DrawSeekDot(int x, int y, int colorNr)
4552 int square = colorNr & 0x80;
4555 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4557 XFillRectangle(xDisplay, xBoardWindow, color,
4558 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4560 XFillArc(xDisplay, xBoardWindow, color,
4561 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4564 static int damage[2][BOARD_RANKS][BOARD_FILES];
4567 * event handler for redrawing the board
4569 void XDrawPosition(w, repaint, board)
4571 /*Boolean*/int repaint;
4575 static int lastFlipView = 0;
4576 static int lastBoardValid[2] = {0, 0};
4577 static Board lastBoard[2];
4580 int nr = twoBoards*partnerUp;
4582 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4584 if (board == NULL) {
4585 if (!lastBoardValid[nr]) return;
4586 board = lastBoard[nr];
4588 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4589 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4590 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4595 * It would be simpler to clear the window with XClearWindow()
4596 * but this causes a very distracting flicker.
4599 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4601 /* If too much changes (begin observing new game, etc.), don't
4603 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4605 /* Special check for castling so we don't flash both the king
4606 and the rook (just flash the king). */
4608 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4609 /* Draw rook with NO flashing. King will be drawn flashing later */
4610 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4611 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4615 /* First pass -- Draw (newly) empty squares and repair damage.
4616 This prevents you from having a piece show up twice while it
4617 is flashing on its new square */
4618 for (i = 0; i < BOARD_HEIGHT; i++)
4619 for (j = 0; j < BOARD_WIDTH; j++)
4620 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4621 || damage[nr][i][j]) {
4622 DrawSquare(i, j, board[i][j], 0);
4623 damage[nr][i][j] = False;
4626 /* Second pass -- Draw piece(s) in new position and flash them */
4627 for (i = 0; i < BOARD_HEIGHT; i++)
4628 for (j = 0; j < BOARD_WIDTH; j++)
4629 if (board[i][j] != lastBoard[nr][i][j]) {
4630 DrawSquare(i, j, board[i][j], do_flash);
4634 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4635 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4636 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4638 for (i = 0; i < BOARD_HEIGHT; i++)
4639 for (j = 0; j < BOARD_WIDTH; j++) {
4640 DrawSquare(i, j, board[i][j], 0);
4641 damage[nr][i][j] = False;
4645 CopyBoard(lastBoard[nr], board);
4646 lastBoardValid[nr] = 1;
4647 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4648 lastFlipView = flipView;
4650 /* Draw highlights */
4651 if (pm1X >= 0 && pm1Y >= 0) {
4652 drawHighlight(pm1X, pm1Y, prelineGC);
4654 if (pm2X >= 0 && pm2Y >= 0) {
4655 drawHighlight(pm2X, pm2Y, prelineGC);
4657 if (hi1X >= 0 && hi1Y >= 0) {
4658 drawHighlight(hi1X, hi1Y, highlineGC);
4660 if (hi2X >= 0 && hi2Y >= 0) {
4661 drawHighlight(hi2X, hi2Y, highlineGC);
4664 /* If piece being dragged around board, must redraw that too */
4667 XSync(xDisplay, False);
4672 * event handler for redrawing the board
4674 void DrawPositionProc(w, event, prms, nprms)
4680 XDrawPosition(w, True, NULL);
4685 * event handler for parsing user moves
4687 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4688 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4689 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4690 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4691 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4692 // and at the end FinishMove() to perform the move after optional promotion popups.
4693 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4694 void HandleUserMove(w, event, prms, nprms)
4700 if (w != boardWidget || errorExitStatus != -1) return;
4701 if(nprms) shiftKey = !strcmp(prms[0], "1");
4704 if (event->type == ButtonPress) {
4705 XtPopdown(promotionShell);
4706 XtDestroyWidget(promotionShell);
4707 promotionUp = False;
4715 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4716 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4717 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4720 void AnimateUserMove (Widget w, XEvent * event,
4721 String * params, Cardinal * nParams)
4723 DragPieceMove(event->xmotion.x, event->xmotion.y);
4726 void HandlePV (Widget w, XEvent * event,
4727 String * params, Cardinal * nParams)
4728 { // [HGM] pv: walk PV
4729 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4732 Widget CommentCreate(name, text, mutable, callback, lines)
4734 int /*Boolean*/ mutable;
4735 XtCallbackProc callback;
4739 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4744 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4745 XtGetValues(boardWidget, args, j);
4748 XtSetArg(args[j], XtNresizable, True); j++;
4751 XtCreatePopupShell(name, topLevelShellWidgetClass,
4752 shellWidget, args, j);
4755 XtCreatePopupShell(name, transientShellWidgetClass,
4756 shellWidget, args, j);
4759 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4760 layoutArgs, XtNumber(layoutArgs));
4762 XtCreateManagedWidget("form", formWidgetClass, layout,
4763 formArgs, XtNumber(formArgs));
4767 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4768 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4770 XtSetArg(args[j], XtNstring, text); j++;
4771 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4772 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4773 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4774 XtSetArg(args[j], XtNright, XtChainRight); j++;
4775 XtSetArg(args[j], XtNresizable, True); j++;
4776 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4777 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4778 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4779 XtSetArg(args[j], XtNautoFill, True); j++;
4780 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4782 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4783 XtOverrideTranslations(edit, XtParseTranslationTable(commentTranslations));
4787 XtSetArg(args[j], XtNfromVert, edit); j++;
4788 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4789 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4790 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4791 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4793 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4794 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4797 XtSetArg(args[j], XtNfromVert, edit); j++;
4798 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4799 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4800 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4801 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4802 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4804 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4805 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4808 XtSetArg(args[j], XtNfromVert, edit); j++;
4809 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4810 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4811 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4812 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4813 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4815 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4816 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4819 XtSetArg(args[j], XtNfromVert, edit); j++;
4820 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4821 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4822 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4823 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4825 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4826 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4829 XtSetArg(args[j], XtNfromVert, edit); j++;
4830 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4831 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4832 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4833 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4834 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4836 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4837 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4840 XtRealizeWidget(shell);
4842 if (commentX == -1) {
4845 Dimension pw_height;
4846 Dimension ew_height;
4849 XtSetArg(args[j], XtNheight, &ew_height); j++;
4850 XtGetValues(edit, args, j);
4853 XtSetArg(args[j], XtNheight, &pw_height); j++;
4854 XtGetValues(shell, args, j);
4855 commentH = pw_height + (lines - 1) * ew_height;
4856 commentW = bw_width - 16;
4858 XSync(xDisplay, False);
4860 /* This code seems to tickle an X bug if it is executed too soon
4861 after xboard starts up. The coordinates get transformed as if
4862 the main window was positioned at (0, 0).
4864 XtTranslateCoords(shellWidget,
4865 (bw_width - commentW) / 2, 0 - commentH / 2,
4866 &commentX, &commentY);
4868 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4869 RootWindowOfScreen(XtScreen(shellWidget)),
4870 (bw_width - commentW) / 2, 0 - commentH / 2,
4875 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4878 if(wpComment.width > 0) {
4879 commentX = wpComment.x;
4880 commentY = wpComment.y;
4881 commentW = wpComment.width;
4882 commentH = wpComment.height;
4886 XtSetArg(args[j], XtNheight, commentH); j++;
4887 XtSetArg(args[j], XtNwidth, commentW); j++;
4888 XtSetArg(args[j], XtNx, commentX); j++;
4889 XtSetArg(args[j], XtNy, commentY); j++;
4890 XtSetValues(shell, args, j);
4891 XtSetKeyboardFocus(shell, edit);
4896 /* Used for analysis window and ICS input window */
4897 Widget MiscCreate(name, text, mutable, callback, lines)
4899 int /*Boolean*/ mutable;
4900 XtCallbackProc callback;
4904 Widget shell, layout, form, edit;
4906 Dimension bw_width, pw_height, ew_height, w, h;
4912 XtSetArg(args[j], XtNresizable, True); j++;
4915 XtCreatePopupShell(name, topLevelShellWidgetClass,
4916 shellWidget, args, j);
4919 XtCreatePopupShell(name, transientShellWidgetClass,
4920 shellWidget, args, j);
4923 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4924 layoutArgs, XtNumber(layoutArgs));
4926 XtCreateManagedWidget("form", formWidgetClass, layout,
4927 formArgs, XtNumber(formArgs));
4931 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4932 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4934 XtSetArg(args[j], XtNstring, text); j++;
4935 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4936 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4937 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4938 XtSetArg(args[j], XtNright, XtChainRight); j++;
4939 XtSetArg(args[j], XtNresizable, True); j++;
4940 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4941 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4942 XtSetArg(args[j], XtNautoFill, True); j++;
4943 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4945 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4947 XtRealizeWidget(shell);
4950 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4951 XtGetValues(boardWidget, args, j);
4954 XtSetArg(args[j], XtNheight, &ew_height); j++;
4955 XtGetValues(edit, args, j);
4958 XtSetArg(args[j], XtNheight, &pw_height); j++;
4959 XtGetValues(shell, args, j);
4960 h = pw_height + (lines - 1) * ew_height;
4963 XSync(xDisplay, False);
4965 /* This code seems to tickle an X bug if it is executed too soon
4966 after xboard starts up. The coordinates get transformed as if
4967 the main window was positioned at (0, 0).
4969 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4971 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4972 RootWindowOfScreen(XtScreen(shellWidget)),
4973 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4977 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4980 XtSetArg(args[j], XtNheight, h); j++;
4981 XtSetArg(args[j], XtNwidth, w); j++;
4982 XtSetArg(args[j], XtNx, x); j++;
4983 XtSetArg(args[j], XtNy, y); j++;
4984 XtSetValues(shell, args, j);
4990 static int savedIndex; /* gross that this is global */
4992 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
4995 XawTextPosition index, dummy;
4998 XawTextGetSelectionPos(w, &index, &dummy);
4999 XtSetArg(arg, XtNstring, &val);
5000 XtGetValues(w, &arg, 1);
5001 ReplaceComment(savedIndex, val);
5002 if(savedIndex != currentMove) ToNrEvent(savedIndex);
5003 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
5006 void EditCommentPopUp(index, title, text)
5015 if (text == NULL) text = "";
5017 if (editShell == NULL) {
5019 CommentCreate(title, text, True, EditCommentCallback, 4);
5020 XtRealizeWidget(editShell);
5021 CatchDeleteWindow(editShell, "EditCommentPopDown");
5023 edit = XtNameToWidget(editShell, "*form.text");
5025 XtSetArg(args[j], XtNstring, text); j++;
5026 XtSetValues(edit, args, j);
5028 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5029 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5030 XtSetValues(editShell, args, j);
5033 XtPopup(editShell, XtGrabNone);
5037 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5038 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
5042 void EditCommentCallback(w, client_data, call_data)
5044 XtPointer client_data, call_data;
5052 XtSetArg(args[j], XtNlabel, &name); j++;
5053 XtGetValues(w, args, j);
5055 if (strcmp(name, _("ok")) == 0) {
5056 edit = XtNameToWidget(editShell, "*form.text");
5058 XtSetArg(args[j], XtNstring, &val); j++;
5059 XtGetValues(edit, args, j);
5060 ReplaceComment(savedIndex, val);
5061 EditCommentPopDown();
5062 } else if (strcmp(name, _("cancel")) == 0) {
5063 EditCommentPopDown();
5064 } else if (strcmp(name, _("clear")) == 0) {
5065 edit = XtNameToWidget(editShell, "*form.text");
5066 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5067 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5071 void EditCommentPopDown()
5076 if (!editUp) return;
5078 XtSetArg(args[j], XtNx, &commentX); j++;
5079 XtSetArg(args[j], XtNy, &commentY); j++;
5080 XtSetArg(args[j], XtNheight, &commentH); j++;
5081 XtSetArg(args[j], XtNwidth, &commentW); j++;
5082 XtGetValues(editShell, args, j);
5083 XtPopdown(editShell);
5086 XtSetArg(args[j], XtNleftBitmap, None); j++;
5087 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
5091 void ICSInputBoxPopUp()
5096 char *title = _("ICS Input");
5099 if (ICSInputShell == NULL) {
5100 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
5101 tr = XtParseTranslationTable(ICSInputTranslations);
5102 edit = XtNameToWidget(ICSInputShell, "*form.text");
5103 XtOverrideTranslations(edit, tr);
5104 XtRealizeWidget(ICSInputShell);
5105 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
5108 edit = XtNameToWidget(ICSInputShell, "*form.text");
5110 XtSetArg(args[j], XtNstring, ""); j++;
5111 XtSetValues(edit, args, j);
5113 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5114 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5115 XtSetValues(ICSInputShell, args, j);
5118 XtPopup(ICSInputShell, XtGrabNone);
5119 XtSetKeyboardFocus(ICSInputShell, edit);
5121 ICSInputBoxUp = True;
5123 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5124 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
5128 void ICSInputSendText()
5135 edit = XtNameToWidget(ICSInputShell, "*form.text");
5137 XtSetArg(args[j], XtNstring, &val); j++;
5138 XtGetValues(edit, args, j);
5140 SendMultiLineToICS(val);
5141 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5142 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5145 void ICSInputBoxPopDown()
5150 if (!ICSInputBoxUp) return;
5152 XtPopdown(ICSInputShell);
5153 ICSInputBoxUp = False;
5155 XtSetArg(args[j], XtNleftBitmap, None); j++;
5156 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
5160 void CommentPopUp(title, text)
5167 savedIndex = currentMove; // [HGM] vari
5168 if (commentShell == NULL) {
5170 CommentCreate(title, text, False, CommentCallback, 4);
5171 XtRealizeWidget(commentShell);
5172 CatchDeleteWindow(commentShell, "CommentPopDown");
5174 edit = XtNameToWidget(commentShell, "*form.text");
5176 XtSetArg(args[j], XtNstring, text); j++;
5177 XtSetValues(edit, args, j);
5179 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5180 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5181 XtSetValues(commentShell, args, j);
5184 XtPopup(commentShell, XtGrabNone);
5185 XSync(xDisplay, False);
5190 void CommentCallback(w, client_data, call_data)
5192 XtPointer client_data, call_data;
5199 XtSetArg(args[j], XtNlabel, &name); j++;
5200 XtGetValues(w, args, j);
5202 if (strcmp(name, _("close")) == 0) {
5204 } else if (strcmp(name, _("edit")) == 0) {
5211 void CommentPopDown()
5216 if (!commentUp) return;
5218 XtSetArg(args[j], XtNx, &commentX); j++;
5219 XtSetArg(args[j], XtNy, &commentY); j++;
5220 XtSetArg(args[j], XtNwidth, &commentW); j++;
5221 XtSetArg(args[j], XtNheight, &commentH); j++;
5222 XtGetValues(commentShell, args, j);
5223 XtPopdown(commentShell);
5224 XSync(xDisplay, False);
5228 void FileNamePopUp(label, def, proc, openMode)
5234 fileProc = proc; /* I can't see a way not */
5235 fileOpenMode = openMode; /* to use globals here */
5236 { // [HGM] use file-selector dialog stolen from Ghostview
5238 int index; // this is not supported yet
5240 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5241 def, openMode, NULL, &name))
5242 (void) (*fileProc)(f, index=0, name);
5246 void FileNamePopDown()
5248 if (!filenameUp) return;
5249 XtPopdown(fileNameShell);
5250 XtDestroyWidget(fileNameShell);
5255 void FileNameCallback(w, client_data, call_data)
5257 XtPointer client_data, call_data;
5262 XtSetArg(args[0], XtNlabel, &name);
5263 XtGetValues(w, args, 1);
5265 if (strcmp(name, _("cancel")) == 0) {
5270 FileNameAction(w, NULL, NULL, NULL);
5273 void FileNameAction(w, event, prms, nprms)
5285 name = XawDialogGetValueString(w = XtParent(w));
5287 if ((name != NULL) && (*name != NULLCHAR)) {
5288 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
5289 XtPopdown(w = XtParent(XtParent(w)));
5293 p = strrchr(buf, ' ');
5300 fullname = ExpandPathName(buf);
5302 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5305 f = fopen(fullname, fileOpenMode);
5307 DisplayError(_("Failed to open file"), errno);
5309 (void) (*fileProc)(f, index, buf);
5316 XtPopdown(w = XtParent(XtParent(w)));
5322 void PromotionPopUp()
5325 Widget dialog, layout;
5327 Dimension bw_width, pw_width;
5331 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5332 XtGetValues(boardWidget, args, j);
5335 XtSetArg(args[j], XtNresizable, True); j++;
5336 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5338 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5339 shellWidget, args, j);
5341 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5342 layoutArgs, XtNumber(layoutArgs));
5345 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5346 XtSetArg(args[j], XtNborderWidth, 0); j++;
5347 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5350 if(gameInfo.variant != VariantShogi) {
5351 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5352 (XtPointer) dialog);
5353 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5354 (XtPointer) dialog);
5355 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5356 (XtPointer) dialog);
5357 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5358 (XtPointer) dialog);
5359 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5360 gameInfo.variant == VariantGiveaway) {
5361 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5362 (XtPointer) dialog);
5364 if(gameInfo.variant == VariantCapablanca ||
5365 gameInfo.variant == VariantGothic ||
5366 gameInfo.variant == VariantCapaRandom) {
5367 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5368 (XtPointer) dialog);
5369 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5370 (XtPointer) dialog);
5372 } else // [HGM] shogi
5374 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5375 (XtPointer) dialog);
5376 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5377 (XtPointer) dialog);
5379 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5380 (XtPointer) dialog);
5382 XtRealizeWidget(promotionShell);
5383 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5386 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5387 XtGetValues(promotionShell, args, j);
5389 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5390 lineGap + squareSize/3 +
5391 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5392 0 : 6*(squareSize + lineGap)), &x, &y);
5395 XtSetArg(args[j], XtNx, x); j++;
5396 XtSetArg(args[j], XtNy, y); j++;
5397 XtSetValues(promotionShell, args, j);
5399 XtPopup(promotionShell, XtGrabNone);
5404 void PromotionPopDown()
5406 if (!promotionUp) return;
5407 XtPopdown(promotionShell);
5408 XtDestroyWidget(promotionShell);
5409 promotionUp = False;
5412 void PromotionCallback(w, client_data, call_data)
5414 XtPointer client_data, call_data;
5420 XtSetArg(args[0], XtNlabel, &name);
5421 XtGetValues(w, args, 1);
5425 if (fromX == -1) return;
5427 if (strcmp(name, _("cancel")) == 0) {
5431 } else if (strcmp(name, _("Knight")) == 0) {
5433 } else if (strcmp(name, _("Promote")) == 0) {
5435 } else if (strcmp(name, _("Defer")) == 0) {
5438 promoChar = ToLower(name[0]);
5441 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5443 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5444 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5449 void ErrorCallback(w, client_data, call_data)
5451 XtPointer client_data, call_data;
5454 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5456 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5462 if (!errorUp) return;
5464 XtPopdown(errorShell);
5465 XtDestroyWidget(errorShell);
5466 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5469 void ErrorPopUp(title, label, modal)
5470 char *title, *label;
5474 Widget dialog, layout;
5478 Dimension bw_width, pw_width;
5479 Dimension pw_height;
5483 XtSetArg(args[i], XtNresizable, True); i++;
5484 XtSetArg(args[i], XtNtitle, title); i++;
5486 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5487 shellWidget, args, i);
5489 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5490 layoutArgs, XtNumber(layoutArgs));
5493 XtSetArg(args[i], XtNlabel, label); i++;
5494 XtSetArg(args[i], XtNborderWidth, 0); i++;
5495 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5498 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5500 XtRealizeWidget(errorShell);
5501 CatchDeleteWindow(errorShell, "ErrorPopDown");
5504 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5505 XtGetValues(boardWidget, args, i);
5507 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5508 XtSetArg(args[i], XtNheight, &pw_height); i++;
5509 XtGetValues(errorShell, args, i);
5512 /* This code seems to tickle an X bug if it is executed too soon
5513 after xboard starts up. The coordinates get transformed as if
5514 the main window was positioned at (0, 0).
5516 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5517 0 - pw_height + squareSize / 3, &x, &y);
5519 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5520 RootWindowOfScreen(XtScreen(boardWidget)),
5521 (bw_width - pw_width) / 2,
5522 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5526 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5529 XtSetArg(args[i], XtNx, x); i++;
5530 XtSetArg(args[i], XtNy, y); i++;
5531 XtSetValues(errorShell, args, i);
5534 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5537 /* Disable all user input other than deleting the window */
5538 static int frozen = 0;
5542 /* Grab by a widget that doesn't accept input */
5543 XtAddGrab(messageWidget, TRUE, FALSE);
5547 /* Undo a FreezeUI */
5550 if (!frozen) return;
5551 XtRemoveGrab(messageWidget);
5555 char *ModeToWidgetName(mode)
5559 case BeginningOfGame:
5560 if (appData.icsActive)
5561 return "menuMode.ICS Client";
5562 else if (appData.noChessProgram ||
5563 *appData.cmailGameName != NULLCHAR)
5564 return "menuMode.Edit Game";
5566 return "menuMode.Machine Black";
5567 case MachinePlaysBlack:
5568 return "menuMode.Machine Black";
5569 case MachinePlaysWhite:
5570 return "menuMode.Machine White";
5572 return "menuMode.Analysis Mode";
5574 return "menuMode.Analyze File";
5575 case TwoMachinesPlay:
5576 return "menuMode.Two Machines";
5578 return "menuMode.Edit Game";
5579 case PlayFromGameFile:
5580 return "menuFile.Load Game";
5582 return "menuMode.Edit Position";
5584 return "menuMode.Training";
5585 case IcsPlayingWhite:
5586 case IcsPlayingBlack:
5590 return "menuMode.ICS Client";
5597 void ModeHighlight()
5600 static int oldPausing = FALSE;
5601 static GameMode oldmode = (GameMode) -1;
5604 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5606 if (pausing != oldPausing) {
5607 oldPausing = pausing;
5609 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5611 XtSetArg(args[0], XtNleftBitmap, None);
5613 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5616 if (appData.showButtonBar) {
5617 /* Always toggle, don't set. Previous code messes up when
5618 invoked while the button is pressed, as releasing it
5619 toggles the state again. */
5622 XtSetArg(args[0], XtNbackground, &oldbg);
5623 XtSetArg(args[1], XtNforeground, &oldfg);
5624 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5626 XtSetArg(args[0], XtNbackground, oldfg);
5627 XtSetArg(args[1], XtNforeground, oldbg);
5629 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5633 wname = ModeToWidgetName(oldmode);
5634 if (wname != NULL) {
5635 XtSetArg(args[0], XtNleftBitmap, None);
5636 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5638 wname = ModeToWidgetName(gameMode);
5639 if (wname != NULL) {
5640 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5641 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5645 /* Maybe all the enables should be handled here, not just this one */
5646 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5647 gameMode == Training || gameMode == PlayFromGameFile);
5652 * Button/menu procedures
5654 void ResetProc(w, event, prms, nprms)
5663 int LoadGamePopUp(f, gameNumber, title)
5668 cmailMsgLoaded = FALSE;
5669 if (gameNumber == 0) {
5670 int error = GameListBuild(f);
5672 DisplayError(_("Cannot build game list"), error);
5673 } else if (!ListEmpty(&gameList) &&
5674 ((ListGame *) gameList.tailPred)->number > 1) {
5675 GameListPopUp(f, title);
5681 return LoadGame(f, gameNumber, title, FALSE);
5684 void LoadGameProc(w, event, prms, nprms)
5690 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5693 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5696 void LoadNextGameProc(w, event, prms, nprms)
5705 void LoadPrevGameProc(w, event, prms, nprms)
5714 void ReloadGameProc(w, event, prms, nprms)
5723 void LoadNextPositionProc(w, event, prms, nprms)
5732 void LoadPrevPositionProc(w, event, prms, nprms)
5741 void ReloadPositionProc(w, event, prms, nprms)
5750 void LoadPositionProc(w, event, prms, nprms)
5756 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5759 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5762 void SaveGameProc(w, event, prms, nprms)
5768 FileNamePopUp(_("Save game file name?"),
5769 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5773 void SavePositionProc(w, event, prms, nprms)
5779 FileNamePopUp(_("Save position file name?"),
5780 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5784 void ReloadCmailMsgProc(w, event, prms, nprms)
5790 ReloadCmailMsgEvent(FALSE);
5793 void MailMoveProc(w, event, prms, nprms)
5802 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5803 char *selected_fen_position=NULL;
5806 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5807 Atom *type_return, XtPointer *value_return,
5808 unsigned long *length_return, int *format_return)
5810 char *selection_tmp;
5812 if (!selected_fen_position) return False; /* should never happen */
5813 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5814 /* note: since no XtSelectionDoneProc was registered, Xt will
5815 * automatically call XtFree on the value returned. So have to
5816 * make a copy of it allocated with XtMalloc */
5817 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5818 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
5820 *value_return=selection_tmp;
5821 *length_return=strlen(selection_tmp);
5822 *type_return=*target;
5823 *format_return = 8; /* bits per byte */
5825 } else if (*target == XA_TARGETS(xDisplay)) {
5826 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5827 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5828 targets_tmp[1] = XA_STRING;
5829 *value_return = targets_tmp;
5830 *type_return = XA_ATOM;
5832 *format_return = 8 * sizeof(Atom);
5833 if (*format_return > 32) {
5834 *length_return *= *format_return / 32;
5835 *format_return = 32;
5843 /* note: when called from menu all parameters are NULL, so no clue what the
5844 * Widget which was clicked on was, or what the click event was
5846 void CopyPositionProc(w, event, prms, nprms)
5853 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5854 * have a notion of a position that is selected but not copied.
5855 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5857 if(gameMode == EditPosition) EditPositionDone(TRUE);
5858 if (selected_fen_position) free(selected_fen_position);
5859 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5860 if (!selected_fen_position) return;
5861 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5863 SendPositionSelection,
5864 NULL/* lose_ownership_proc */ ,
5865 NULL/* transfer_done_proc */);
5866 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5868 SendPositionSelection,
5869 NULL/* lose_ownership_proc */ ,
5870 NULL/* transfer_done_proc */);
5873 /* function called when the data to Paste is ready */
5875 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5876 Atom *type, XtPointer value, unsigned long *len, int *format)
5879 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5880 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5881 EditPositionPasteFEN(fenstr);
5885 /* called when Paste Position button is pressed,
5886 * all parameters will be NULL */
5887 void PastePositionProc(w, event, prms, nprms)
5893 XtGetSelectionValue(menuBarWidget,
5894 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5895 /* (XtSelectionCallbackProc) */ PastePositionCB,
5896 NULL, /* client_data passed to PastePositionCB */
5898 /* better to use the time field from the event that triggered the
5899 * call to this function, but that isn't trivial to get
5907 SendGameSelection(Widget w, Atom *selection, Atom *target,
5908 Atom *type_return, XtPointer *value_return,
5909 unsigned long *length_return, int *format_return)
5911 char *selection_tmp;
5913 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5914 FILE* f = fopen(gameCopyFilename, "r");
5917 if (f == NULL) return False;
5921 selection_tmp = XtMalloc(len + 1);
5922 count = fread(selection_tmp, 1, len, f);
5924 XtFree(selection_tmp);
5927 selection_tmp[len] = NULLCHAR;
5928 *value_return = selection_tmp;
5929 *length_return = len;
5930 *type_return = *target;
5931 *format_return = 8; /* bits per byte */
5933 } else if (*target == XA_TARGETS(xDisplay)) {
5934 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5935 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5936 targets_tmp[1] = XA_STRING;
5937 *value_return = targets_tmp;
5938 *type_return = XA_ATOM;
5940 *format_return = 8 * sizeof(Atom);
5941 if (*format_return > 32) {
5942 *length_return *= *format_return / 32;
5943 *format_return = 32;
5951 /* note: when called from menu all parameters are NULL, so no clue what the
5952 * Widget which was clicked on was, or what the click event was
5954 void CopyGameProc(w, event, prms, nprms)
5962 ret = SaveGameToFile(gameCopyFilename, FALSE);
5966 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5967 * have a notion of a game that is selected but not copied.
5968 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5970 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5973 NULL/* lose_ownership_proc */ ,
5974 NULL/* transfer_done_proc */);
5975 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5978 NULL/* lose_ownership_proc */ ,
5979 NULL/* transfer_done_proc */);
5982 /* function called when the data to Paste is ready */
5984 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5985 Atom *type, XtPointer value, unsigned long *len, int *format)
5988 if (value == NULL || *len == 0) {
5989 return; /* nothing had been selected to copy */
5991 f = fopen(gamePasteFilename, "w");
5993 DisplayError(_("Can't open temp file"), errno);
5996 fwrite(value, 1, *len, f);
5999 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
6002 /* called when Paste Game button is pressed,
6003 * all parameters will be NULL */
6004 void PasteGameProc(w, event, prms, nprms)
6010 XtGetSelectionValue(menuBarWidget,
6011 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
6012 /* (XtSelectionCallbackProc) */ PasteGameCB,
6013 NULL, /* client_data passed to PasteGameCB */
6015 /* better to use the time field from the event that triggered the
6016 * call to this function, but that isn't trivial to get
6026 SaveGameProc(NULL, NULL, NULL, NULL);
6030 void QuitProc(w, event, prms, nprms)
6039 void PauseProc(w, event, prms, nprms)
6049 void MachineBlackProc(w, event, prms, nprms)
6055 MachineBlackEvent();
6058 void MachineWhiteProc(w, event, prms, nprms)
6064 MachineWhiteEvent();
6067 void AnalyzeModeProc(w, event, prms, nprms)
6075 if (!first.analysisSupport) {
6076 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6077 DisplayError(buf, 0);
6080 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
6081 if (appData.icsActive) {
6082 if (gameMode != IcsObserving) {
6083 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
6084 DisplayError(buf, 0);
6086 if (appData.icsEngineAnalyze) {
6087 if (appData.debugMode)
6088 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
6094 /* if enable, use want disable icsEngineAnalyze */
6095 if (appData.icsEngineAnalyze) {
6100 appData.icsEngineAnalyze = TRUE;
6101 if (appData.debugMode)
6102 fprintf(debugFP, _("ICS engine analyze starting... \n"));
6104 if (!appData.showThinking)
6105 ShowThinkingProc(w,event,prms,nprms);
6110 void AnalyzeFileProc(w, event, prms, nprms)
6116 if (!first.analysisSupport) {
6118 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6119 DisplayError(buf, 0);
6124 if (!appData.showThinking)
6125 ShowThinkingProc(w,event,prms,nprms);
6128 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
6129 AnalysisPeriodicEvent(1);
6132 void TwoMachinesProc(w, event, prms, nprms)
6141 void IcsClientProc(w, event, prms, nprms)
6150 void EditGameProc(w, event, prms, nprms)
6159 void EditPositionProc(w, event, prms, nprms)
6165 EditPositionEvent();
6168 void TrainingProc(w, event, prms, nprms)
6177 void EditCommentProc(w, event, prms, nprms)
6184 EditCommentPopDown();
6190 void IcsInputBoxProc(w, event, prms, nprms)
6196 if (ICSInputBoxUp) {
6197 ICSInputBoxPopDown();
6203 void AcceptProc(w, event, prms, nprms)
6212 void DeclineProc(w, event, prms, nprms)
6221 void RematchProc(w, event, prms, nprms)
6230 void CallFlagProc(w, event, prms, nprms)
6239 void DrawProc(w, event, prms, nprms)
6248 void AbortProc(w, event, prms, nprms)
6257 void AdjournProc(w, event, prms, nprms)
6266 void ResignProc(w, event, prms, nprms)
6275 void AdjuWhiteProc(w, event, prms, nprms)
6281 UserAdjudicationEvent(+1);
6284 void AdjuBlackProc(w, event, prms, nprms)
6290 UserAdjudicationEvent(-1);
6293 void AdjuDrawProc(w, event, prms, nprms)
6299 UserAdjudicationEvent(0);
6302 void EnterKeyProc(w, event, prms, nprms)
6308 if (ICSInputBoxUp == True)
6312 void UpKeyProc(w, event, prms, nprms)
6317 { // [HGM] input: let up-arrow recall previous line from history
6324 if (!ICSInputBoxUp) return;
6325 edit = XtNameToWidget(ICSInputShell, "*form.text");
6327 XtSetArg(args[j], XtNstring, &val); j++;
6328 XtGetValues(edit, args, j);
6329 val = PrevInHistory(val);
6330 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6331 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6333 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6334 XawTextReplace(edit, 0, 0, &t);
6335 XawTextSetInsertionPoint(edit, 9999);
6339 void DownKeyProc(w, event, prms, nprms)
6344 { // [HGM] input: let down-arrow recall next line from history
6349 if (!ICSInputBoxUp) return;
6350 edit = XtNameToWidget(ICSInputShell, "*form.text");
6351 val = NextInHistory();
6352 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6353 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6355 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6356 XawTextReplace(edit, 0, 0, &t);
6357 XawTextSetInsertionPoint(edit, 9999);
6361 void StopObservingProc(w, event, prms, nprms)
6367 StopObservingEvent();
6370 void StopExaminingProc(w, event, prms, nprms)
6376 StopExaminingEvent();
6379 void UploadProc(w, event, prms, nprms)
6389 void ForwardProc(w, event, prms, nprms)
6399 void BackwardProc(w, event, prms, nprms)
6408 void ToStartProc(w, event, prms, nprms)
6417 void ToEndProc(w, event, prms, nprms)
6426 void RevertProc(w, event, prms, nprms)
6435 void AnnotateProc(w, event, prms, nprms)
6444 void TruncateGameProc(w, event, prms, nprms)
6450 TruncateGameEvent();
6452 void RetractMoveProc(w, event, prms, nprms)
6461 void MoveNowProc(w, event, prms, nprms)
6471 void AlwaysQueenProc(w, event, prms, nprms)
6479 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6481 if (appData.alwaysPromoteToQueen) {
6482 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6484 XtSetArg(args[0], XtNleftBitmap, None);
6486 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6490 void AnimateDraggingProc(w, event, prms, nprms)
6498 appData.animateDragging = !appData.animateDragging;
6500 if (appData.animateDragging) {
6501 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6504 XtSetArg(args[0], XtNleftBitmap, None);
6506 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6510 void AnimateMovingProc(w, event, prms, nprms)
6518 appData.animate = !appData.animate;
6520 if (appData.animate) {
6521 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6524 XtSetArg(args[0], XtNleftBitmap, None);
6526 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6530 void AutocommProc(w, event, prms, nprms)
6538 appData.autoComment = !appData.autoComment;
6540 if (appData.autoComment) {
6541 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6543 XtSetArg(args[0], XtNleftBitmap, None);
6545 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6550 void AutoflagProc(w, event, prms, nprms)
6558 appData.autoCallFlag = !appData.autoCallFlag;
6560 if (appData.autoCallFlag) {
6561 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6563 XtSetArg(args[0], XtNleftBitmap, None);
6565 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6569 void AutoflipProc(w, event, prms, nprms)
6577 appData.autoFlipView = !appData.autoFlipView;
6579 if (appData.autoFlipView) {
6580 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6582 XtSetArg(args[0], XtNleftBitmap, None);
6584 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6588 void AutobsProc(w, event, prms, nprms)
6596 appData.autoObserve = !appData.autoObserve;
6598 if (appData.autoObserve) {
6599 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6601 XtSetArg(args[0], XtNleftBitmap, None);
6603 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6607 void AutoraiseProc(w, event, prms, nprms)
6615 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6617 if (appData.autoRaiseBoard) {
6618 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6620 XtSetArg(args[0], XtNleftBitmap, None);
6622 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6626 void AutosaveProc(w, event, prms, nprms)
6634 appData.autoSaveGames = !appData.autoSaveGames;
6636 if (appData.autoSaveGames) {
6637 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6639 XtSetArg(args[0], XtNleftBitmap, None);
6641 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6645 void BlindfoldProc(w, event, prms, nprms)
6653 appData.blindfold = !appData.blindfold;
6655 if (appData.blindfold) {
6656 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6658 XtSetArg(args[0], XtNleftBitmap, None);
6660 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6663 DrawPosition(True, NULL);
6666 void TestLegalityProc(w, event, prms, nprms)
6674 appData.testLegality = !appData.testLegality;
6676 if (appData.testLegality) {
6677 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6679 XtSetArg(args[0], XtNleftBitmap, None);
6681 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6686 void FlashMovesProc(w, event, prms, nprms)
6694 if (appData.flashCount == 0) {
6695 appData.flashCount = 3;
6697 appData.flashCount = -appData.flashCount;
6700 if (appData.flashCount > 0) {
6701 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6703 XtSetArg(args[0], XtNleftBitmap, None);
6705 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6709 void FlipViewProc(w, event, prms, nprms)
6715 flipView = !flipView;
6716 DrawPosition(True, NULL);
6719 void GetMoveListProc(w, event, prms, nprms)
6727 appData.getMoveList = !appData.getMoveList;
6729 if (appData.getMoveList) {
6730 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6733 XtSetArg(args[0], XtNleftBitmap, None);
6735 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6740 void HighlightDraggingProc(w, event, prms, nprms)
6748 appData.highlightDragging = !appData.highlightDragging;
6750 if (appData.highlightDragging) {
6751 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6753 XtSetArg(args[0], XtNleftBitmap, None);
6755 XtSetValues(XtNameToWidget(menuBarWidget,
6756 "menuOptions.Highlight Dragging"), args, 1);
6760 void HighlightLastMoveProc(w, event, prms, nprms)
6768 appData.highlightLastMove = !appData.highlightLastMove;
6770 if (appData.highlightLastMove) {
6771 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6773 XtSetArg(args[0], XtNleftBitmap, None);
6775 XtSetValues(XtNameToWidget(menuBarWidget,
6776 "menuOptions.Highlight Last Move"), args, 1);
6779 void IcsAlarmProc(w, event, prms, nprms)
6787 appData.icsAlarm = !appData.icsAlarm;
6789 if (appData.icsAlarm) {
6790 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6792 XtSetArg(args[0], XtNleftBitmap, None);
6794 XtSetValues(XtNameToWidget(menuBarWidget,
6795 "menuOptions.ICS Alarm"), args, 1);
6798 void MoveSoundProc(w, event, prms, nprms)
6806 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6808 if (appData.ringBellAfterMoves) {
6809 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6811 XtSetArg(args[0], XtNleftBitmap, None);
6813 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6818 void OldSaveStyleProc(w, event, prms, nprms)
6826 appData.oldSaveStyle = !appData.oldSaveStyle;
6828 if (appData.oldSaveStyle) {
6829 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6831 XtSetArg(args[0], XtNleftBitmap, None);
6833 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6837 void PeriodicUpdatesProc(w, event, prms, nprms)
6845 PeriodicUpdatesEvent(!appData.periodicUpdates);
6847 if (appData.periodicUpdates) {
6848 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6850 XtSetArg(args[0], XtNleftBitmap, None);
6852 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6856 void PonderNextMoveProc(w, event, prms, nprms)
6864 PonderNextMoveEvent(!appData.ponderNextMove);
6866 if (appData.ponderNextMove) {
6867 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6869 XtSetArg(args[0], XtNleftBitmap, None);
6871 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6875 void PopupExitMessageProc(w, event, prms, nprms)
6883 appData.popupExitMessage = !appData.popupExitMessage;
6885 if (appData.popupExitMessage) {
6886 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6888 XtSetArg(args[0], XtNleftBitmap, None);
6890 XtSetValues(XtNameToWidget(menuBarWidget,
6891 "menuOptions.Popup Exit Message"), args, 1);
6894 void PopupMoveErrorsProc(w, event, prms, nprms)
6902 appData.popupMoveErrors = !appData.popupMoveErrors;
6904 if (appData.popupMoveErrors) {
6905 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6907 XtSetArg(args[0], XtNleftBitmap, None);
6909 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6913 void PremoveProc(w, event, prms, nprms)
6921 appData.premove = !appData.premove;
6923 if (appData.premove) {
6924 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6926 XtSetArg(args[0], XtNleftBitmap, None);
6928 XtSetValues(XtNameToWidget(menuBarWidget,
6929 "menuOptions.Premove"), args, 1);
6932 void QuietPlayProc(w, event, prms, nprms)
6940 appData.quietPlay = !appData.quietPlay;
6942 if (appData.quietPlay) {
6943 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6945 XtSetArg(args[0], XtNleftBitmap, None);
6947 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6951 void ShowCoordsProc(w, event, prms, nprms)
6959 appData.showCoords = !appData.showCoords;
6961 if (appData.showCoords) {
6962 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6964 XtSetArg(args[0], XtNleftBitmap, None);
6966 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6969 DrawPosition(True, NULL);
6972 void ShowThinkingProc(w, event, prms, nprms)
6978 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6979 ShowThinkingEvent();
6982 void HideThinkingProc(w, event, prms, nprms)
6990 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6991 ShowThinkingEvent();
6993 if (appData.hideThinkingFromHuman) {
6994 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6996 XtSetArg(args[0], XtNleftBitmap, None);
6998 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
7002 void SaveOnExitProc(w, event, prms, nprms)
7010 saveSettingsOnExit = !saveSettingsOnExit;
7012 if (saveSettingsOnExit) {
7013 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
7015 XtSetArg(args[0], XtNleftBitmap, None);
7017 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
7021 void SaveSettingsProc(w, event, prms, nprms)
7027 SaveSettings(settingsFileName);
7030 void InfoProc(w, event, prms, nprms)
7037 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
7042 void ManProc(w, event, prms, nprms)
7050 if (nprms && *nprms > 0)
7054 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
7058 void HintProc(w, event, prms, nprms)
7067 void BookProc(w, event, prms, nprms)
7076 void AboutProc(w, event, prms, nprms)
7084 char *zippy = " (with Zippy code)";
7088 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
7089 programVersion, zippy,
7090 "Copyright 1991 Digital Equipment Corporation",
7091 "Enhancements Copyright 1992-2009 Free Software Foundation",
7092 "Enhancements Copyright 2005 Alessandro Scotti",
7093 PACKAGE, " is free software and carries NO WARRANTY;",
7094 "see the file COPYING for more information.");
7095 ErrorPopUp(_("About XBoard"), buf, FALSE);
7098 void DebugProc(w, event, prms, nprms)
7104 appData.debugMode = !appData.debugMode;
7107 void AboutGameProc(w, event, prms, nprms)
7116 void NothingProc(w, event, prms, nprms)
7125 void Iconify(w, event, prms, nprms)
7134 XtSetArg(args[0], XtNiconic, True);
7135 XtSetValues(shellWidget, args, 1);
7138 void DisplayMessage(message, extMessage)
7139 char *message, *extMessage;
7141 /* display a message in the message widget */
7150 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
7155 message = extMessage;
7159 /* need to test if messageWidget already exists, since this function
7160 can also be called during the startup, if for example a Xresource
7161 is not set up correctly */
7164 XtSetArg(arg, XtNlabel, message);
7165 XtSetValues(messageWidget, &arg, 1);
7171 void DisplayTitle(text)
7176 char title[MSG_SIZ];
7179 if (text == NULL) text = "";
7181 if (appData.titleInWindow) {
7183 XtSetArg(args[i], XtNlabel, text); i++;
7184 XtSetValues(titleWidget, args, i);
7187 if (*text != NULLCHAR) {
7188 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
7189 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
7190 } else if (appData.icsActive) {
7191 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7192 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7193 } else if (appData.cmailGameName[0] != NULLCHAR) {
7194 snprintf(icon, sizeof(icon), "%s", "CMail");
7195 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7197 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7198 } else if (gameInfo.variant == VariantGothic) {
7199 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7200 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
7203 } else if (gameInfo.variant == VariantFalcon) {
7204 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7205 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
7207 } else if (appData.noChessProgram) {
7208 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7209 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
7211 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
7212 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7215 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7216 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7217 XtSetValues(shellWidget, args, i);
7222 DisplayError(message, error)
7229 if (appData.debugMode || appData.matchMode) {
7230 fprintf(stderr, "%s: %s\n", programName, message);
7233 if (appData.debugMode || appData.matchMode) {
7234 fprintf(stderr, "%s: %s: %s\n",
7235 programName, message, strerror(error));
7237 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7240 ErrorPopUp(_("Error"), message, FALSE);
7244 void DisplayMoveError(message)
7249 DrawPosition(FALSE, NULL);
7250 if (appData.debugMode || appData.matchMode) {
7251 fprintf(stderr, "%s: %s\n", programName, message);
7253 if (appData.popupMoveErrors) {
7254 ErrorPopUp(_("Error"), message, FALSE);
7256 DisplayMessage(message, "");
7261 void DisplayFatalError(message, error, status)
7267 errorExitStatus = status;
7269 fprintf(stderr, "%s: %s\n", programName, message);
7271 fprintf(stderr, "%s: %s: %s\n",
7272 programName, message, strerror(error));
7273 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7276 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7277 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7283 void DisplayInformation(message)
7287 ErrorPopUp(_("Information"), message, TRUE);
7290 void DisplayNote(message)
7294 ErrorPopUp(_("Note"), message, FALSE);
7298 NullXErrorCheck(dpy, error_event)
7300 XErrorEvent *error_event;
7305 void DisplayIcsInteractionTitle(message)
7308 if (oldICSInteractionTitle == NULL) {
7309 /* Magic to find the old window title, adapted from vim */
7310 char *wina = getenv("WINDOWID");
7312 Window win = (Window) atoi(wina);
7313 Window root, parent, *children;
7314 unsigned int nchildren;
7315 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7317 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7318 if (!XQueryTree(xDisplay, win, &root, &parent,
7319 &children, &nchildren)) break;
7320 if (children) XFree((void *)children);
7321 if (parent == root || parent == 0) break;
7324 XSetErrorHandler(oldHandler);
7326 if (oldICSInteractionTitle == NULL) {
7327 oldICSInteractionTitle = "xterm";
7330 printf("\033]0;%s\007", message);
7334 char pendingReplyPrefix[MSG_SIZ];
7335 ProcRef pendingReplyPR;
7337 void AskQuestionProc(w, event, prms, nprms)
7344 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7348 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7351 void AskQuestionPopDown()
7353 if (!askQuestionUp) return;
7354 XtPopdown(askQuestionShell);
7355 XtDestroyWidget(askQuestionShell);
7356 askQuestionUp = False;
7359 void AskQuestionReplyAction(w, event, prms, nprms)
7369 reply = XawDialogGetValueString(w = XtParent(w));
7370 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
7371 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
7372 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
7373 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
7374 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7375 AskQuestionPopDown();
7377 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7380 void AskQuestionCallback(w, client_data, call_data)
7382 XtPointer client_data, call_data;
7387 XtSetArg(args[0], XtNlabel, &name);
7388 XtGetValues(w, args, 1);
7390 if (strcmp(name, _("cancel")) == 0) {
7391 AskQuestionPopDown();
7393 AskQuestionReplyAction(w, NULL, NULL, NULL);
7397 void AskQuestion(title, question, replyPrefix, pr)
7398 char *title, *question, *replyPrefix;
7402 Widget popup, layout, dialog, edit;
7408 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
7409 pendingReplyPR = pr;
7412 XtSetArg(args[i], XtNresizable, True); i++;
7413 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7414 askQuestionShell = popup =
7415 XtCreatePopupShell(title, transientShellWidgetClass,
7416 shellWidget, args, i);
7419 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7420 layoutArgs, XtNumber(layoutArgs));
7423 XtSetArg(args[i], XtNlabel, question); i++;
7424 XtSetArg(args[i], XtNvalue, ""); i++;
7425 XtSetArg(args[i], XtNborderWidth, 0); i++;
7426 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7429 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7430 (XtPointer) dialog);
7431 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7432 (XtPointer) dialog);
7434 XtRealizeWidget(popup);
7435 CatchDeleteWindow(popup, "AskQuestionPopDown");
7437 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7438 &x, &y, &win_x, &win_y, &mask);
7440 XtSetArg(args[0], XtNx, x - 10);
7441 XtSetArg(args[1], XtNy, y - 30);
7442 XtSetValues(popup, args, 2);
7444 XtPopup(popup, XtGrabExclusive);
7445 askQuestionUp = True;
7447 edit = XtNameToWidget(dialog, "*value");
7448 XtSetKeyboardFocus(popup, edit);
7456 if (*name == NULLCHAR) {
7458 } else if (strcmp(name, "$") == 0) {
7459 putc(BELLCHAR, stderr);
7462 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7470 PlaySound(appData.soundMove);
7476 PlaySound(appData.soundIcsWin);
7482 PlaySound(appData.soundIcsLoss);
7488 PlaySound(appData.soundIcsDraw);
7492 PlayIcsUnfinishedSound()
7494 PlaySound(appData.soundIcsUnfinished);
7500 PlaySound(appData.soundIcsAlarm);
7506 system("stty echo");
7512 system("stty -echo");
7516 Colorize(cc, continuation)
7521 int count, outCount, error;
7523 if (textColors[(int)cc].bg > 0) {
7524 if (textColors[(int)cc].fg > 0) {
7525 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7526 textColors[(int)cc].fg, textColors[(int)cc].bg);
7528 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7529 textColors[(int)cc].bg);
7532 if (textColors[(int)cc].fg > 0) {
7533 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7534 textColors[(int)cc].fg);
7536 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7539 count = strlen(buf);
7540 outCount = OutputToProcess(NoProc, buf, count, &error);
7541 if (outCount < count) {
7542 DisplayFatalError(_("Error writing to display"), error, 1);
7545 if (continuation) return;
7548 PlaySound(appData.soundShout);
7551 PlaySound(appData.soundSShout);
7554 PlaySound(appData.soundChannel1);
7557 PlaySound(appData.soundChannel);
7560 PlaySound(appData.soundKibitz);
7563 PlaySound(appData.soundTell);
7565 case ColorChallenge:
7566 PlaySound(appData.soundChallenge);
7569 PlaySound(appData.soundRequest);
7572 PlaySound(appData.soundSeek);
7583 return getpwuid(getuid())->pw_name;
7587 ExpandPathName(path)
7590 static char static_buf[4*MSG_SIZ];
7591 char *d, *s, buf[4*MSG_SIZ];
7597 while (*s && isspace(*s))
7606 if (*(s+1) == '/') {
7607 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7611 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7612 *strchr(buf, '/') = 0;
7613 pwd = getpwnam(buf);
7616 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7620 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7621 strcat(d, strchr(s+1, '/'));
7625 safeStrCpy(d, s, 4*MSG_SIZ );
7632 static char host_name[MSG_SIZ];
7634 #if HAVE_GETHOSTNAME
7635 gethostname(host_name, MSG_SIZ);
7637 #else /* not HAVE_GETHOSTNAME */
7638 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7639 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7641 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7643 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7644 #endif /* not HAVE_GETHOSTNAME */
7647 XtIntervalId delayedEventTimerXID = 0;
7648 DelayedEventCallback delayedEventCallback = 0;
7653 delayedEventTimerXID = 0;
7654 delayedEventCallback();
7658 ScheduleDelayedEvent(cb, millisec)
7659 DelayedEventCallback cb; long millisec;
7661 if(delayedEventTimerXID && delayedEventCallback == cb)
7662 // [HGM] alive: replace, rather than add or flush identical event
7663 XtRemoveTimeOut(delayedEventTimerXID);
7664 delayedEventCallback = cb;
7665 delayedEventTimerXID =
7666 XtAppAddTimeOut(appContext, millisec,
7667 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7670 DelayedEventCallback
7673 if (delayedEventTimerXID) {
7674 return delayedEventCallback;
7681 CancelDelayedEvent()
7683 if (delayedEventTimerXID) {
7684 XtRemoveTimeOut(delayedEventTimerXID);
7685 delayedEventTimerXID = 0;
7689 XtIntervalId loadGameTimerXID = 0;
7691 int LoadGameTimerRunning()
7693 return loadGameTimerXID != 0;
7696 int StopLoadGameTimer()
7698 if (loadGameTimerXID != 0) {
7699 XtRemoveTimeOut(loadGameTimerXID);
7700 loadGameTimerXID = 0;
7708 LoadGameTimerCallback(arg, id)
7712 loadGameTimerXID = 0;
7717 StartLoadGameTimer(millisec)
7721 XtAppAddTimeOut(appContext, millisec,
7722 (XtTimerCallbackProc) LoadGameTimerCallback,
7726 XtIntervalId analysisClockXID = 0;
7729 AnalysisClockCallback(arg, id)
7733 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7734 || appData.icsEngineAnalyze) { // [DM]
7735 AnalysisPeriodicEvent(0);
7736 StartAnalysisClock();
7741 StartAnalysisClock()
7744 XtAppAddTimeOut(appContext, 2000,
7745 (XtTimerCallbackProc) AnalysisClockCallback,
7749 XtIntervalId clockTimerXID = 0;
7751 int ClockTimerRunning()
7753 return clockTimerXID != 0;
7756 int StopClockTimer()
7758 if (clockTimerXID != 0) {
7759 XtRemoveTimeOut(clockTimerXID);
7768 ClockTimerCallback(arg, id)
7777 StartClockTimer(millisec)
7781 XtAppAddTimeOut(appContext, millisec,
7782 (XtTimerCallbackProc) ClockTimerCallback,
7787 DisplayTimerLabel(w, color, timer, highlight)
7796 /* check for low time warning */
7797 Pixel foregroundOrWarningColor = timerForegroundPixel;
7800 appData.lowTimeWarning &&
7801 (timer / 1000) < appData.icsAlarmTime)
7802 foregroundOrWarningColor = lowTimeWarningColor;
7804 if (appData.clockMode) {
7805 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7806 XtSetArg(args[0], XtNlabel, buf);
7808 snprintf(buf, MSG_SIZ, "%s ", color);
7809 XtSetArg(args[0], XtNlabel, buf);
7814 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7815 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7817 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7818 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7821 XtSetValues(w, args, 3);
7825 DisplayWhiteClock(timeRemaining, highlight)
7831 if(appData.noGUI) return;
7832 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7833 if (highlight && iconPixmap == bIconPixmap) {
7834 iconPixmap = wIconPixmap;
7835 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7836 XtSetValues(shellWidget, args, 1);
7841 DisplayBlackClock(timeRemaining, highlight)
7847 if(appData.noGUI) return;
7848 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7849 if (highlight && iconPixmap == wIconPixmap) {
7850 iconPixmap = bIconPixmap;
7851 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7852 XtSetValues(shellWidget, args, 1);
7870 int StartChildProcess(cmdLine, dir, pr)
7877 int to_prog[2], from_prog[2];
7881 if (appData.debugMode) {
7882 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7885 /* We do NOT feed the cmdLine to the shell; we just
7886 parse it into blank-separated arguments in the
7887 most simple-minded way possible.
7890 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7893 while(*p == ' ') p++;
7895 if(*p == '"' || *p == '\'')
7896 p = strchr(++argv[i-1], *p);
7897 else p = strchr(p, ' ');
7898 if (p == NULL) break;
7903 SetUpChildIO(to_prog, from_prog);
7905 if ((pid = fork()) == 0) {
7907 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7908 close(to_prog[1]); // first close the unused pipe ends
7909 close(from_prog[0]);
7910 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7911 dup2(from_prog[1], 1);
7912 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7913 close(from_prog[1]); // and closing again loses one of the pipes!
7914 if(fileno(stderr) >= 2) // better safe than sorry...
7915 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7917 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7922 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7924 execvp(argv[0], argv);
7926 /* If we get here, exec failed */
7931 /* Parent process */
7933 close(from_prog[1]);
7935 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7938 cp->fdFrom = from_prog[0];
7939 cp->fdTo = to_prog[1];
7944 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7945 static RETSIGTYPE AlarmCallBack(int n)
7951 DestroyChildProcess(pr, signalType)
7955 ChildProc *cp = (ChildProc *) pr;
7957 if (cp->kind != CPReal) return;
7959 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7960 signal(SIGALRM, AlarmCallBack);
7962 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7963 kill(cp->pid, SIGKILL); // kill it forcefully
7964 wait((int *) 0); // and wait again
7968 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7970 /* Process is exiting either because of the kill or because of
7971 a quit command sent by the backend; either way, wait for it to die.
7980 InterruptChildProcess(pr)
7983 ChildProc *cp = (ChildProc *) pr;
7985 if (cp->kind != CPReal) return;
7986 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7989 int OpenTelnet(host, port, pr)
7994 char cmdLine[MSG_SIZ];
7996 if (port[0] == NULLCHAR) {
7997 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7999 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
8001 return StartChildProcess(cmdLine, "", pr);
8004 int OpenTCP(host, port, pr)
8010 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
8011 #else /* !OMIT_SOCKETS */
8013 struct sockaddr_in sa;
8015 unsigned short uport;
8018 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
8022 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
8023 sa.sin_family = AF_INET;
8024 sa.sin_addr.s_addr = INADDR_ANY;
8025 uport = (unsigned short) 0;
8026 sa.sin_port = htons(uport);
8027 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
8031 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
8032 if (!(hp = gethostbyname(host))) {
8034 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
8035 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
8036 hp->h_addrtype = AF_INET;
8038 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
8039 hp->h_addr_list[0] = (char *) malloc(4);
8040 hp->h_addr_list[0][0] = b0;
8041 hp->h_addr_list[0][1] = b1;
8042 hp->h_addr_list[0][2] = b2;
8043 hp->h_addr_list[0][3] = b3;
8048 sa.sin_family = hp->h_addrtype;
8049 uport = (unsigned short) atoi(port);
8050 sa.sin_port = htons(uport);
8051 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
8053 if (connect(s, (struct sockaddr *) &sa,
8054 sizeof(struct sockaddr_in)) < 0) {
8058 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8065 #endif /* !OMIT_SOCKETS */
8070 int OpenCommPort(name, pr)
8077 fd = open(name, 2, 0);
8078 if (fd < 0) return errno;
8080 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8090 int OpenLoopback(pr)
8096 SetUpChildIO(to, from);
8098 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8101 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
8108 int OpenRcmd(host, user, cmd, pr)
8109 char *host, *user, *cmd;
8112 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
8116 #define INPUT_SOURCE_BUF_SIZE 8192
8125 char buf[INPUT_SOURCE_BUF_SIZE];
8130 DoInputCallback(closure, source, xid)
8135 InputSource *is = (InputSource *) closure;
8140 if (is->lineByLine) {
8141 count = read(is->fd, is->unused,
8142 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
8144 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
8147 is->unused += count;
8149 while (p < is->unused) {
8150 q = memchr(p, '\n', is->unused - p);
8151 if (q == NULL) break;
8153 (is->func)(is, is->closure, p, q - p, 0);
8157 while (p < is->unused) {
8162 # if HAVE_LIBREADLINE
8163 /* check if input is from stdin, if yes, use gnu-readline */
8164 if( is->fd==fileno(stdin) )
8166 /* to clear the line */
8169 /* read from stdin */
8170 rl_callback_read_char();
8172 /* redisplay the current line, check special case for login and password */
8173 if(sending_ICS_password)
8175 int i; char buf[MSG_SIZ];
8179 /* blank the password */
8180 count = strlen(rl_line_buffer);
8183 printf("PROBLEM with readline\n");
8186 for(i=0;i<count;i++)
8190 printf("\rpassword: %s",buf);
8192 else if (sending_ICS_login)
8194 /* show login prompt */
8195 count = strlen(rl_line_buffer);
8196 printf("\rlogin: %s",rl_line_buffer);
8199 rl_reset_line_state();
8201 if(readline_complete)
8203 /* copy into XBoards buffer */
8204 count = strlen(readline_buffer);
8205 if (count>INPUT_SOURCE_BUF_SIZE-1)
8207 printf("PROBLEM with readline\n");
8208 count = INPUT_SOURCE_BUF_SIZE;
8210 strncpy(is->buf,readline_buffer,count);
8211 is->buf[count]='\n';count++;
8213 /* reset gnu-readline state */
8214 free(readline_buffer);
8215 readline_buffer=NULL;
8216 readline_complete=0;
8222 (is->func)(is, is->closure, is->buf, count, error);
8224 /* are we done with the password? */
8225 if(sending_ICS_password)
8226 sending_ICS_password=0;
8227 if(sending_ICS_login)
8228 sending_ICS_login=0;
8233 /* input not from stdin, use default method */
8234 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8239 (is->func)(is, is->closure, is->buf, count, error);
8241 #else /* no readline support */
8242 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8247 (is->func)(is, is->closure, is->buf, count, error);
8253 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8260 ChildProc *cp = (ChildProc *) pr;
8262 is = (InputSource *) calloc(1, sizeof(InputSource));
8263 is->lineByLine = lineByLine;
8267 is->fd = fileno(stdin);
8269 is->kind = cp->kind;
8270 is->fd = cp->fdFrom;
8273 is->unused = is->buf;
8276 is->xid = XtAppAddInput(appContext, is->fd,
8277 (XtPointer) (XtInputReadMask),
8278 (XtInputCallbackProc) DoInputCallback,
8280 is->closure = closure;
8281 return (InputSourceRef) is;
8285 RemoveInputSource(isr)
8288 InputSource *is = (InputSource *) isr;
8290 if (is->xid == 0) return;
8291 XtRemoveInput(is->xid);
8295 int OutputToProcess(pr, message, count, outError)
8301 static int line = 0;
8302 ChildProc *cp = (ChildProc *) pr;
8308 if (appData.noJoin || !appData.useInternalWrap)
8309 outCount = fwrite(message, 1, count, stdout);
8312 int width = get_term_width();
8313 int len = wrap(NULL, message, count, width, &line);
8314 char *msg = malloc(len);
8318 outCount = fwrite(message, 1, count, stdout);
8321 dbgchk = wrap(msg, message, count, width, &line);
8322 if (dbgchk != len && appData.debugMode)
8323 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8324 outCount = fwrite(msg, 1, dbgchk, stdout);
8329 # if HAVE_LIBREADLINE
8330 /* readline support */
8331 if(strlen(rl_line_buffer))
8332 printf("\n> %s",rl_line_buffer);
8337 outCount = write(cp->fdTo, message, count);
8347 /* Output message to process, with "ms" milliseconds of delay
8348 between each character. This is needed when sending the logon
8349 script to ICC, which for some reason doesn't like the
8350 instantaneous send. */
8351 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8358 ChildProc *cp = (ChildProc *) pr;
8363 r = write(cp->fdTo, message++, 1);
8376 /**** Animation code by Hugh Fisher, DCS, ANU.
8378 Known problem: if a window overlapping the board is
8379 moved away while a piece is being animated underneath,
8380 the newly exposed area won't be updated properly.
8381 I can live with this.
8383 Known problem: if you look carefully at the animation
8384 of pieces in mono mode, they are being drawn as solid
8385 shapes without interior detail while moving. Fixing
8386 this would be a major complication for minimal return.
8389 /* Masks for XPM pieces. Black and white pieces can have
8390 different shapes, but in the interest of retaining my
8391 sanity pieces must have the same outline on both light
8392 and dark squares, and all pieces must use the same
8393 background square colors/images. */
8395 static int xpmDone = 0;
8398 CreateAnimMasks (pieceDepth)
8405 unsigned long plane;
8408 /* Need a bitmap just to get a GC with right depth */
8409 buf = XCreatePixmap(xDisplay, xBoardWindow,
8411 values.foreground = 1;
8412 values.background = 0;
8413 /* Don't use XtGetGC, not read only */
8414 maskGC = XCreateGC(xDisplay, buf,
8415 GCForeground | GCBackground, &values);
8416 XFreePixmap(xDisplay, buf);
8418 buf = XCreatePixmap(xDisplay, xBoardWindow,
8419 squareSize, squareSize, pieceDepth);
8420 values.foreground = XBlackPixel(xDisplay, xScreen);
8421 values.background = XWhitePixel(xDisplay, xScreen);
8422 bufGC = XCreateGC(xDisplay, buf,
8423 GCForeground | GCBackground, &values);
8425 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8426 /* Begin with empty mask */
8427 if(!xpmDone) // [HGM] pieces: keep using existing
8428 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8429 squareSize, squareSize, 1);
8430 XSetFunction(xDisplay, maskGC, GXclear);
8431 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8432 0, 0, squareSize, squareSize);
8434 /* Take a copy of the piece */
8439 XSetFunction(xDisplay, bufGC, GXcopy);
8440 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8442 0, 0, squareSize, squareSize, 0, 0);
8444 /* XOR the background (light) over the piece */
8445 XSetFunction(xDisplay, bufGC, GXxor);
8447 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8448 0, 0, squareSize, squareSize, 0, 0);
8450 XSetForeground(xDisplay, bufGC, lightSquareColor);
8451 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8454 /* We now have an inverted piece image with the background
8455 erased. Construct mask by just selecting all the non-zero
8456 pixels - no need to reconstruct the original image. */
8457 XSetFunction(xDisplay, maskGC, GXor);
8459 /* Might be quicker to download an XImage and create bitmap
8460 data from it rather than this N copies per piece, but it
8461 only takes a fraction of a second and there is a much
8462 longer delay for loading the pieces. */
8463 for (n = 0; n < pieceDepth; n ++) {
8464 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8465 0, 0, squareSize, squareSize,
8471 XFreePixmap(xDisplay, buf);
8472 XFreeGC(xDisplay, bufGC);
8473 XFreeGC(xDisplay, maskGC);
8477 InitAnimState (anim, info)
8479 XWindowAttributes * info;
8484 /* Each buffer is square size, same depth as window */
8485 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8486 squareSize, squareSize, info->depth);
8487 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8488 squareSize, squareSize, info->depth);
8490 /* Create a plain GC for blitting */
8491 mask = GCForeground | GCBackground | GCFunction |
8492 GCPlaneMask | GCGraphicsExposures;
8493 values.foreground = XBlackPixel(xDisplay, xScreen);
8494 values.background = XWhitePixel(xDisplay, xScreen);
8495 values.function = GXcopy;
8496 values.plane_mask = AllPlanes;
8497 values.graphics_exposures = False;
8498 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8500 /* Piece will be copied from an existing context at
8501 the start of each new animation/drag. */
8502 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8504 /* Outline will be a read-only copy of an existing */
8505 anim->outlineGC = None;
8511 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8512 XWindowAttributes info;
8514 if (xpmDone && gameInfo.variant == old) return;
8515 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8516 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8518 InitAnimState(&game, &info);
8519 InitAnimState(&player, &info);
8521 /* For XPM pieces, we need bitmaps to use as masks. */
8523 CreateAnimMasks(info.depth);
8529 static Boolean frameWaiting;
8531 static RETSIGTYPE FrameAlarm (sig)
8534 frameWaiting = False;
8535 /* In case System-V style signals. Needed?? */
8536 signal(SIGALRM, FrameAlarm);
8543 struct itimerval delay;
8545 XSync(xDisplay, False);
8548 frameWaiting = True;
8549 signal(SIGALRM, FrameAlarm);
8550 delay.it_interval.tv_sec =
8551 delay.it_value.tv_sec = time / 1000;
8552 delay.it_interval.tv_usec =
8553 delay.it_value.tv_usec = (time % 1000) * 1000;
8554 setitimer(ITIMER_REAL, &delay, NULL);
8555 while (frameWaiting) pause();
8556 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8557 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8558 setitimer(ITIMER_REAL, &delay, NULL);
8568 XSync(xDisplay, False);
8570 usleep(time * 1000);
8575 /* Convert board position to corner of screen rect and color */
8578 ScreenSquare(column, row, pt, color)
8579 int column; int row; XPoint * pt; int * color;
8582 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8583 pt->y = lineGap + row * (squareSize + lineGap);
8585 pt->x = lineGap + column * (squareSize + lineGap);
8586 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8588 *color = SquareColor(row, column);
8591 /* Convert window coords to square */
8594 BoardSquare(x, y, column, row)
8595 int x; int y; int * column; int * row;
8597 *column = EventToSquare(x, BOARD_WIDTH);
8598 if (flipView && *column >= 0)
8599 *column = BOARD_WIDTH - 1 - *column;
8600 *row = EventToSquare(y, BOARD_HEIGHT);
8601 if (!flipView && *row >= 0)
8602 *row = BOARD_HEIGHT - 1 - *row;
8607 #undef Max /* just in case */
8609 #define Max(a, b) ((a) > (b) ? (a) : (b))
8610 #define Min(a, b) ((a) < (b) ? (a) : (b))
8613 SetRect(rect, x, y, width, height)
8614 XRectangle * rect; int x; int y; int width; int height;
8618 rect->width = width;
8619 rect->height = height;
8622 /* Test if two frames overlap. If they do, return
8623 intersection rect within old and location of
8624 that rect within new. */
8627 Intersect(old, new, size, area, pt)
8628 XPoint * old; XPoint * new;
8629 int size; XRectangle * area; XPoint * pt;
8631 if (old->x > new->x + size || new->x > old->x + size ||
8632 old->y > new->y + size || new->y > old->y + size) {
8635 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8636 size - abs(old->x - new->x), size - abs(old->y - new->y));
8637 pt->x = Max(old->x - new->x, 0);
8638 pt->y = Max(old->y - new->y, 0);
8643 /* For two overlapping frames, return the rect(s)
8644 in the old that do not intersect with the new. */
8647 CalcUpdateRects(old, new, size, update, nUpdates)
8648 XPoint * old; XPoint * new; int size;
8649 XRectangle update[]; int * nUpdates;
8653 /* If old = new (shouldn't happen) then nothing to draw */
8654 if (old->x == new->x && old->y == new->y) {
8658 /* Work out what bits overlap. Since we know the rects
8659 are the same size we don't need a full intersect calc. */
8661 /* Top or bottom edge? */
8662 if (new->y > old->y) {
8663 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8665 } else if (old->y > new->y) {
8666 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8667 size, old->y - new->y);
8670 /* Left or right edge - don't overlap any update calculated above. */
8671 if (new->x > old->x) {
8672 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8673 new->x - old->x, size - abs(new->y - old->y));
8675 } else if (old->x > new->x) {
8676 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8677 old->x - new->x, size - abs(new->y - old->y));
8684 /* Generate a series of frame coords from start->mid->finish.
8685 The movement rate doubles until the half way point is
8686 reached, then halves back down to the final destination,
8687 which gives a nice slow in/out effect. The algorithmn
8688 may seem to generate too many intermediates for short
8689 moves, but remember that the purpose is to attract the
8690 viewers attention to the piece about to be moved and
8691 then to where it ends up. Too few frames would be less
8695 Tween(start, mid, finish, factor, frames, nFrames)
8696 XPoint * start; XPoint * mid;
8697 XPoint * finish; int factor;
8698 XPoint frames[]; int * nFrames;
8700 int fraction, n, count;
8704 /* Slow in, stepping 1/16th, then 1/8th, ... */
8706 for (n = 0; n < factor; n++)
8708 for (n = 0; n < factor; n++) {
8709 frames[count].x = start->x + (mid->x - start->x) / fraction;
8710 frames[count].y = start->y + (mid->y - start->y) / fraction;
8712 fraction = fraction / 2;
8716 frames[count] = *mid;
8719 /* Slow out, stepping 1/2, then 1/4, ... */
8721 for (n = 0; n < factor; n++) {
8722 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8723 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8725 fraction = fraction * 2;
8730 /* Draw a piece on the screen without disturbing what's there */
8733 SelectGCMask(piece, clip, outline, mask)
8734 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8738 /* Bitmap for piece being moved. */
8739 if (appData.monoMode) {
8740 *mask = *pieceToSolid(piece);
8741 } else if (useImages) {
8743 *mask = xpmMask[piece];
8745 *mask = ximMaskPm[piece];
8748 *mask = *pieceToSolid(piece);
8751 /* GC for piece being moved. Square color doesn't matter, but
8752 since it gets modified we make a copy of the original. */
8754 if (appData.monoMode)
8759 if (appData.monoMode)
8764 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8766 /* Outline only used in mono mode and is not modified */
8768 *outline = bwPieceGC;
8770 *outline = wbPieceGC;
8774 OverlayPiece(piece, clip, outline, dest)
8775 ChessSquare piece; GC clip; GC outline; Drawable dest;
8780 /* Draw solid rectangle which will be clipped to shape of piece */
8781 XFillRectangle(xDisplay, dest, clip,
8782 0, 0, squareSize, squareSize);
8783 if (appData.monoMode)
8784 /* Also draw outline in contrasting color for black
8785 on black / white on white cases */
8786 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8787 0, 0, squareSize, squareSize, 0, 0, 1);
8789 /* Copy the piece */
8794 if(appData.upsideDown && flipView) kind ^= 2;
8795 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8797 0, 0, squareSize, squareSize,
8802 /* Animate the movement of a single piece */
8805 BeginAnimation(anim, piece, startColor, start)
8813 /* The old buffer is initialised with the start square (empty) */
8814 BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0);
8815 anim->prevFrame = *start;
8817 /* The piece will be drawn using its own bitmap as a matte */
8818 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8819 XSetClipMask(xDisplay, anim->pieceGC, mask);
8823 AnimationFrame(anim, frame, piece)
8828 XRectangle updates[4];
8833 /* Save what we are about to draw into the new buffer */
8834 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8835 frame->x, frame->y, squareSize, squareSize,
8838 /* Erase bits of the previous frame */
8839 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8840 /* Where the new frame overlapped the previous,
8841 the contents in newBuf are wrong. */
8842 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8843 overlap.x, overlap.y,
8844 overlap.width, overlap.height,
8846 /* Repaint the areas in the old that don't overlap new */
8847 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8848 for (i = 0; i < count; i++)
8849 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8850 updates[i].x - anim->prevFrame.x,
8851 updates[i].y - anim->prevFrame.y,
8852 updates[i].width, updates[i].height,
8853 updates[i].x, updates[i].y);
8855 /* Easy when no overlap */
8856 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8857 0, 0, squareSize, squareSize,
8858 anim->prevFrame.x, anim->prevFrame.y);
8861 /* Save this frame for next time round */
8862 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8863 0, 0, squareSize, squareSize,
8865 anim->prevFrame = *frame;
8867 /* Draw piece over original screen contents, not current,
8868 and copy entire rect. Wipes out overlapping piece images. */
8869 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8870 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8871 0, 0, squareSize, squareSize,
8872 frame->x, frame->y);
8876 EndAnimation (anim, finish)
8880 XRectangle updates[4];
8885 /* The main code will redraw the final square, so we
8886 only need to erase the bits that don't overlap. */
8887 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8888 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8889 for (i = 0; i < count; i++)
8890 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8891 updates[i].x - anim->prevFrame.x,
8892 updates[i].y - anim->prevFrame.y,
8893 updates[i].width, updates[i].height,
8894 updates[i].x, updates[i].y);
8896 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8897 0, 0, squareSize, squareSize,
8898 anim->prevFrame.x, anim->prevFrame.y);
8903 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8905 ChessSquare piece; int startColor;
8906 XPoint * start; XPoint * finish;
8907 XPoint frames[]; int nFrames;
8911 BeginAnimation(anim, piece, startColor, start);
8912 for (n = 0; n < nFrames; n++) {
8913 AnimationFrame(anim, &(frames[n]), piece);
8914 FrameDelay(appData.animSpeed);
8916 EndAnimation(anim, finish);
8920 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
8923 ChessSquare piece = board[fromY][toY];
8924 board[fromY][toY] = EmptySquare;
8925 DrawPosition(FALSE, board);
8927 x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap);
8928 y = lineGap + toY * (squareSize + lineGap);
8930 x = lineGap + toX * (squareSize + lineGap);
8931 y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap);
8933 for(i=1; i<4*kFactor; i++) {
8934 int r = squareSize * 9 * i/(20*kFactor - 5);
8935 XFillArc(xDisplay, xBoardWindow, highlineGC,
8936 x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360);
8937 FrameDelay(appData.animSpeed);
8939 board[fromY][toY] = piece;
8942 /* Main control logic for deciding what to animate and how */
8945 AnimateMove(board, fromX, fromY, toX, toY)
8954 XPoint start, finish, mid;
8955 XPoint frames[kFactor * 2 + 1];
8956 int nFrames, startColor, endColor;
8958 /* Are we animating? */
8959 if (!appData.animate || appData.blindfold)
8962 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8963 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8964 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8966 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8967 piece = board[fromY][fromX];
8968 if (piece >= EmptySquare) return;
8973 hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1;
8976 if (appData.debugMode) {
8977 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8978 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8979 piece, fromX, fromY, toX, toY); }
8981 ScreenSquare(fromX, fromY, &start, &startColor);
8982 ScreenSquare(toX, toY, &finish, &endColor);
8985 /* Knight: make straight movement then diagonal */
8986 if (abs(toY - fromY) < abs(toX - fromX)) {
8987 mid.x = start.x + (finish.x - start.x) / 2;
8991 mid.y = start.y + (finish.y - start.y) / 2;
8994 mid.x = start.x + (finish.x - start.x) / 2;
8995 mid.y = start.y + (finish.y - start.y) / 2;
8998 /* Don't use as many frames for very short moves */
8999 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
9000 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
9002 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
9003 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
9004 if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
9006 for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
9007 if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
9010 /* Be sure end square is redrawn */
9011 damage[0][toY][toX] = True;
9015 DragPieceBegin(x, y)
9018 int boardX, boardY, color;
9021 /* Are we animating? */
9022 if (!appData.animateDragging || appData.blindfold)
9025 /* Figure out which square we start in and the
9026 mouse position relative to top left corner. */
9027 BoardSquare(x, y, &boardX, &boardY);
9028 player.startBoardX = boardX;
9029 player.startBoardY = boardY;
9030 ScreenSquare(boardX, boardY, &corner, &color);
9031 player.startSquare = corner;
9032 player.startColor = color;
9033 /* As soon as we start dragging, the piece will jump slightly to
9034 be centered over the mouse pointer. */
9035 player.mouseDelta.x = squareSize/2;
9036 player.mouseDelta.y = squareSize/2;
9037 /* Initialise animation */
9038 player.dragPiece = PieceForSquare(boardX, boardY);
9040 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
9041 player.dragActive = True;
9042 BeginAnimation(&player, player.dragPiece, color, &corner);
9043 /* Mark this square as needing to be redrawn. Note that
9044 we don't remove the piece though, since logically (ie
9045 as seen by opponent) the move hasn't been made yet. */
9046 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
9047 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
9048 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
9049 corner.x, corner.y, squareSize, squareSize,
9050 0, 0); // [HGM] zh: unstack in stead of grab
9051 damage[0][boardY][boardX] = True;
9053 player.dragActive = False;
9063 /* Are we animating? */
9064 if (!appData.animateDragging || appData.blindfold)
9068 if (! player.dragActive)
9070 /* Move piece, maintaining same relative position
9071 of mouse within square */
9072 corner.x = x - player.mouseDelta.x;
9073 corner.y = y - player.mouseDelta.y;
9074 AnimationFrame(&player, &corner, player.dragPiece);
9076 if (appData.highlightDragging) {
9078 BoardSquare(x, y, &boardX, &boardY);
9079 SetHighlights(fromX, fromY, boardX, boardY);
9088 int boardX, boardY, color;
9091 /* Are we animating? */
9092 if (!appData.animateDragging || appData.blindfold)
9096 if (! player.dragActive)
9098 /* Last frame in sequence is square piece is
9099 placed on, which may not match mouse exactly. */
9100 BoardSquare(x, y, &boardX, &boardY);
9101 ScreenSquare(boardX, boardY, &corner, &color);
9102 EndAnimation(&player, &corner);
9104 /* Be sure end square is redrawn */
9105 damage[0][boardY][boardX] = True;
9107 /* This prevents weird things happening with fast successive
9108 clicks which on my Sun at least can cause motion events
9109 without corresponding press/release. */
9110 player.dragActive = False;
9113 /* Handle expose event while piece being dragged */
9118 if (!player.dragActive || appData.blindfold)
9121 /* What we're doing: logically, the move hasn't been made yet,
9122 so the piece is still in it's original square. But visually
9123 it's being dragged around the board. So we erase the square
9124 that the piece is on and draw it at the last known drag point. */
9125 BlankSquare(player.startSquare.x, player.startSquare.y,
9126 player.startColor, EmptySquare, xBoardWindow, 1);
9127 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
9128 damage[0][player.startBoardY][player.startBoardX] = TRUE;
9131 #include <sys/ioctl.h>
9132 int get_term_width()
9134 int fd, default_width;
9137 default_width = 79; // this is FICS default anyway...
9139 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
9141 if (!ioctl(fd, TIOCGSIZE, &win))
9142 default_width = win.ts_cols;
9143 #elif defined(TIOCGWINSZ)
9145 if (!ioctl(fd, TIOCGWINSZ, &win))
9146 default_width = win.ws_col;
9148 return default_width;
9154 static int old_width = 0;
9155 int new_width = get_term_width();
9157 if (old_width != new_width)
9158 ics_printf("set width %d\n", new_width);
9159 old_width = new_width;
9162 void NotifyFrontendLogin()
9167 # if HAVE_LIBREADLINE
9169 ReadlineCompleteHandler(char* ptr)
9171 /* make gnu-readline keep the history */
9172 readline_buffer = ptr;
9173 readline_complete = 1;
9175 if (ptr && *ptr && !sending_ICS_password && !sending_ICS_login)