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
144 #include <X11/Intrinsic.h>
145 #include <X11/StringDefs.h>
146 #include <X11/Shell.h>
147 #include <X11/cursorfont.h>
148 #include <X11/Xatom.h>
149 #include <X11/Xmu/Atoms.h>
151 #include <X11/Xaw3d/Dialog.h>
152 #include <X11/Xaw3d/Form.h>
153 #include <X11/Xaw3d/List.h>
154 #include <X11/Xaw3d/Label.h>
155 #include <X11/Xaw3d/SimpleMenu.h>
156 #include <X11/Xaw3d/SmeBSB.h>
157 #include <X11/Xaw3d/SmeLine.h>
158 #include <X11/Xaw3d/Box.h>
159 #include <X11/Xaw3d/MenuButton.h>
160 #include <X11/Xaw3d/Text.h>
161 #include <X11/Xaw3d/AsciiText.h>
163 #include <X11/Xaw/Dialog.h>
164 #include <X11/Xaw/Form.h>
165 #include <X11/Xaw/List.h>
166 #include <X11/Xaw/Label.h>
167 #include <X11/Xaw/SimpleMenu.h>
168 #include <X11/Xaw/SmeBSB.h>
169 #include <X11/Xaw/SmeLine.h>
170 #include <X11/Xaw/Box.h>
171 #include <X11/Xaw/MenuButton.h>
172 #include <X11/Xaw/Text.h>
173 #include <X11/Xaw/AsciiText.h>
176 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
181 #include "pixmaps/pixmaps.h"
182 #define IMAGE_EXT "xpm"
184 #define IMAGE_EXT "xim"
185 #include "bitmaps/bitmaps.h"
188 #include "bitmaps/icon_white.bm"
189 #include "bitmaps/icon_black.bm"
190 #include "bitmaps/checkmark.bm"
192 #include "frontend.h"
194 #include "backendz.h"
198 #include "xgamelist.h"
199 #include "xhistory.h"
200 #include "xedittags.h"
203 // must be moved to xengineoutput.h
205 void EngineOutputProc P((Widget w, XEvent *event,
206 String *prms, Cardinal *nprms));
207 void EvalGraphProc P((Widget w, XEvent *event,
208 String *prms, Cardinal *nprms));
215 #define usleep(t) _sleep2(((t)+500)/1000)
219 # define _(s) gettext (s)
220 # define N_(s) gettext_noop (s)
238 int main P((int argc, char **argv));
239 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
240 char *init_path, char *mode, int (*show_entry)(), char **name_return));
241 RETSIGTYPE CmailSigHandler P((int sig));
242 RETSIGTYPE IntSigHandler P((int sig));
243 RETSIGTYPE TermSizeSigHandler P((int sig));
244 void CreateGCs P((void));
245 void CreateXIMPieces P((void));
246 void CreateXPMPieces P((void));
247 void CreateXPMBoard P((char *s, int n));
248 void CreatePieces P((void));
249 void CreatePieceMenus P((void));
250 Widget CreateMenuBar P((Menu *mb));
251 Widget CreateButtonBar P ((MenuItem *mi));
252 char *FindFont P((char *pattern, int targetPxlSize));
253 void PieceMenuPopup P((Widget w, XEvent *event,
254 String *params, Cardinal *num_params));
255 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
256 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
257 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
258 u_int wreq, u_int hreq));
259 void CreateGrid P((void));
260 int EventToSquare P((int x, int limit));
261 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
262 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
263 void HandleUserMove P((Widget w, XEvent *event,
264 String *prms, Cardinal *nprms));
265 void AnimateUserMove P((Widget w, XEvent * event,
266 String * params, Cardinal * nParams));
267 void HandlePV P((Widget w, XEvent * event,
268 String * params, Cardinal * nParams));
269 void SelectPV P((Widget w, XEvent * event,
270 String * params, Cardinal * nParams));
271 void StopPV P((Widget w, XEvent * event,
272 String * params, Cardinal * nParams));
273 void WhiteClock P((Widget w, XEvent *event,
274 String *prms, Cardinal *nprms));
275 void BlackClock P((Widget w, XEvent *event,
276 String *prms, Cardinal *nprms));
277 void DrawPositionProc P((Widget w, XEvent *event,
278 String *prms, Cardinal *nprms));
279 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
281 void CommentClick P((Widget w, XEvent * event,
282 String * params, Cardinal * nParams));
283 void CommentPopUp P((char *title, char *label));
284 void CommentPopDown P((void));
285 void CommentCallback P((Widget w, XtPointer client_data,
286 XtPointer call_data));
287 void ICSInputBoxPopUp P((void));
288 void ICSInputBoxPopDown P((void));
289 void FileNamePopUp P((char *label, char *def,
290 FileProc proc, char *openMode));
291 void FileNamePopDown P((void));
292 void FileNameCallback P((Widget w, XtPointer client_data,
293 XtPointer call_data));
294 void FileNameAction P((Widget w, XEvent *event,
295 String *prms, Cardinal *nprms));
296 void AskQuestionReplyAction P((Widget w, XEvent *event,
297 String *prms, Cardinal *nprms));
298 void AskQuestionProc P((Widget w, XEvent *event,
299 String *prms, Cardinal *nprms));
300 void AskQuestionPopDown P((void));
301 void PromotionPopDown P((void));
302 void PromotionCallback P((Widget w, XtPointer client_data,
303 XtPointer call_data));
304 void EditCommentPopDown P((void));
305 void EditCommentCallback P((Widget w, XtPointer client_data,
306 XtPointer call_data));
307 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
308 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
309 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
310 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
312 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
314 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
316 void LoadPositionProc P((Widget w, XEvent *event,
317 String *prms, Cardinal *nprms));
318 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
320 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
322 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
324 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
326 void PastePositionProc P((Widget w, XEvent *event, String *prms,
328 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
329 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
330 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
331 void SavePositionProc P((Widget w, XEvent *event,
332 String *prms, Cardinal *nprms));
333 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
334 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
336 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
337 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
338 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
340 void MachineWhiteProc P((Widget w, XEvent *event,
341 String *prms, Cardinal *nprms));
342 void AnalyzeModeProc P((Widget w, XEvent *event,
343 String *prms, Cardinal *nprms));
344 void AnalyzeFileProc P((Widget w, XEvent *event,
345 String *prms, Cardinal *nprms));
346 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
348 void IcsClientProc P((Widget w, XEvent *event, String *prms,
350 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
351 void EditPositionProc P((Widget w, XEvent *event,
352 String *prms, Cardinal *nprms));
353 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
354 void EditCommentProc P((Widget w, XEvent *event,
355 String *prms, Cardinal *nprms));
356 void IcsInputBoxProc P((Widget w, XEvent *event,
357 String *prms, Cardinal *nprms));
358 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
365 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
370 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
371 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
372 void StopObservingProc P((Widget w, XEvent *event, String *prms,
374 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
376 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
377 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
379 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
380 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
385 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
387 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
388 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
390 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
392 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
394 void AutocommProc P((Widget w, XEvent *event, String *prms,
396 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
397 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
398 void AutobsProc P((Widget w, XEvent *event, String *prms,
400 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
401 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
402 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
403 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
405 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
406 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
408 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
410 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
412 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
413 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
414 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
416 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
418 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
420 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
422 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
424 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
425 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
426 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
428 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
430 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
432 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
434 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
435 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
436 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
442 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
443 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
444 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
445 void DisplayMove P((int moveNumber));
446 void DisplayTitle P((char *title));
447 void ICSInitScript P((void));
448 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
449 void ErrorPopUp P((char *title, char *text, int modal));
450 void ErrorPopDown P((void));
451 static char *ExpandPathName P((char *path));
452 static void CreateAnimVars P((void));
453 static void DragPieceMove P((int x, int y));
454 static void DrawDragPiece P((void));
455 char *ModeToWidgetName P((GameMode mode));
456 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
457 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
458 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
459 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
460 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
461 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
462 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
463 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
464 void GameListOptionsPopDown P(());
465 void ShufflePopDown P(());
466 void EnginePopDown P(());
467 void UciPopDown P(());
468 void TimeControlPopDown P(());
469 void NewVariantPopDown P(());
470 void SettingsPopDown P(());
471 void update_ics_width P(());
472 int get_term_width P(());
473 int CopyMemoProc P(());
475 * XBoard depends on Xt R4 or higher
477 int xtVersion = XtSpecificationRelease;
482 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
483 jailSquareColor, highlightSquareColor, premoveHighlightColor;
484 Pixel lowTimeWarningColor;
485 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
486 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
487 wjPieceGC, bjPieceGC, prelineGC, countGC;
488 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
489 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
490 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
491 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
492 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
493 ICSInputShell, fileNameShell, askQuestionShell;
494 Widget historyShell, evalGraphShell, gameListShell;
495 int hOffset; // [HGM] dual
496 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
497 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
498 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
499 Font clockFontID, coordFontID, countFontID;
500 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
501 XtAppContext appContext;
503 char *oldICSInteractionTitle;
507 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
509 Position commentX = -1, commentY = -1;
510 Dimension commentW, commentH;
511 typedef unsigned int BoardSize;
513 Boolean chessProgram;
515 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
516 int squareSize, smallLayout = 0, tinyLayout = 0,
517 marginW, marginH, // [HGM] for run-time resizing
518 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
519 ICSInputBoxUp = False, askQuestionUp = False,
520 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
521 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
522 Pixel timerForegroundPixel, timerBackgroundPixel;
523 Pixel buttonForegroundPixel, buttonBackgroundPixel;
524 char *chessDir, *programName, *programVersion,
525 *gameCopyFilename, *gamePasteFilename;
526 Boolean alwaysOnTop = False;
527 Boolean saveSettingsOnExit;
528 char *settingsFileName;
529 char *icsTextMenuString;
531 char *firstChessProgramNames;
532 char *secondChessProgramNames;
534 WindowPlacement wpMain;
535 WindowPlacement wpConsole;
536 WindowPlacement wpComment;
537 WindowPlacement wpMoveHistory;
538 WindowPlacement wpEvalGraph;
539 WindowPlacement wpEngineOutput;
540 WindowPlacement wpGameList;
541 WindowPlacement wpTags;
545 Pixmap pieceBitmap[2][(int)BlackPawn];
546 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
547 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
548 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
549 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
550 Pixmap xpmBoardBitmap[2];
551 int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
552 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
553 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
554 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
555 XImage *ximLightSquare, *ximDarkSquare;
558 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
559 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
561 #define White(piece) ((int)(piece) < (int)BlackPawn)
563 /* Variables for doing smooth animation. This whole thing
564 would be much easier if the board was double-buffered,
565 but that would require a fairly major rewrite. */
570 GC blitGC, pieceGC, outlineGC;
571 XPoint startSquare, prevFrame, mouseDelta;
575 int startBoardX, startBoardY;
578 /* There can be two pieces being animated at once: a player
579 can begin dragging a piece before the remote opponent has moved. */
581 static AnimState game, player;
583 /* Bitmaps for use as masks when drawing XPM pieces.
584 Need one for each black and white piece. */
585 static Pixmap xpmMask[BlackKing + 1];
587 /* This magic number is the number of intermediate frames used
588 in each half of the animation. For short moves it's reduced
589 by 1. The total number of frames will be factor * 2 + 1. */
592 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
594 MenuItem fileMenu[] = {
595 {N_("New Game Ctrl+N"), "New Game", ResetProc},
596 {N_("New Shuffle Game ..."), "New Shuffle Game", ShuffleMenuProc},
597 {N_("New Variant ... Alt+Shift+V"), "New Variant", NewVariantProc}, // [HGM] variant: not functional yet
598 {"----", NULL, NothingProc},
599 {N_("Load Game Ctrl+O"), "Load Game", LoadGameProc},
600 {N_("Load Position Ctrl+Shift+O"), "Load Position", LoadPositionProc},
601 // {N_("Load Next Game"), "Load Next Game", LoadNextGameProc},
602 // {N_("Load Previous Game"), "Load Previous Game", LoadPrevGameProc},
603 // {N_("Reload Same Game"), "Reload Same Game", ReloadGameProc},
604 {"----", NULL, NothingProc},
605 // {N_("Load Next Position"), "Load Next Position", LoadNextPositionProc},
606 // {N_("Load Previous Position"), "Load Previous Position", LoadPrevPositionProc},
607 // {N_("Reload Same Position"), "Reload Same Position", ReloadPositionProc},
608 {N_("Save Game Ctrl+S"), "Save Game", SaveGameProc},
609 {N_("Save Position Ctrl+Shift+S"), "Save Position", SavePositionProc},
610 {"----", NULL, NothingProc},
611 {N_("Mail Move"), "Mail Move", MailMoveProc},
612 {N_("Reload CMail Message"), "Reload CMail Message", ReloadCmailMsgProc},
613 {"----", NULL, NothingProc},
614 {N_("Quit Ctr+Q"), "Exit", QuitProc},
618 MenuItem editMenu[] = {
619 {N_("Copy Game Ctrl+C"), "Copy Game", CopyGameProc},
620 {N_("Copy Position Ctrl+Shift+C"), "Copy Position", CopyPositionProc},
621 {"----", NULL, NothingProc},
622 {N_("Paste Game Ctrl+V"), "Paste Game", PasteGameProc},
623 {N_("Paste Position Ctrl+Shift+V"), "Paste Position", PastePositionProc},
624 {"----", NULL, NothingProc},
625 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
626 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
627 {N_("Edit Tags"), "Edit Tags", EditTagsProc},
628 {N_("Edit Comment"), "Edit Comment", EditCommentProc},
629 {"----", NULL, NothingProc},
630 {N_("Revert Home"), "Revert", RevertProc},
631 {N_("Annotate"), "Annotate", AnnotateProc},
632 {N_("Truncate Game End"), "Truncate Game", TruncateGameProc},
633 {"----", NULL, NothingProc},
634 {N_("Backward Alt+Left"), "Backward", BackwardProc},
635 {N_("Forward Alt+Right"), "Forward", ForwardProc},
636 {N_("Back to Start Alt+Home"), "Back to Start", ToStartProc},
637 {N_("Forward to End Alt+End"), "Forward to End", ToEndProc},
641 MenuItem viewMenu[] = {
642 {N_("Flip View F2"), "Flip View", FlipViewProc},
643 {"----", NULL, NothingProc},
644 {N_("Engine Output Alt+Shift+O"), "Show Engine Output", EngineOutputProc},
645 {N_("Move History Alt+Shift+H"), "Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
646 {N_("Evaluation Graph Alt+Shift+E"), "Show Evaluation Graph", EvalGraphProc},
647 {N_("Game List Alt+Shift+G"), "Show Game List", ShowGameListProc},
648 {"----", NULL, NothingProc},
649 {N_("Tags"), "Show Tags", EditTagsProc},
650 {N_("Comments"), "Show Comments", EditCommentProc},
651 {N_("ICS Input Box"), "ICS Input Box", IcsInputBoxProc},
655 MenuItem modeMenu[] = {
656 {N_("Machine White Ctrl+W"), "Machine White", MachineWhiteProc},
657 {N_("Machine Black Ctrl+B"), "Machine Black", MachineBlackProc},
658 {N_("Two Machines Ctrl+T"), "Two Machines", TwoMachinesProc},
659 {N_("Analysis Mode Ctrl+A"), "Analysis Mode", AnalyzeModeProc},
660 {N_("Analyze File Ctrl+F"), "Analyze File", AnalyzeFileProc },
661 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
662 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
663 {N_("Training"), "Training", TrainingProc},
664 {N_("ICS Client"), "ICS Client", IcsClientProc},
665 {"----", NULL, NothingProc},
666 {N_("Pause Pause"), "Pause", PauseProc},
670 MenuItem actionMenu[] = {
671 {N_("Accept F3"), "Accept", AcceptProc},
672 {N_("Decline F4"), "Decline", DeclineProc},
673 {N_("Rematch F12"), "Rematch", RematchProc},
674 {"----", NULL, NothingProc},
675 {N_("Call Flag F5"), "Call Flag", CallFlagProc},
676 {N_("Draw F6"), "Draw", DrawProc},
677 {N_("Adjourn F7"), "Adjourn", AdjournProc},
678 {N_("Abort F8"),"Abort", AbortProc},
679 {N_("Resign F9"), "Resign", ResignProc},
680 {"----", NULL, NothingProc},
681 {N_("Stop Observing F10"), "Stop Observing", StopObservingProc},
682 {N_("Stop Examining F11"), "Stop Examining", StopExaminingProc},
683 {N_("Upload to Examine"), "Upload to Examine", UploadProc},
684 {"----", NULL, NothingProc},
685 {N_("Adjudicate to White"), "Adjudicate to White", AdjuWhiteProc},
686 {N_("Adjudicate to Black"), "Adjudicate to Black", AdjuBlackProc},
687 {N_("Adjudicate Draw"), "Adjudicate Draw", AdjuDrawProc},
691 MenuItem engineMenu[] = {
692 {N_("Engine #1 Settings ..."), "Engine #1 Settings", FirstSettingsProc},
693 {N_("Engine #2 Settings ..."), "Engine #2 Settings", SecondSettingsProc},
694 {"----", NULL, NothingProc},
695 {N_("Hint"), "Hint", HintProc},
696 {N_("Book"), "Book", BookProc},
697 {"----", NULL, NothingProc},
698 {N_("Move Now Ctrl+M"), "Move Now", MoveNowProc},
699 {N_("Retract Move Ctrl+X"), "Retract Move", RetractMoveProc},
703 MenuItem optionsMenu[] = {
704 {N_("Time Control ... Alt+Shift+T"), "Time Control", TimeControlProc},
705 {N_("Common Engine ... Alt+Shift+U"), "Common Engine", UciMenuProc},
706 {N_("Adjudications ... Alt+Shift+J"), "Adjudications", EngineMenuProc},
707 {N_("Game List ..."), "Game List", GameListOptionsPopUp},
708 {"----", NULL, NothingProc},
709 {N_("Always Queen Ctrl+Shift+Q"), "Always Queen", AlwaysQueenProc},
710 {N_("Animate Dragging"), "Animate Dragging", AnimateDraggingProc},
711 {N_("Animate Moving Ctrl+Shift+A"), "Animate Moving", AnimateMovingProc},
712 {N_("Auto Comment"), "Auto Comment", AutocommProc},
713 {N_("Auto Flag Ctrl+Shift+F"), "Auto Flag", AutoflagProc},
714 {N_("Auto Flip View"), "Auto Flip View", AutoflipProc},
715 {N_("Auto Observe"), "Auto Observe", AutobsProc},
716 {N_("Auto Raise Board"), "Auto Raise Board", AutoraiseProc},
717 {N_("Auto Save"), "Auto Save", AutosaveProc},
718 {N_("Blindfold"), "Blindfold", BlindfoldProc},
719 {N_("Flash Moves"), "Flash Moves", FlashMovesProc},
720 {N_("Get Move List"), "Get Move List", GetMoveListProc},
722 {N_("Highlight Dragging"), "Highlight Dragging", HighlightDraggingProc},
724 {N_("Highlight Last Move"), "Highlight Last Move", HighlightLastMoveProc},
725 {N_("Move Sound"), "Move Sound", MoveSoundProc},
726 {N_("ICS Alarm"), "ICS Alarm", IcsAlarmProc},
727 {N_("Old Save Style"), "Old Save Style", OldSaveStyleProc},
728 {N_("Periodic Updates"), "Periodic Updates", PeriodicUpdatesProc},
729 {N_("Ponder Next Move Ctrl+Shift+P"), "Ponder Next Move", PonderNextMoveProc},
730 {N_("Popup Exit Message"), "Popup Exit Message", PopupExitMessageProc},
731 {N_("Popup Move Errors"), "Popup Move Errors", PopupMoveErrorsProc},
732 {N_("Premove"), "Premove", PremoveProc},
733 {N_("Quiet Play"), "Quiet Play", QuietPlayProc},
734 {N_("Show Coords"), "Show Coords", ShowCoordsProc},
735 {N_("Hide Thinking Ctrl+Shift+H"), "Hide Thinking", HideThinkingProc},
736 {N_("Test Legality Ctrl+Shift+L"), "Test Legality", TestLegalityProc},
737 {"----", NULL, NothingProc},
738 {N_("Save Settings Now"), "Save Settings Now", SaveSettingsProc},
739 {N_("Save Settings on Exit"), "Save Settings on Exit", SaveOnExitProc},
743 MenuItem helpMenu[] = {
744 {N_("Info XBoard"), "Info XBoard", InfoProc},
745 {N_("Man XBoard F1"), "Man XBoard", ManProc},
746 {"----", NULL, NothingProc},
747 {N_("About XBoard"), "About XBoard", AboutProc},
752 {N_("File"), "File", fileMenu},
753 {N_("Edit"), "Edit", editMenu},
754 {N_("View"), "View", viewMenu},
755 {N_("Mode"), "Mode", modeMenu},
756 {N_("Action"), "Action", actionMenu},
757 {N_("Engine"), "Engine", engineMenu},
758 {N_("Options"), "Options", optionsMenu},
759 {N_("Help"), "Help", helpMenu},
763 #define PAUSE_BUTTON "P"
764 MenuItem buttonBar[] = {
765 {"<<", "<<", ToStartProc},
766 {"<", "<", BackwardProc},
767 {PAUSE_BUTTON, PAUSE_BUTTON, PauseProc},
768 {">", ">", ForwardProc},
769 {">>", ">>", ToEndProc},
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 :<Key>Home: RevertProc() \n \
1063 :<Key>End: TruncateGameProc() \n \
1064 :Ctrl<Key>m: MoveNowProc() \n \
1065 :Ctrl<Key>x: RetractMoveProc() \n \
1066 :Meta<Key>J: EngineMenuProc() \n \
1067 :Meta<Key>U: UciMenuProc() \n \
1068 :Meta<Key>T: TimeControlProc() \n \
1069 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1070 :Ctrl<Key>F: AutoflagProc() \n \
1071 :Ctrl<Key>A: AnimateMovingProc() \n \
1072 :Ctrl<Key>P: PonderNextMoveProc() \n \
1073 :Ctrl<Key>L: TestLegalityProc() \n \
1074 :Ctrl<Key>H: HideThinkingProc() \n \
1075 :<Key>-: Iconify() \n \
1076 :<Key>F1: ManProc() \n \
1077 :<Key>F2: FlipViewProc() \n \
1078 <KeyDown>.: BackwardProc() \n \
1079 <KeyUp>.: ForwardProc() \n \
1080 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1081 \"Send to chess program:\",,1) \n \
1082 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1083 \"Send to second chess program:\",,2) \n";
1085 char boardTranslations[] =
1086 "<Btn1Down>: HandleUserMove(0) \n \
1087 Shift<Btn1Up>: HandleUserMove(1) \n \
1088 <Btn1Up>: HandleUserMove(0) \n \
1089 <Btn1Motion>: AnimateUserMove() \n \
1090 <Btn3Motion>: HandlePV() \n \
1091 <Btn3Up>: PieceMenuPopup(menuB) \n \
1092 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1093 PieceMenuPopup(menuB) \n \
1094 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1095 PieceMenuPopup(menuW) \n \
1096 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1097 PieceMenuPopup(menuW) \n \
1098 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1099 PieceMenuPopup(menuB) \n";
1101 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1102 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1104 char ICSInputTranslations[] =
1105 "<Key>Up: UpKeyProc() \n "
1106 "<Key>Down: DownKeyProc() \n "
1107 "<Key>Return: EnterKeyProc() \n";
1109 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1110 // as the widget is destroyed before the up-click can call extend-end
1111 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1113 String xboardResources[] = {
1114 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1115 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1116 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1121 /* Max possible square size */
1122 #define MAXSQSIZE 256
1124 static int xpm_avail[MAXSQSIZE];
1126 #ifdef HAVE_DIR_STRUCT
1128 /* Extract piece size from filename */
1130 xpm_getsize(name, len, ext)
1141 if ((p=strchr(name, '.')) == NULL ||
1142 StrCaseCmp(p+1, ext) != 0)
1148 while (*p && isdigit(*p))
1155 /* Setup xpm_avail */
1157 xpm_getavail(dirname, ext)
1165 for (i=0; i<MAXSQSIZE; ++i)
1168 if (appData.debugMode)
1169 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1171 dir = opendir(dirname);
1174 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1175 programName, dirname);
1179 while ((ent=readdir(dir)) != NULL) {
1180 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1181 if (i > 0 && i < MAXSQSIZE)
1191 xpm_print_avail(fp, ext)
1197 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1198 for (i=1; i<MAXSQSIZE; ++i) {
1204 /* Return XPM piecesize closest to size */
1206 xpm_closest_to(dirname, size, ext)
1212 int sm_diff = MAXSQSIZE;
1216 xpm_getavail(dirname, ext);
1218 if (appData.debugMode)
1219 xpm_print_avail(stderr, ext);
1221 for (i=1; i<MAXSQSIZE; ++i) {
1224 diff = (diff<0) ? -diff : diff;
1225 if (diff < sm_diff) {
1233 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1239 #else /* !HAVE_DIR_STRUCT */
1240 /* If we are on a system without a DIR struct, we can't
1241 read the directory, so we can't collect a list of
1242 filenames, etc., so we can't do any size-fitting. */
1244 xpm_closest_to(dirname, size, ext)
1249 fprintf(stderr, _("\
1250 Warning: No DIR structure found on this system --\n\
1251 Unable to autosize for XPM/XIM pieces.\n\
1252 Please report this error to frankm@hiwaay.net.\n\
1253 Include system type & operating system in message.\n"));
1256 #endif /* HAVE_DIR_STRUCT */
1258 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1259 "magenta", "cyan", "white" };
1263 TextColors textColors[(int)NColorClasses];
1265 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1267 parse_color(str, which)
1271 char *p, buf[100], *d;
1274 if (strlen(str) > 99) /* watch bounds on buf */
1279 for (i=0; i<which; ++i) {
1286 /* Could be looking at something like:
1288 .. in which case we want to stop on a comma also */
1289 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1293 return -1; /* Use default for empty field */
1296 if (which == 2 || isdigit(*p))
1299 while (*p && isalpha(*p))
1304 for (i=0; i<8; ++i) {
1305 if (!StrCaseCmp(buf, cnames[i]))
1306 return which? (i+40) : (i+30);
1308 if (!StrCaseCmp(buf, "default")) return -1;
1310 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1315 parse_cpair(cc, str)
1319 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1320 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1325 /* bg and attr are optional */
1326 textColors[(int)cc].bg = parse_color(str, 1);
1327 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1328 textColors[(int)cc].attr = 0;
1334 /* Arrange to catch delete-window events */
1335 Atom wm_delete_window;
1337 CatchDeleteWindow(Widget w, String procname)
1340 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1341 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1342 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1349 XtSetArg(args[0], XtNiconic, False);
1350 XtSetValues(shellWidget, args, 1);
1352 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1355 //---------------------------------------------------------------------------------------------------------
1356 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1359 #define CW_USEDEFAULT (1<<31)
1360 #define ICS_TEXT_MENU_SIZE 90
1361 #define DEBUG_FILE "xboard.debug"
1362 #define SetCurrentDirectory chdir
1363 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1367 // these two must some day move to frontend.h, when they are implemented
1368 Boolean GameListIsUp();
1370 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1373 // front-end part of option handling
1375 // [HGM] This platform-dependent table provides the location for storing the color info
1376 extern char *crWhite, * crBlack;
1380 &appData.whitePieceColor,
1381 &appData.blackPieceColor,
1382 &appData.lightSquareColor,
1383 &appData.darkSquareColor,
1384 &appData.highlightSquareColor,
1385 &appData.premoveHighlightColor,
1386 &appData.lowTimeWarningColor,
1397 // [HGM] font: keep a font for each square size, even non-stndard ones
1398 #define NUM_SIZES 18
1399 #define MAX_SIZE 130
1400 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1401 char *fontTable[NUM_FONTS][MAX_SIZE];
1404 ParseFont(char *name, int number)
1405 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1407 if(sscanf(name, "size%d:", &size)) {
1408 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1409 // defer processing it until we know if it matches our board size
1410 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1411 fontTable[number][size] = strdup(strchr(name, ':')+1);
1412 fontValid[number][size] = True;
1417 case 0: // CLOCK_FONT
1418 appData.clockFont = strdup(name);
1420 case 1: // MESSAGE_FONT
1421 appData.font = strdup(name);
1423 case 2: // COORD_FONT
1424 appData.coordFont = strdup(name);
1429 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1434 { // only 2 fonts currently
1435 appData.clockFont = CLOCK_FONT_NAME;
1436 appData.coordFont = COORD_FONT_NAME;
1437 appData.font = DEFAULT_FONT_NAME;
1442 { // no-op, until we identify the code for this already in XBoard and move it here
1446 ParseColor(int n, char *name)
1447 { // in XBoard, just copy the color-name string
1448 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1452 ParseTextAttribs(ColorClass cc, char *s)
1454 (&appData.colorShout)[cc] = strdup(s);
1458 ParseBoardSize(void *addr, char *name)
1460 appData.boardSize = strdup(name);
1465 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1469 SetCommPortDefaults()
1470 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1473 // [HGM] args: these three cases taken out to stay in front-end
1475 SaveFontArg(FILE *f, ArgDescriptor *ad)
1478 int i, n = (int)ad->argLoc;
1480 case 0: // CLOCK_FONT
1481 name = appData.clockFont;
1483 case 1: // MESSAGE_FONT
1484 name = appData.font;
1486 case 2: // COORD_FONT
1487 name = appData.coordFont;
1492 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1493 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1494 fontTable[n][squareSize] = strdup(name);
1495 fontValid[n][squareSize] = True;
1498 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1499 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1504 { // nothing to do, as the sounds are at all times represented by their text-string names already
1508 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1509 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1510 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1514 SaveColor(FILE *f, ArgDescriptor *ad)
1515 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1516 if(colorVariable[(int)ad->argLoc])
1517 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1521 SaveBoardSize(FILE *f, char *name, void *addr)
1522 { // wrapper to shield back-end from BoardSize & sizeInfo
1523 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1527 ParseCommPortSettings(char *s)
1528 { // no such option in XBoard (yet)
1531 extern Widget engineOutputShell;
1532 extern Widget tagsShell, editTagsShell;
1534 GetActualPlacement(Widget wg, WindowPlacement *wp)
1544 XtSetArg(args[i], XtNx, &x); i++;
1545 XtSetArg(args[i], XtNy, &y); i++;
1546 XtSetArg(args[i], XtNwidth, &w); i++;
1547 XtSetArg(args[i], XtNheight, &h); i++;
1548 XtGetValues(wg, args, i);
1557 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1558 // In XBoard this will have to wait until awareness of window parameters is implemented
1559 GetActualPlacement(shellWidget, &wpMain);
1560 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1561 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1562 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1563 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1564 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1565 else GetActualPlacement(editShell, &wpComment);
1566 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1567 else GetActualPlacement(editTagsShell, &wpTags);
1571 PrintCommPortSettings(FILE *f, char *name)
1572 { // This option does not exist in XBoard
1576 MySearchPath(char *installDir, char *name, char *fullname)
1577 { // just append installDir and name. Perhaps ExpandPath should be used here?
1578 name = ExpandPathName(name);
1579 if(name && name[0] == '/')
1580 safeStrCpy(fullname, name, MSG_SIZ );
1582 sprintf(fullname, "%s%c%s", installDir, '/', name);
1588 MyGetFullPathName(char *name, char *fullname)
1589 { // should use ExpandPath?
1590 name = ExpandPathName(name);
1591 safeStrCpy(fullname, name, MSG_SIZ );
1596 EnsureOnScreen(int *x, int *y, int minX, int minY)
1603 { // [HGM] args: allows testing if main window is realized from back-end
1604 return xBoardWindow != 0;
1608 PopUpStartupDialog()
1609 { // start menu not implemented in XBoard
1613 ConvertToLine(int argc, char **argv)
1615 static char line[128*1024], buf[1024];
1619 for(i=1; i<argc; i++)
1621 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1622 && argv[i][0] != '{' )
1623 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1625 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1626 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1629 line[strlen(line)-1] = NULLCHAR;
1633 //--------------------------------------------------------------------------------------------
1635 extern Boolean twoBoards, partnerUp;
1638 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1640 #define BoardSize int
1641 void InitDrawingSizes(BoardSize boardSize, int flags)
1642 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1643 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1645 XtGeometryResult gres;
1648 if(!formWidget) return;
1651 * Enable shell resizing.
1653 shellArgs[0].value = (XtArgVal) &w;
1654 shellArgs[1].value = (XtArgVal) &h;
1655 XtGetValues(shellWidget, shellArgs, 2);
1657 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1658 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1659 XtSetValues(shellWidget, &shellArgs[2], 4);
1661 XtSetArg(args[0], XtNdefaultDistance, &sep);
1662 XtGetValues(formWidget, args, 1);
1664 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1665 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1667 hOffset = boardWidth + 10;
1668 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1669 secondSegments[i] = gridSegments[i];
1670 secondSegments[i].x1 += hOffset;
1671 secondSegments[i].x2 += hOffset;
1674 XtSetArg(args[0], XtNwidth, boardWidth);
1675 XtSetArg(args[1], XtNheight, boardHeight);
1676 XtSetValues(boardWidget, args, 2);
1678 timerWidth = (boardWidth - sep) / 2;
1679 XtSetArg(args[0], XtNwidth, timerWidth);
1680 XtSetValues(whiteTimerWidget, args, 1);
1681 XtSetValues(blackTimerWidget, args, 1);
1683 XawFormDoLayout(formWidget, False);
1685 if (appData.titleInWindow) {
1687 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1688 XtSetArg(args[i], XtNheight, &h); i++;
1689 XtGetValues(titleWidget, args, i);
1691 w = boardWidth - 2*bor;
1693 XtSetArg(args[0], XtNwidth, &w);
1694 XtGetValues(menuBarWidget, args, 1);
1695 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1698 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1699 if (gres != XtGeometryYes && appData.debugMode) {
1701 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1702 programName, gres, w, h, wr, hr);
1706 XawFormDoLayout(formWidget, True);
1709 * Inhibit shell resizing.
1711 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1712 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1713 shellArgs[4].value = shellArgs[2].value = w;
1714 shellArgs[5].value = shellArgs[3].value = h;
1715 XtSetValues(shellWidget, &shellArgs[0], 6);
1717 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1720 for(i=0; i<4; i++) {
1722 for(p=0; p<=(int)WhiteKing; p++)
1723 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1724 if(gameInfo.variant == VariantShogi) {
1725 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1726 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1727 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1728 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1729 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1732 if(gameInfo.variant == VariantGothic) {
1733 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1736 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1737 xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
1738 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1741 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1742 for(p=0; p<=(int)WhiteKing; p++)
1743 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1744 if(gameInfo.variant == VariantShogi) {
1745 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1746 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1747 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1748 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1749 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1752 if(gameInfo.variant == VariantGothic) {
1753 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1756 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1757 ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
1758 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1763 for(i=0; i<2; i++) {
1765 for(p=0; p<=(int)WhiteKing; p++)
1766 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1767 if(gameInfo.variant == VariantShogi) {
1768 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1769 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1770 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1771 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1772 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1775 if(gameInfo.variant == VariantGothic) {
1776 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1779 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1780 pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
1781 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1796 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1797 XSetWindowAttributes window_attributes;
1799 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1800 XrmValue vFrom, vTo;
1801 XtGeometryResult gres;
1804 int forceMono = False;
1806 srandom(time(0)); // [HGM] book: make random truly random
1808 setbuf(stdout, NULL);
1809 setbuf(stderr, NULL);
1812 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1813 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1817 programName = strrchr(argv[0], '/');
1818 if (programName == NULL)
1819 programName = argv[0];
1824 XtSetLanguageProc(NULL, NULL, NULL);
1825 bindtextdomain(PACKAGE, LOCALEDIR);
1826 textdomain(PACKAGE);
1830 XtAppInitialize(&appContext, "XBoard", shellOptions,
1831 XtNumber(shellOptions),
1832 &argc, argv, xboardResources, NULL, 0);
1833 appData.boardSize = "";
1834 InitAppData(ConvertToLine(argc, argv));
1836 if (p == NULL) p = "/tmp";
1837 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1838 gameCopyFilename = (char*) malloc(i);
1839 gamePasteFilename = (char*) malloc(i);
1840 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1841 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1843 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1844 clientResources, XtNumber(clientResources),
1847 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1848 static char buf[MSG_SIZ];
1849 EscapeExpand(buf, appData.initString);
1850 appData.initString = strdup(buf);
1851 EscapeExpand(buf, appData.secondInitString);
1852 appData.secondInitString = strdup(buf);
1853 EscapeExpand(buf, appData.firstComputerString);
1854 appData.firstComputerString = strdup(buf);
1855 EscapeExpand(buf, appData.secondComputerString);
1856 appData.secondComputerString = strdup(buf);
1859 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1862 if (chdir(chessDir) != 0) {
1863 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1869 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1870 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1871 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1872 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1875 setbuf(debugFP, NULL);
1878 /* [HGM,HR] make sure board size is acceptable */
1879 if(appData.NrFiles > BOARD_FILES ||
1880 appData.NrRanks > BOARD_RANKS )
1881 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1884 /* This feature does not work; animation needs a rewrite */
1885 appData.highlightDragging = FALSE;
1889 xDisplay = XtDisplay(shellWidget);
1890 xScreen = DefaultScreen(xDisplay);
1891 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1893 gameInfo.variant = StringToVariant(appData.variant);
1894 InitPosition(FALSE);
1897 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1899 if (isdigit(appData.boardSize[0])) {
1900 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1901 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1902 &fontPxlSize, &smallLayout, &tinyLayout);
1904 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1905 programName, appData.boardSize);
1909 /* Find some defaults; use the nearest known size */
1910 SizeDefaults *szd, *nearest;
1911 int distance = 99999;
1912 nearest = szd = sizeDefaults;
1913 while (szd->name != NULL) {
1914 if (abs(szd->squareSize - squareSize) < distance) {
1916 distance = abs(szd->squareSize - squareSize);
1917 if (distance == 0) break;
1921 if (i < 2) lineGap = nearest->lineGap;
1922 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1923 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1924 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1925 if (i < 6) smallLayout = nearest->smallLayout;
1926 if (i < 7) tinyLayout = nearest->tinyLayout;
1929 SizeDefaults *szd = sizeDefaults;
1930 if (*appData.boardSize == NULLCHAR) {
1931 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1932 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1935 if (szd->name == NULL) szd--;
1936 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1938 while (szd->name != NULL &&
1939 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1940 if (szd->name == NULL) {
1941 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1942 programName, appData.boardSize);
1946 squareSize = szd->squareSize;
1947 lineGap = szd->lineGap;
1948 clockFontPxlSize = szd->clockFontPxlSize;
1949 coordFontPxlSize = szd->coordFontPxlSize;
1950 fontPxlSize = szd->fontPxlSize;
1951 smallLayout = szd->smallLayout;
1952 tinyLayout = szd->tinyLayout;
1953 // [HGM] font: use defaults from settings file if available and not overruled
1955 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
1956 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
1957 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
1958 appData.font = fontTable[MESSAGE_FONT][squareSize];
1959 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
1960 appData.coordFont = fontTable[COORD_FONT][squareSize];
1962 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1963 if (strlen(appData.pixmapDirectory) > 0) {
1964 p = ExpandPathName(appData.pixmapDirectory);
1966 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1967 appData.pixmapDirectory);
1970 if (appData.debugMode) {
1971 fprintf(stderr, _("\
1972 XBoard square size (hint): %d\n\
1973 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1975 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1976 if (appData.debugMode) {
1977 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1980 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1982 /* [HR] height treated separately (hacked) */
1983 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1984 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1985 if (appData.showJail == 1) {
1986 /* Jail on top and bottom */
1987 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1988 XtSetArg(boardArgs[2], XtNheight,
1989 boardHeight + 2*(lineGap + squareSize));
1990 } else if (appData.showJail == 2) {
1992 XtSetArg(boardArgs[1], XtNwidth,
1993 boardWidth + 2*(lineGap + squareSize));
1994 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1997 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1998 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2002 * Determine what fonts to use.
2004 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2005 clockFontID = XLoadFont(xDisplay, appData.clockFont);
2006 clockFontStruct = XQueryFont(xDisplay, clockFontID);
2007 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2008 coordFontID = XLoadFont(xDisplay, appData.coordFont);
2009 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2010 appData.font = FindFont(appData.font, fontPxlSize);
2011 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
2012 countFontStruct = XQueryFont(xDisplay, countFontID);
2013 // appData.font = FindFont(appData.font, fontPxlSize);
2015 xdb = XtDatabase(xDisplay);
2016 XrmPutStringResource(&xdb, "*font", appData.font);
2019 * Detect if there are not enough colors available and adapt.
2021 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2022 appData.monoMode = True;
2025 if (!appData.monoMode) {
2026 vFrom.addr = (caddr_t) appData.lightSquareColor;
2027 vFrom.size = strlen(appData.lightSquareColor);
2028 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2029 if (vTo.addr == NULL) {
2030 appData.monoMode = True;
2033 lightSquareColor = *(Pixel *) vTo.addr;
2036 if (!appData.monoMode) {
2037 vFrom.addr = (caddr_t) appData.darkSquareColor;
2038 vFrom.size = strlen(appData.darkSquareColor);
2039 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2040 if (vTo.addr == NULL) {
2041 appData.monoMode = True;
2044 darkSquareColor = *(Pixel *) vTo.addr;
2047 if (!appData.monoMode) {
2048 vFrom.addr = (caddr_t) appData.whitePieceColor;
2049 vFrom.size = strlen(appData.whitePieceColor);
2050 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2051 if (vTo.addr == NULL) {
2052 appData.monoMode = True;
2055 whitePieceColor = *(Pixel *) vTo.addr;
2058 if (!appData.monoMode) {
2059 vFrom.addr = (caddr_t) appData.blackPieceColor;
2060 vFrom.size = strlen(appData.blackPieceColor);
2061 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2062 if (vTo.addr == NULL) {
2063 appData.monoMode = True;
2066 blackPieceColor = *(Pixel *) vTo.addr;
2070 if (!appData.monoMode) {
2071 vFrom.addr = (caddr_t) appData.highlightSquareColor;
2072 vFrom.size = strlen(appData.highlightSquareColor);
2073 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2074 if (vTo.addr == NULL) {
2075 appData.monoMode = True;
2078 highlightSquareColor = *(Pixel *) vTo.addr;
2082 if (!appData.monoMode) {
2083 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
2084 vFrom.size = strlen(appData.premoveHighlightColor);
2085 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2086 if (vTo.addr == NULL) {
2087 appData.monoMode = True;
2090 premoveHighlightColor = *(Pixel *) vTo.addr;
2095 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2098 if (appData.bitmapDirectory == NULL ||
2099 appData.bitmapDirectory[0] == NULLCHAR)
2100 appData.bitmapDirectory = DEF_BITMAP_DIR;
2103 if (appData.lowTimeWarning && !appData.monoMode) {
2104 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2105 vFrom.size = strlen(appData.lowTimeWarningColor);
2106 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2107 if (vTo.addr == NULL)
2108 appData.monoMode = True;
2110 lowTimeWarningColor = *(Pixel *) vTo.addr;
2113 if (appData.monoMode && appData.debugMode) {
2114 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2115 (unsigned long) XWhitePixel(xDisplay, xScreen),
2116 (unsigned long) XBlackPixel(xDisplay, xScreen));
2119 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2120 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2121 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2122 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2123 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2124 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2125 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2126 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2127 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2128 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2130 if (appData.colorize) {
2132 _("%s: can't parse color names; disabling colorization\n"),
2135 appData.colorize = FALSE;
2137 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2138 textColors[ColorNone].attr = 0;
2140 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2146 layoutName = "tinyLayout";
2147 } else if (smallLayout) {
2148 layoutName = "smallLayout";
2150 layoutName = "normalLayout";
2152 /* Outer layoutWidget is there only to provide a name for use in
2153 resources that depend on the layout style */
2155 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2156 layoutArgs, XtNumber(layoutArgs));
2158 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2159 formArgs, XtNumber(formArgs));
2160 XtSetArg(args[0], XtNdefaultDistance, &sep);
2161 XtGetValues(formWidget, args, 1);
2164 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2165 XtSetArg(args[0], XtNtop, XtChainTop);
2166 XtSetArg(args[1], XtNbottom, XtChainTop);
2167 XtSetArg(args[2], XtNright, XtChainLeft);
2168 XtSetValues(menuBarWidget, args, 3);
2170 widgetList[j++] = whiteTimerWidget =
2171 XtCreateWidget("whiteTime", 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(whiteTimerWidget, args, 3);
2178 widgetList[j++] = blackTimerWidget =
2179 XtCreateWidget("blackTime", labelWidgetClass,
2180 formWidget, timerArgs, XtNumber(timerArgs));
2181 XtSetArg(args[0], XtNfont, clockFontStruct);
2182 XtSetArg(args[1], XtNtop, XtChainTop);
2183 XtSetArg(args[2], XtNbottom, XtChainTop);
2184 XtSetValues(blackTimerWidget, args, 3);
2186 if (appData.titleInWindow) {
2187 widgetList[j++] = titleWidget =
2188 XtCreateWidget("title", labelWidgetClass, formWidget,
2189 titleArgs, XtNumber(titleArgs));
2190 XtSetArg(args[0], XtNtop, XtChainTop);
2191 XtSetArg(args[1], XtNbottom, XtChainTop);
2192 XtSetValues(titleWidget, args, 2);
2195 if (appData.showButtonBar) {
2196 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2197 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2198 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2199 XtSetArg(args[2], XtNtop, XtChainTop);
2200 XtSetArg(args[3], XtNbottom, XtChainTop);
2201 XtSetValues(buttonBarWidget, args, 4);
2204 widgetList[j++] = messageWidget =
2205 XtCreateWidget("message", labelWidgetClass, formWidget,
2206 messageArgs, XtNumber(messageArgs));
2207 XtSetArg(args[0], XtNtop, XtChainTop);
2208 XtSetArg(args[1], XtNbottom, XtChainTop);
2209 XtSetValues(messageWidget, args, 2);
2211 widgetList[j++] = boardWidget =
2212 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2213 XtNumber(boardArgs));
2215 XtManageChildren(widgetList, j);
2217 timerWidth = (boardWidth - sep) / 2;
2218 XtSetArg(args[0], XtNwidth, timerWidth);
2219 XtSetValues(whiteTimerWidget, args, 1);
2220 XtSetValues(blackTimerWidget, args, 1);
2222 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2223 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2224 XtGetValues(whiteTimerWidget, args, 2);
2226 if (appData.showButtonBar) {
2227 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2228 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2229 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2233 * formWidget uses these constraints but they are stored
2237 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2238 XtSetValues(menuBarWidget, args, i);
2239 if (appData.titleInWindow) {
2242 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2243 XtSetValues(whiteTimerWidget, args, i);
2245 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2246 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2247 XtSetValues(blackTimerWidget, args, i);
2249 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2250 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2251 XtSetValues(titleWidget, args, i);
2253 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2254 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2255 XtSetValues(messageWidget, args, i);
2256 if (appData.showButtonBar) {
2258 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2259 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2260 XtSetValues(buttonBarWidget, args, i);
2264 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2265 XtSetValues(whiteTimerWidget, args, i);
2267 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2268 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2269 XtSetValues(blackTimerWidget, args, i);
2271 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2272 XtSetValues(titleWidget, args, i);
2274 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2275 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2276 XtSetValues(messageWidget, args, i);
2277 if (appData.showButtonBar) {
2279 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2280 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2281 XtSetValues(buttonBarWidget, args, i);
2286 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2287 XtSetValues(whiteTimerWidget, args, i);
2289 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2290 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2291 XtSetValues(blackTimerWidget, args, i);
2293 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2294 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2295 XtSetValues(messageWidget, args, i);
2296 if (appData.showButtonBar) {
2298 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2299 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2300 XtSetValues(buttonBarWidget, args, i);
2304 XtSetArg(args[0], XtNfromVert, messageWidget);
2305 XtSetArg(args[1], XtNtop, XtChainTop);
2306 XtSetArg(args[2], XtNbottom, XtChainBottom);
2307 XtSetArg(args[3], XtNleft, XtChainLeft);
2308 XtSetArg(args[4], XtNright, XtChainRight);
2309 XtSetValues(boardWidget, args, 5);
2311 XtRealizeWidget(shellWidget);
2314 XtSetArg(args[0], XtNx, wpMain.x);
2315 XtSetArg(args[1], XtNy, wpMain.y);
2316 XtSetValues(shellWidget, args, 2);
2320 * Correct the width of the message and title widgets.
2321 * It is not known why some systems need the extra fudge term.
2322 * The value "2" is probably larger than needed.
2324 XawFormDoLayout(formWidget, False);
2326 #define WIDTH_FUDGE 2
2328 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2329 XtSetArg(args[i], XtNheight, &h); i++;
2330 XtGetValues(messageWidget, args, i);
2331 if (appData.showButtonBar) {
2333 XtSetArg(args[i], XtNwidth, &w); i++;
2334 XtGetValues(buttonBarWidget, args, i);
2335 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2337 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2340 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2341 if (gres != XtGeometryYes && appData.debugMode) {
2342 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2343 programName, gres, w, h, wr, hr);
2346 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2347 /* The size used for the child widget in layout lags one resize behind
2348 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2350 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2351 if (gres != XtGeometryYes && appData.debugMode) {
2352 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2353 programName, gres, w, h, wr, hr);
2356 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2357 XtSetArg(args[1], XtNright, XtChainRight);
2358 XtSetValues(messageWidget, args, 2);
2360 if (appData.titleInWindow) {
2362 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2363 XtSetArg(args[i], XtNheight, &h); i++;
2364 XtGetValues(titleWidget, args, i);
2366 w = boardWidth - 2*bor;
2368 XtSetArg(args[0], XtNwidth, &w);
2369 XtGetValues(menuBarWidget, args, 1);
2370 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2373 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2374 if (gres != XtGeometryYes && appData.debugMode) {
2376 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2377 programName, gres, w, h, wr, hr);
2380 XawFormDoLayout(formWidget, True);
2382 xBoardWindow = XtWindow(boardWidget);
2384 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2385 // not need to go into InitDrawingSizes().
2389 * Create X checkmark bitmap and initialize option menu checks.
2391 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2392 checkmark_bits, checkmark_width, checkmark_height);
2393 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2394 if (appData.alwaysPromoteToQueen) {
2395 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2398 if (appData.animateDragging) {
2399 XtSetValues(XtNameToWidget(menuBarWidget,
2400 "menuOptions.Animate Dragging"),
2403 if (appData.animate) {
2404 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2407 if (appData.autoComment) {
2408 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2411 if (appData.autoCallFlag) {
2412 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2415 if (appData.autoFlipView) {
2416 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2419 if (appData.autoObserve) {
2420 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2423 if (appData.autoRaiseBoard) {
2424 XtSetValues(XtNameToWidget(menuBarWidget,
2425 "menuOptions.Auto Raise Board"), args, 1);
2427 if (appData.autoSaveGames) {
2428 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2431 if (appData.saveGameFile[0] != NULLCHAR) {
2432 /* Can't turn this off from menu */
2433 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2435 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2439 if (appData.blindfold) {
2440 XtSetValues(XtNameToWidget(menuBarWidget,
2441 "menuOptions.Blindfold"), args, 1);
2443 if (appData.flashCount > 0) {
2444 XtSetValues(XtNameToWidget(menuBarWidget,
2445 "menuOptions.Flash Moves"),
2448 if (appData.getMoveList) {
2449 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2453 if (appData.highlightDragging) {
2454 XtSetValues(XtNameToWidget(menuBarWidget,
2455 "menuOptions.Highlight Dragging"),
2459 if (appData.highlightLastMove) {
2460 XtSetValues(XtNameToWidget(menuBarWidget,
2461 "menuOptions.Highlight Last Move"),
2464 if (appData.icsAlarm) {
2465 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2468 if (appData.ringBellAfterMoves) {
2469 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2472 if (appData.oldSaveStyle) {
2473 XtSetValues(XtNameToWidget(menuBarWidget,
2474 "menuOptions.Old Save Style"), args, 1);
2476 if (appData.periodicUpdates) {
2477 XtSetValues(XtNameToWidget(menuBarWidget,
2478 "menuOptions.Periodic Updates"), args, 1);
2480 if (appData.ponderNextMove) {
2481 XtSetValues(XtNameToWidget(menuBarWidget,
2482 "menuOptions.Ponder Next Move"), args, 1);
2484 if (appData.popupExitMessage) {
2485 XtSetValues(XtNameToWidget(menuBarWidget,
2486 "menuOptions.Popup Exit Message"), args, 1);
2488 if (appData.popupMoveErrors) {
2489 XtSetValues(XtNameToWidget(menuBarWidget,
2490 "menuOptions.Popup Move Errors"), args, 1);
2492 if (appData.premove) {
2493 XtSetValues(XtNameToWidget(menuBarWidget,
2494 "menuOptions.Premove"), args, 1);
2496 if (appData.quietPlay) {
2497 XtSetValues(XtNameToWidget(menuBarWidget,
2498 "menuOptions.Quiet Play"), args, 1);
2500 if (appData.showCoords) {
2501 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2504 if (appData.hideThinkingFromHuman) {
2505 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2508 if (appData.testLegality) {
2509 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2512 if (saveSettingsOnExit) {
2513 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2520 ReadBitmap(&wIconPixmap, "icon_white.bm",
2521 icon_white_bits, icon_white_width, icon_white_height);
2522 ReadBitmap(&bIconPixmap, "icon_black.bm",
2523 icon_black_bits, icon_black_width, icon_black_height);
2524 iconPixmap = wIconPixmap;
2526 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2527 XtSetValues(shellWidget, args, i);
2530 * Create a cursor for the board widget.
2532 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2533 XChangeWindowAttributes(xDisplay, xBoardWindow,
2534 CWCursor, &window_attributes);
2537 * Inhibit shell resizing.
2539 shellArgs[0].value = (XtArgVal) &w;
2540 shellArgs[1].value = (XtArgVal) &h;
2541 XtGetValues(shellWidget, shellArgs, 2);
2542 shellArgs[4].value = shellArgs[2].value = w;
2543 shellArgs[5].value = shellArgs[3].value = h;
2544 XtSetValues(shellWidget, &shellArgs[2], 4);
2545 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2546 marginH = h - boardHeight;
2548 CatchDeleteWindow(shellWidget, "QuitProc");
2553 if (appData.bitmapDirectory[0] != NULLCHAR) {
2557 CreateXPMBoard(appData.liteBackTextureFile, 1);
2558 CreateXPMBoard(appData.darkBackTextureFile, 0);
2562 /* Create regular pieces */
2563 if (!useImages) CreatePieces();
2568 if (appData.animate || appData.animateDragging)
2571 XtAugmentTranslations(formWidget,
2572 XtParseTranslationTable(globalTranslations));
2573 XtAugmentTranslations(boardWidget,
2574 XtParseTranslationTable(boardTranslations));
2575 XtAugmentTranslations(whiteTimerWidget,
2576 XtParseTranslationTable(whiteTranslations));
2577 XtAugmentTranslations(blackTimerWidget,
2578 XtParseTranslationTable(blackTranslations));
2580 /* Why is the following needed on some versions of X instead
2581 * of a translation? */
2582 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2583 (XtEventHandler) EventProc, NULL);
2586 /* [AS] Restore layout */
2587 if( wpMoveHistory.visible ) {
2591 if( wpEvalGraph.visible )
2596 if( wpEngineOutput.visible ) {
2597 EngineOutputPopUp();
2602 if (errorExitStatus == -1) {
2603 if (appData.icsActive) {
2604 /* We now wait until we see "login:" from the ICS before
2605 sending the logon script (problems with timestamp otherwise) */
2606 /*ICSInitScript();*/
2607 if (appData.icsInputBox) ICSInputBoxPopUp();
2611 signal(SIGWINCH, TermSizeSigHandler);
2613 signal(SIGINT, IntSigHandler);
2614 signal(SIGTERM, IntSigHandler);
2615 if (*appData.cmailGameName != NULLCHAR) {
2616 signal(SIGUSR1, CmailSigHandler);
2619 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2621 XtSetKeyboardFocus(shellWidget, formWidget);
2623 XtAppMainLoop(appContext);
2624 if (appData.debugMode) fclose(debugFP); // [DM] debug
2631 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2632 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2634 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2635 unlink(gameCopyFilename);
2636 unlink(gamePasteFilename);
2639 RETSIGTYPE TermSizeSigHandler(int sig)
2652 CmailSigHandler(sig)
2658 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2660 /* Activate call-back function CmailSigHandlerCallBack() */
2661 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2663 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2667 CmailSigHandlerCallBack(isr, closure, message, count, error)
2675 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2677 /**** end signal code ****/
2683 /* try to open the icsLogon script, either in the location given
2684 * or in the users HOME directory
2691 f = fopen(appData.icsLogon, "r");
2694 homedir = getenv("HOME");
2695 if (homedir != NULL)
2697 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2698 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2699 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2700 f = fopen(buf, "r");
2705 ProcessICSInitScript(f);
2707 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2716 EditCommentPopDown();
2731 if (!menuBarWidget) return;
2732 w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2734 DisplayError("menuEdit.Revert", 0);
2736 XtSetSensitive(w, !grey);
2738 w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2740 DisplayError("menuEdit.Annotate", 0);
2742 XtSetSensitive(w, !grey);
2747 SetMenuEnables(enab)
2751 if (!menuBarWidget) return;
2752 while (enab->name != NULL) {
2753 w = XtNameToWidget(menuBarWidget, enab->name);
2755 DisplayError(enab->name, 0);
2757 XtSetSensitive(w, enab->value);
2763 Enables icsEnables[] = {
2764 { "menuFile.Mail Move", False },
2765 { "menuFile.Reload CMail Message", False },
2766 { "menuMode.Machine Black", False },
2767 { "menuMode.Machine White", False },
2768 { "menuMode.Analysis Mode", False },
2769 { "menuMode.Analyze File", False },
2770 { "menuMode.Two Machines", False },
2772 { "menuEngine.Hint", False },
2773 { "menuEngine.Book", False },
2774 { "menuEngine.Move Now", False },
2775 { "menuOptions.Periodic Updates", False },
2776 { "menuOptions.Hide Thinking", False },
2777 { "menuOptions.Ponder Next Move", False },
2778 { "menuEngine.Engine #1 Settings", False },
2780 { "menuEngine.Engine #2 Settings", False },
2781 { "menuEdit.Annotate", False },
2785 Enables ncpEnables[] = {
2786 { "menuFile.Mail Move", False },
2787 { "menuFile.Reload CMail Message", False },
2788 { "menuMode.Machine White", False },
2789 { "menuMode.Machine Black", False },
2790 { "menuMode.Analysis Mode", False },
2791 { "menuMode.Analyze File", False },
2792 { "menuMode.Two Machines", False },
2793 { "menuMode.ICS Client", False },
2794 { "menuView.ICS Input Box", False },
2795 { "Action", False },
2796 { "menuEdit.Revert", False },
2797 { "menuEdit.Annotate", False },
2798 { "menuEngine.Engine #1 Settings", False },
2799 { "menuEngine.Engine #2 Settings", False },
2800 { "menuEngine.Move Now", False },
2801 { "menuEngine.Retract Move", False },
2802 { "menuOptions.Auto Comment", False },
2803 { "menuOptions.Auto Flag", False },
2804 { "menuOptions.Auto Flip View", False },
2805 { "menuOptions.Auto Observe", False },
2806 { "menuOptions.Auto Raise Board", False },
2807 { "menuOptions.Get Move List", False },
2808 { "menuOptions.ICS Alarm", False },
2809 { "menuOptions.Move Sound", False },
2810 { "menuOptions.Quiet Play", False },
2811 { "menuOptions.Hide Thinking", False },
2812 { "menuOptions.Periodic Updates", False },
2813 { "menuOptions.Ponder Next Move", False },
2814 { "menuEngine.Hint", False },
2815 { "menuEngine.Book", False },
2819 Enables gnuEnables[] = {
2820 { "menuMode.ICS Client", False },
2821 { "menuView.ICS Input Box", False },
2822 { "menuAction.Accept", False },
2823 { "menuAction.Decline", False },
2824 { "menuAction.Rematch", False },
2825 { "menuAction.Adjourn", False },
2826 { "menuAction.Stop Examining", False },
2827 { "menuAction.Stop Observing", False },
2828 { "menuAction.Upload to Examine", False },
2829 { "menuEdit.Revert", False },
2830 { "menuEdit.Annotate", False },
2831 { "menuOptions.Auto Comment", False },
2832 { "menuOptions.Auto Observe", False },
2833 { "menuOptions.Auto Raise Board", False },
2834 { "menuOptions.Get Move List", False },
2835 { "menuOptions.Premove", False },
2836 { "menuOptions.Quiet Play", False },
2838 /* The next two options rely on SetCmailMode being called *after* */
2839 /* SetGNUMode so that when GNU is being used to give hints these */
2840 /* menu options are still available */
2842 { "menuFile.Mail Move", False },
2843 { "menuFile.Reload CMail Message", False },
2847 Enables cmailEnables[] = {
2849 { "menuAction.Call Flag", False },
2850 { "menuAction.Draw", True },
2851 { "menuAction.Adjourn", False },
2852 { "menuAction.Abort", False },
2853 { "menuAction.Stop Observing", False },
2854 { "menuAction.Stop Examining", False },
2855 { "menuFile.Mail Move", True },
2856 { "menuFile.Reload CMail Message", True },
2860 Enables trainingOnEnables[] = {
2861 { "menuMode.Edit Comment", False },
2862 { "menuMode.Pause", False },
2863 { "menuEdit.Forward", False },
2864 { "menuEdit.Backward", False },
2865 { "menuEdit.Forward to End", False },
2866 { "menuEdit.Back to Start", False },
2867 { "menuEngine.Move Now", False },
2868 { "menuEdit.Truncate Game", False },
2872 Enables trainingOffEnables[] = {
2873 { "menuMode.Edit Comment", True },
2874 { "menuMode.Pause", True },
2875 { "menuEdit.Forward", True },
2876 { "menuEdit.Backward", True },
2877 { "menuEdit.Forward to End", True },
2878 { "menuEdit.Back to Start", True },
2879 { "menuEngine.Move Now", True },
2880 { "menuEdit.Truncate Game", True },
2884 Enables machineThinkingEnables[] = {
2885 { "menuFile.Load Game", False },
2886 // { "menuFile.Load Next Game", False },
2887 // { "menuFile.Load Previous Game", False },
2888 // { "menuFile.Reload Same Game", False },
2889 { "menuEdit.Paste Game", False },
2890 { "menuFile.Load Position", False },
2891 // { "menuFile.Load Next Position", False },
2892 // { "menuFile.Load Previous Position", False },
2893 // { "menuFile.Reload Same Position", False },
2894 { "menuEdit.Paste Position", False },
2895 { "menuMode.Machine White", False },
2896 { "menuMode.Machine Black", False },
2897 { "menuMode.Two Machines", False },
2898 { "menuEngine.Retract Move", False },
2902 Enables userThinkingEnables[] = {
2903 { "menuFile.Load Game", True },
2904 // { "menuFile.Load Next Game", True },
2905 // { "menuFile.Load Previous Game", True },
2906 // { "menuFile.Reload Same Game", True },
2907 { "menuEdit.Paste Game", True },
2908 { "menuFile.Load Position", True },
2909 // { "menuFile.Load Next Position", True },
2910 // { "menuFile.Load Previous Position", True },
2911 // { "menuFile.Reload Same Position", True },
2912 { "menuEdit.Paste Position", True },
2913 { "menuMode.Machine White", True },
2914 { "menuMode.Machine Black", True },
2915 { "menuMode.Two Machines", True },
2916 { "menuEngine.Retract Move", True },
2922 SetMenuEnables(icsEnables);
2925 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2926 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2933 SetMenuEnables(ncpEnables);
2939 SetMenuEnables(gnuEnables);
2945 SetMenuEnables(cmailEnables);
2951 SetMenuEnables(trainingOnEnables);
2952 if (appData.showButtonBar) {
2953 XtSetSensitive(buttonBarWidget, False);
2959 SetTrainingModeOff()
2961 SetMenuEnables(trainingOffEnables);
2962 if (appData.showButtonBar) {
2963 XtSetSensitive(buttonBarWidget, True);
2968 SetUserThinkingEnables()
2970 if (appData.noChessProgram) return;
2971 SetMenuEnables(userThinkingEnables);
2975 SetMachineThinkingEnables()
2977 if (appData.noChessProgram) return;
2978 SetMenuEnables(machineThinkingEnables);
2980 case MachinePlaysBlack:
2981 case MachinePlaysWhite:
2982 case TwoMachinesPlay:
2983 XtSetSensitive(XtNameToWidget(menuBarWidget,
2984 ModeToWidgetName(gameMode)), True);
2991 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2992 #define HISTORY_SIZE 64
\r
2993 static char *history[HISTORY_SIZE];
\r
2994 int histIn = 0, histP = 0;
\r
2997 SaveInHistory(char *cmd)
\r
2999 if (history[histIn] != NULL) {
\r
3000 free(history[histIn]);
\r
3001 history[histIn] = NULL;
\r
3003 if (*cmd == NULLCHAR) return;
\r
3004 history[histIn] = StrSave(cmd);
\r
3005 histIn = (histIn + 1) % HISTORY_SIZE;
\r
3006 if (history[histIn] != NULL) {
\r
3007 free(history[histIn]);
\r
3008 history[histIn] = NULL;
\r
3014 PrevInHistory(char *cmd)
\r
3017 if (histP == histIn) {
\r
3018 if (history[histIn] != NULL) free(history[histIn]);
\r
3019 history[histIn] = StrSave(cmd);
\r
3021 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
3022 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
3024 return history[histP];
\r
3030 if (histP == histIn) return NULL;
\r
3031 histP = (histP + 1) % HISTORY_SIZE;
\r
3032 return history[histP];
\r
3034 // end of borrowed code
\r
3036 #define Abs(n) ((n)<0 ? -(n) : (n))
3039 * Find a font that matches "pattern" that is as close as
3040 * possible to the targetPxlSize. Prefer fonts that are k
3041 * pixels smaller to fonts that are k pixels larger. The
3042 * pattern must be in the X Consortium standard format,
3043 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3044 * The return value should be freed with XtFree when no
3048 FindFont(pattern, targetPxlSize)
3052 char **fonts, *p, *best, *scalable, *scalableTail;
3053 int i, j, nfonts, minerr, err, pxlSize;
3056 char **missing_list;
3058 char *def_string, *base_fnt_lst, strInt[3];
3060 XFontStruct **fnt_list;
3062 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3063 snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
3064 p = strstr(pattern, "--");
3065 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3066 strcat(base_fnt_lst, strInt);
3067 strcat(base_fnt_lst, strchr(p + 2, '-'));
3069 if ((fntSet = XCreateFontSet(xDisplay,
3073 &def_string)) == NULL) {
3075 fprintf(stderr, _("Unable to create font set.\n"));
3079 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3081 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3083 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3084 programName, pattern);
3092 for (i=0; i<nfonts; i++) {
3095 if (*p != '-') continue;
3097 if (*p == NULLCHAR) break;
3098 if (*p++ == '-') j++;
3100 if (j < 7) continue;
3103 scalable = fonts[i];
3106 err = pxlSize - targetPxlSize;
3107 if (Abs(err) < Abs(minerr) ||
3108 (minerr > 0 && err < 0 && -err == minerr)) {
3114 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3115 /* If the error is too big and there is a scalable font,
3116 use the scalable font. */
3117 int headlen = scalableTail - scalable;
3118 p = (char *) XtMalloc(strlen(scalable) + 10);
3119 while (isdigit(*scalableTail)) scalableTail++;
3120 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3122 p = (char *) XtMalloc(strlen(best) + 2);
3123 safeStrCpy(p, best, strlen(best)+1 );
3125 if (appData.debugMode) {
3126 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3127 pattern, targetPxlSize, p);
3130 if (missing_count > 0)
3131 XFreeStringList(missing_list);
3132 XFreeFontSet(xDisplay, fntSet);
3134 XFreeFontNames(fonts);
3141 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3142 | GCBackground | GCFunction | GCPlaneMask;
3143 XGCValues gc_values;
3146 gc_values.plane_mask = AllPlanes;
3147 gc_values.line_width = lineGap;
3148 gc_values.line_style = LineSolid;
3149 gc_values.function = GXcopy;
3151 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3152 gc_values.background = XBlackPixel(xDisplay, xScreen);
3153 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3155 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3156 gc_values.background = XWhitePixel(xDisplay, xScreen);
3157 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3158 XSetFont(xDisplay, coordGC, coordFontID);
3160 // [HGM] make font for holdings counts (white on black0
3161 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3162 gc_values.background = XBlackPixel(xDisplay, xScreen);
3163 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3164 XSetFont(xDisplay, countGC, countFontID);
3166 if (appData.monoMode) {
3167 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3168 gc_values.background = XWhitePixel(xDisplay, xScreen);
3169 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3171 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3172 gc_values.background = XBlackPixel(xDisplay, xScreen);
3173 lightSquareGC = wbPieceGC
3174 = XtGetGC(shellWidget, value_mask, &gc_values);
3176 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3177 gc_values.background = XWhitePixel(xDisplay, xScreen);
3178 darkSquareGC = bwPieceGC
3179 = XtGetGC(shellWidget, value_mask, &gc_values);
3181 if (DefaultDepth(xDisplay, xScreen) == 1) {
3182 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3183 gc_values.function = GXcopyInverted;
3184 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3185 gc_values.function = GXcopy;
3186 if (XBlackPixel(xDisplay, xScreen) == 1) {
3187 bwPieceGC = darkSquareGC;
3188 wbPieceGC = copyInvertedGC;
3190 bwPieceGC = copyInvertedGC;
3191 wbPieceGC = lightSquareGC;
3195 gc_values.foreground = highlightSquareColor;
3196 gc_values.background = highlightSquareColor;
3197 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3199 gc_values.foreground = premoveHighlightColor;
3200 gc_values.background = premoveHighlightColor;
3201 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3203 gc_values.foreground = lightSquareColor;
3204 gc_values.background = darkSquareColor;
3205 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3207 gc_values.foreground = darkSquareColor;
3208 gc_values.background = lightSquareColor;
3209 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3211 gc_values.foreground = jailSquareColor;
3212 gc_values.background = jailSquareColor;
3213 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3215 gc_values.foreground = whitePieceColor;
3216 gc_values.background = darkSquareColor;
3217 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3219 gc_values.foreground = whitePieceColor;
3220 gc_values.background = lightSquareColor;
3221 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3223 gc_values.foreground = whitePieceColor;
3224 gc_values.background = jailSquareColor;
3225 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3227 gc_values.foreground = blackPieceColor;
3228 gc_values.background = darkSquareColor;
3229 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3231 gc_values.foreground = blackPieceColor;
3232 gc_values.background = lightSquareColor;
3233 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3235 gc_values.foreground = blackPieceColor;
3236 gc_values.background = jailSquareColor;
3237 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3241 void loadXIM(xim, xmask, filename, dest, mask)
3254 fp = fopen(filename, "rb");
3256 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3263 for (y=0; y<h; ++y) {
3264 for (x=0; x<h; ++x) {
3269 XPutPixel(xim, x, y, blackPieceColor);
3271 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3274 XPutPixel(xim, x, y, darkSquareColor);
3276 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3279 XPutPixel(xim, x, y, whitePieceColor);
3281 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3284 XPutPixel(xim, x, y, lightSquareColor);
3286 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3292 /* create Pixmap of piece */
3293 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3295 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3298 /* create Pixmap of clipmask
3299 Note: We assume the white/black pieces have the same
3300 outline, so we make only 6 masks. This is okay
3301 since the XPM clipmask routines do the same. */
3303 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3305 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3308 /* now create the 1-bit version */
3309 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3312 values.foreground = 1;
3313 values.background = 0;
3315 /* Don't use XtGetGC, not read only */
3316 maskGC = XCreateGC(xDisplay, *mask,
3317 GCForeground | GCBackground, &values);
3318 XCopyPlane(xDisplay, temp, *mask, maskGC,
3319 0, 0, squareSize, squareSize, 0, 0, 1);
3320 XFreePixmap(xDisplay, temp);
3325 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3327 void CreateXIMPieces()
3332 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3337 /* The XSynchronize calls were copied from CreatePieces.
3338 Not sure if needed, but can't hurt */
3339 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3342 /* temp needed by loadXIM() */
3343 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3344 0, 0, ss, ss, AllPlanes, XYPixmap);
3346 if (strlen(appData.pixmapDirectory) == 0) {
3350 if (appData.monoMode) {
3351 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3355 fprintf(stderr, _("\nLoading XIMs...\n"));
3357 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3358 fprintf(stderr, "%d", piece+1);
3359 for (kind=0; kind<4; kind++) {
3360 fprintf(stderr, ".");
3361 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3362 ExpandPathName(appData.pixmapDirectory),
3363 piece <= (int) WhiteKing ? "" : "w",
3364 pieceBitmapNames[piece],
3366 ximPieceBitmap[kind][piece] =
3367 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3368 0, 0, ss, ss, AllPlanes, XYPixmap);
3369 if (appData.debugMode)
3370 fprintf(stderr, _("(File:%s:) "), buf);
3371 loadXIM(ximPieceBitmap[kind][piece],
3373 &(xpmPieceBitmap2[kind][piece]),
3374 &(ximMaskPm2[piece]));
3375 if(piece <= (int)WhiteKing)
3376 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3378 fprintf(stderr," ");
3380 /* Load light and dark squares */
3381 /* If the LSQ and DSQ pieces don't exist, we will
3382 draw them with solid squares. */
3383 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3384 if (access(buf, 0) != 0) {
3388 fprintf(stderr, _("light square "));
3390 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3391 0, 0, ss, ss, AllPlanes, XYPixmap);
3392 if (appData.debugMode)
3393 fprintf(stderr, _("(File:%s:) "), buf);
3395 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3396 fprintf(stderr, _("dark square "));
3397 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3398 ExpandPathName(appData.pixmapDirectory), ss);
3399 if (appData.debugMode)
3400 fprintf(stderr, _("(File:%s:) "), buf);
3402 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3403 0, 0, ss, ss, AllPlanes, XYPixmap);
3404 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3405 xpmJailSquare = xpmLightSquare;
3407 fprintf(stderr, _("Done.\n"));
3409 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3413 void CreateXPMBoard(char *s, int kind)
3417 if(s == NULL || *s == 0 || *s == '*') return;
3418 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3419 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3423 void CreateXPMPieces()
3427 u_int ss = squareSize;
3429 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3430 XpmColorSymbol symbols[4];
3432 /* The XSynchronize calls were copied from CreatePieces.
3433 Not sure if needed, but can't hurt */
3434 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3436 /* Setup translations so piece colors match square colors */
3437 symbols[0].name = "light_piece";
3438 symbols[0].value = appData.whitePieceColor;
3439 symbols[1].name = "dark_piece";
3440 symbols[1].value = appData.blackPieceColor;
3441 symbols[2].name = "light_square";
3442 symbols[2].value = appData.lightSquareColor;
3443 symbols[3].name = "dark_square";
3444 symbols[3].value = appData.darkSquareColor;
3446 attr.valuemask = XpmColorSymbols;
3447 attr.colorsymbols = symbols;
3448 attr.numsymbols = 4;
3450 if (appData.monoMode) {
3451 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3455 if (strlen(appData.pixmapDirectory) == 0) {
3456 XpmPieces* pieces = builtInXpms;
3459 while (pieces->size != squareSize && pieces->size) pieces++;
3460 if (!pieces->size) {
3461 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3464 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3465 for (kind=0; kind<4; kind++) {
3467 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3468 pieces->xpm[piece][kind],
3469 &(xpmPieceBitmap2[kind][piece]),
3470 NULL, &attr)) != 0) {
3471 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3475 if(piece <= (int) WhiteKing)
3476 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3480 xpmJailSquare = xpmLightSquare;
3484 fprintf(stderr, _("\nLoading XPMs...\n"));
3487 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3488 fprintf(stderr, "%d ", piece+1);
3489 for (kind=0; kind<4; kind++) {
3490 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3491 ExpandPathName(appData.pixmapDirectory),
3492 piece > (int) WhiteKing ? "w" : "",
3493 pieceBitmapNames[piece],
3495 if (appData.debugMode) {
3496 fprintf(stderr, _("(File:%s:) "), buf);
3498 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3499 &(xpmPieceBitmap2[kind][piece]),
3500 NULL, &attr)) != 0) {
3501 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3502 // [HGM] missing: read of unorthodox piece failed; substitute King.
3503 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3504 ExpandPathName(appData.pixmapDirectory),
3506 if (appData.debugMode) {
3507 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3509 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3510 &(xpmPieceBitmap2[kind][piece]),
3514 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3519 if(piece <= (int) WhiteKing)
3520 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3523 /* Load light and dark squares */
3524 /* If the LSQ and DSQ pieces don't exist, we will
3525 draw them with solid squares. */
3526 fprintf(stderr, _("light square "));
3527 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3528 if (access(buf, 0) != 0) {
3532 if (appData.debugMode)
3533 fprintf(stderr, _("(File:%s:) "), buf);
3535 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3536 &xpmLightSquare, NULL, &attr)) != 0) {
3537 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3540 fprintf(stderr, _("dark square "));
3541 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3542 ExpandPathName(appData.pixmapDirectory), ss);
3543 if (appData.debugMode) {
3544 fprintf(stderr, _("(File:%s:) "), buf);
3546 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3547 &xpmDarkSquare, NULL, &attr)) != 0) {
3548 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3552 xpmJailSquare = xpmLightSquare;
3553 fprintf(stderr, _("Done.\n"));
3555 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3558 #endif /* HAVE_LIBXPM */
3561 /* No built-in bitmaps */
3566 u_int ss = squareSize;
3568 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3571 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3572 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3573 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3574 pieceBitmapNames[piece],
3575 ss, kind == SOLID ? 's' : 'o');
3576 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3577 if(piece <= (int)WhiteKing)
3578 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3582 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3586 /* With built-in bitmaps */
3589 BuiltInBits* bib = builtInBits;
3592 u_int ss = squareSize;
3594 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3597 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3599 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3600 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3601 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3602 pieceBitmapNames[piece],
3603 ss, kind == SOLID ? 's' : 'o');
3604 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3605 bib->bits[kind][piece], ss, ss);
3606 if(piece <= (int)WhiteKing)
3607 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3611 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3616 void ReadBitmap(pm, name, bits, wreq, hreq)
3619 unsigned char bits[];
3625 char msg[MSG_SIZ], fullname[MSG_SIZ];
3627 if (*appData.bitmapDirectory != NULLCHAR) {
3628 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3629 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3630 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3631 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3632 &w, &h, pm, &x_hot, &y_hot);
3633 fprintf(stderr, "load %s\n", name);
3634 if (errcode != BitmapSuccess) {
3636 case BitmapOpenFailed:
3637 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3639 case BitmapFileInvalid:
3640 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3642 case BitmapNoMemory:
3643 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3647 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3651 fprintf(stderr, _("%s: %s...using built-in\n"),
3653 } else if (w != wreq || h != hreq) {
3655 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3656 programName, fullname, w, h, wreq, hreq);
3662 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3671 if (lineGap == 0) return;
3673 /* [HR] Split this into 2 loops for non-square boards. */
3675 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3676 gridSegments[i].x1 = 0;
3677 gridSegments[i].x2 =
3678 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3679 gridSegments[i].y1 = gridSegments[i].y2
3680 = lineGap / 2 + (i * (squareSize + lineGap));
3683 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3684 gridSegments[j + i].y1 = 0;
3685 gridSegments[j + i].y2 =
3686 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3687 gridSegments[j + i].x1 = gridSegments[j + i].x2
3688 = lineGap / 2 + (j * (squareSize + lineGap));
3692 static void MenuBarSelect(w, addr, index)
3697 XtActionProc proc = (XtActionProc) addr;
3699 (proc)(NULL, NULL, NULL, NULL);
3702 void CreateMenuBarPopup(parent, name, mb)
3712 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3715 XtSetArg(args[j], XtNleftMargin, 20); j++;
3716 XtSetArg(args[j], XtNrightMargin, 20); j++;
3718 while (mi->string != NULL) {
3719 if (strcmp(mi->string, "----") == 0) {
3720 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3723 XtSetArg(args[j], XtNlabel, XtNewString(mi->string));
3724 entry = XtCreateManagedWidget(mi->ref, smeBSBObjectClass,
3726 XtAddCallback(entry, XtNcallback,
3727 (XtCallbackProc) MenuBarSelect,
3728 (caddr_t) mi->proc);
3734 Widget CreateMenuBar(mb)
3738 Widget anchor, menuBar;
3740 char menuName[MSG_SIZ];
3743 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3744 XtSetArg(args[j], XtNvSpace, 0); j++;
3745 XtSetArg(args[j], XtNborderWidth, 0); j++;
3746 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3747 formWidget, args, j);
3749 while (mb->name != NULL) {
3750 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3751 strncat(menuName, mb->ref, MSG_SIZ - strlen(menuName) - 1);
3753 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3756 shortName[0] = mb->name[0];
3757 shortName[1] = NULLCHAR;
3758 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3761 XtSetArg(args[j], XtNlabel, XtNewString(mb->name)); j++;
3764 XtSetArg(args[j], XtNborderWidth, 0); j++;
3765 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3767 CreateMenuBarPopup(menuBar, menuName, mb);
3773 Widget CreateButtonBar(mi)
3777 Widget button, buttonBar;
3781 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3783 XtSetArg(args[j], XtNhSpace, 0); j++;
3785 XtSetArg(args[j], XtNborderWidth, 0); j++;
3786 XtSetArg(args[j], XtNvSpace, 0); j++;
3787 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3788 formWidget, args, j);
3790 while (mi->string != NULL) {
3793 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3794 XtSetArg(args[j], XtNborderWidth, 0); j++;
3796 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3797 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3798 buttonBar, args, j);
3799 XtAddCallback(button, XtNcallback,
3800 (XtCallbackProc) MenuBarSelect,
3801 (caddr_t) mi->proc);
3808 CreatePieceMenu(name, color)
3815 ChessSquare selection;
3817 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3818 boardWidget, args, 0);
3820 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3821 String item = pieceMenuStrings[color][i];
3823 if (strcmp(item, "----") == 0) {
3824 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3827 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3828 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3830 selection = pieceMenuTranslation[color][i];
3831 XtAddCallback(entry, XtNcallback,
3832 (XtCallbackProc) PieceMenuSelect,
3833 (caddr_t) selection);
3834 if (selection == WhitePawn || selection == BlackPawn) {
3835 XtSetArg(args[0], XtNpopupOnEntry, entry);
3836 XtSetValues(menu, args, 1);
3849 ChessSquare selection;
3851 whitePieceMenu = CreatePieceMenu("menuW", 0);
3852 blackPieceMenu = CreatePieceMenu("menuB", 1);
3854 XtRegisterGrabAction(PieceMenuPopup, True,
3855 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3856 GrabModeAsync, GrabModeAsync);
3858 XtSetArg(args[0], XtNlabel, _("Drop"));
3859 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3860 boardWidget, args, 1);
3861 for (i = 0; i < DROP_MENU_SIZE; i++) {
3862 String item = dropMenuStrings[i];
3864 if (strcmp(item, "----") == 0) {
3865 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3868 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3869 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3871 selection = dropMenuTranslation[i];
3872 XtAddCallback(entry, XtNcallback,
3873 (XtCallbackProc) DropMenuSelect,
3874 (caddr_t) selection);
3879 void SetupDropMenu()
3887 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3888 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3889 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3890 dmEnables[i].piece);
3891 XtSetSensitive(entry, p != NULL || !appData.testLegality
3892 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3893 && !appData.icsActive));
3895 while (p && *p++ == dmEnables[i].piece) count++;
3896 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3898 XtSetArg(args[j], XtNlabel, label); j++;
3899 XtSetValues(entry, args, j);
3903 void PieceMenuPopup(w, event, params, num_params)
3907 Cardinal *num_params;
3909 String whichMenu; int menuNr;
3910 if (event->type == ButtonRelease)
3911 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3912 else if (event->type == ButtonPress)
3913 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3915 case 0: whichMenu = params[0]; break;
3916 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3918 case -1: if (errorUp) ErrorPopDown();
3921 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3924 static void PieceMenuSelect(w, piece, junk)
3929 if (pmFromX < 0 || pmFromY < 0) return;
3930 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3933 static void DropMenuSelect(w, piece, junk)
3938 if (pmFromX < 0 || pmFromY < 0) return;
3939 DropMenuEvent(piece, pmFromX, pmFromY);
3942 void WhiteClock(w, event, prms, nprms)
3948 if (gameMode == EditPosition || gameMode == IcsExamining) {
3949 SetWhiteToPlayEvent();
3950 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3955 void BlackClock(w, event, prms, nprms)
3961 if (gameMode == EditPosition || gameMode == IcsExamining) {
3962 SetBlackToPlayEvent();
3963 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3970 * If the user selects on a border boundary, return -1; if off the board,
3971 * return -2. Otherwise map the event coordinate to the square.
3973 int EventToSquare(x, limit)
3981 if ((x % (squareSize + lineGap)) >= squareSize)
3983 x /= (squareSize + lineGap);
3989 static void do_flash_delay(msec)
3995 static void drawHighlight(file, rank, gc)
4001 if (lineGap == 0 || appData.blindfold) return;
4004 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
4005 (squareSize + lineGap);
4006 y = lineGap/2 + rank * (squareSize + lineGap);
4008 x = lineGap/2 + file * (squareSize + lineGap);
4009 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
4010 (squareSize + lineGap);
4013 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
4014 squareSize+lineGap, squareSize+lineGap);
4017 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
4018 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4021 SetHighlights(fromX, fromY, toX, toY)
4022 int fromX, fromY, toX, toY;
4024 if (hi1X != fromX || hi1Y != fromY) {
4025 if (hi1X >= 0 && hi1Y >= 0) {
4026 drawHighlight(hi1X, hi1Y, lineGC);
4028 } // [HGM] first erase both, then draw new!
4029 if (hi2X != toX || hi2Y != toY) {
4030 if (hi2X >= 0 && hi2Y >= 0) {
4031 drawHighlight(hi2X, hi2Y, lineGC);
4034 if (hi1X != fromX || hi1Y != fromY) {
4035 if (fromX >= 0 && fromY >= 0) {
4036 drawHighlight(fromX, fromY, highlineGC);
4039 if (hi2X != toX || hi2Y != toY) {
4040 if (toX >= 0 && toY >= 0) {
4041 drawHighlight(toX, toY, highlineGC);
4053 SetHighlights(-1, -1, -1, -1);
4058 SetPremoveHighlights(fromX, fromY, toX, toY)
4059 int fromX, fromY, toX, toY;
4061 if (pm1X != fromX || pm1Y != fromY) {
4062 if (pm1X >= 0 && pm1Y >= 0) {
4063 drawHighlight(pm1X, pm1Y, lineGC);
4065 if (fromX >= 0 && fromY >= 0) {
4066 drawHighlight(fromX, fromY, prelineGC);
4069 if (pm2X != toX || pm2Y != toY) {
4070 if (pm2X >= 0 && pm2Y >= 0) {
4071 drawHighlight(pm2X, pm2Y, lineGC);
4073 if (toX >= 0 && toY >= 0) {
4074 drawHighlight(toX, toY, prelineGC);
4084 ClearPremoveHighlights()
4086 SetPremoveHighlights(-1, -1, -1, -1);
4089 static int CutOutSquare(x, y, x0, y0, kind)
4090 int x, y, *x0, *y0, kind;
4092 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
4093 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
4095 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
4096 if(textureW[kind] < W*squareSize)
4097 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
4099 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
4100 if(textureH[kind] < H*squareSize)
4101 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
4103 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
4107 static void BlankSquare(x, y, color, piece, dest, fac)
4108 int x, y, color, fac;
4111 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
4113 if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
4114 XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
4115 squareSize, squareSize, x*fac, y*fac);
4117 if (useImages && useImageSqs) {
4121 pm = xpmLightSquare;
4126 case 2: /* neutral */
4131 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4132 squareSize, squareSize, x*fac, y*fac);
4142 case 2: /* neutral */
4147 XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
4152 I split out the routines to draw a piece so that I could
4153 make a generic flash routine.
4155 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4157 int square_color, x, y;
4160 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4161 switch (square_color) {
4163 case 2: /* neutral */
4165 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4166 ? *pieceToOutline(piece)
4167 : *pieceToSolid(piece),
4168 dest, bwPieceGC, 0, 0,
4169 squareSize, squareSize, x, y);
4172 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4173 ? *pieceToSolid(piece)
4174 : *pieceToOutline(piece),
4175 dest, wbPieceGC, 0, 0,
4176 squareSize, squareSize, x, y);
4181 static void monoDrawPiece(piece, square_color, x, y, dest)
4183 int square_color, x, y;
4186 switch (square_color) {
4188 case 2: /* neutral */
4190 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4191 ? *pieceToOutline(piece)
4192 : *pieceToSolid(piece),
4193 dest, bwPieceGC, 0, 0,
4194 squareSize, squareSize, x, y, 1);
4197 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4198 ? *pieceToSolid(piece)
4199 : *pieceToOutline(piece),
4200 dest, wbPieceGC, 0, 0,
4201 squareSize, squareSize, x, y, 1);
4206 static void colorDrawPiece(piece, square_color, x, y, dest)
4208 int square_color, x, y;
4211 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4212 switch (square_color) {
4214 XCopyPlane(xDisplay, *pieceToSolid(piece),
4215 dest, (int) piece < (int) BlackPawn
4216 ? wlPieceGC : blPieceGC, 0, 0,
4217 squareSize, squareSize, x, y, 1);
4220 XCopyPlane(xDisplay, *pieceToSolid(piece),
4221 dest, (int) piece < (int) BlackPawn
4222 ? wdPieceGC : bdPieceGC, 0, 0,
4223 squareSize, squareSize, x, y, 1);
4225 case 2: /* neutral */
4227 XCopyPlane(xDisplay, *pieceToSolid(piece),
4228 dest, (int) piece < (int) BlackPawn
4229 ? wjPieceGC : bjPieceGC, 0, 0,
4230 squareSize, squareSize, x, y, 1);
4235 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4237 int square_color, x, y;
4240 int kind, p = piece;
4242 switch (square_color) {
4244 case 2: /* neutral */
4246 if ((int)piece < (int) BlackPawn) {
4254 if ((int)piece < (int) BlackPawn) {
4262 if(appData.upsideDown && flipView) kind ^= 2; // swap white and black pieces
4263 if(useTexture & square_color+1) {
4264 BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
4265 XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
4266 XSetClipOrigin(xDisplay, wlPieceGC, x, y);
4267 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);
4268 XSetClipMask(xDisplay, wlPieceGC, None);
4269 XSetClipOrigin(xDisplay, wlPieceGC, 0, 0);
4271 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4272 dest, wlPieceGC, 0, 0,
4273 squareSize, squareSize, x, y);
4276 typedef void (*DrawFunc)();
4278 DrawFunc ChooseDrawFunc()
4280 if (appData.monoMode) {
4281 if (DefaultDepth(xDisplay, xScreen) == 1) {
4282 return monoDrawPiece_1bit;
4284 return monoDrawPiece;
4288 return colorDrawPieceImage;
4290 return colorDrawPiece;
4294 /* [HR] determine square color depending on chess variant. */
4295 static int SquareColor(row, column)
4300 if (gameInfo.variant == VariantXiangqi) {
4301 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4303 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4305 } else if (row <= 4) {
4311 square_color = ((column + row) % 2) == 1;
4314 /* [hgm] holdings: next line makes all holdings squares light */
4315 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4317 return square_color;
4320 void DrawSquare(row, column, piece, do_flash)
4321 int row, column, do_flash;
4324 int square_color, x, y, direction, font_ascent, font_descent;
4327 XCharStruct overall;
4331 /* Calculate delay in milliseconds (2-delays per complete flash) */
4332 flash_delay = 500 / appData.flashRate;
4335 x = lineGap + ((BOARD_WIDTH-1)-column) *
4336 (squareSize + lineGap);
4337 y = lineGap + row * (squareSize + lineGap);
4339 x = lineGap + column * (squareSize + lineGap);
4340 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4341 (squareSize + lineGap);
4344 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4346 square_color = SquareColor(row, column);
4348 if ( // [HGM] holdings: blank out area between board and holdings
4349 column == BOARD_LEFT-1 || column == BOARD_RGHT
4350 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4351 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4352 BlankSquare(x, y, 2, EmptySquare, xBoardWindow, 1);
4354 // [HGM] print piece counts next to holdings
4355 string[1] = NULLCHAR;
4356 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4357 string[0] = '0' + piece;
4358 XTextExtents(countFontStruct, string, 1, &direction,
4359 &font_ascent, &font_descent, &overall);
4360 if (appData.monoMode) {
4361 XDrawImageString(xDisplay, xBoardWindow, countGC,
4362 x + squareSize - overall.width - 2,
4363 y + font_ascent + 1, string, 1);
4365 XDrawString(xDisplay, xBoardWindow, countGC,
4366 x + squareSize - overall.width - 2,
4367 y + font_ascent + 1, string, 1);
4370 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4371 string[0] = '0' + piece;
4372 XTextExtents(countFontStruct, string, 1, &direction,
4373 &font_ascent, &font_descent, &overall);
4374 if (appData.monoMode) {
4375 XDrawImageString(xDisplay, xBoardWindow, countGC,
4376 x + 2, y + font_ascent + 1, string, 1);
4378 XDrawString(xDisplay, xBoardWindow, countGC,
4379 x + 2, y + font_ascent + 1, string, 1);
4383 if (piece == EmptySquare || appData.blindfold) {
4384 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4386 drawfunc = ChooseDrawFunc();
4387 if (do_flash && appData.flashCount > 0) {
4388 for (i=0; i<appData.flashCount; ++i) {
4390 drawfunc(piece, square_color, x, y, xBoardWindow);
4391 XSync(xDisplay, False);
4392 do_flash_delay(flash_delay);
4394 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4395 XSync(xDisplay, False);
4396 do_flash_delay(flash_delay);
4399 drawfunc(piece, square_color, x, y, xBoardWindow);
4403 string[1] = NULLCHAR;
4404 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4405 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4406 string[0] = 'a' + column - BOARD_LEFT;
4407 XTextExtents(coordFontStruct, string, 1, &direction,
4408 &font_ascent, &font_descent, &overall);
4409 if (appData.monoMode) {
4410 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4411 x + squareSize - overall.width - 2,
4412 y + squareSize - font_descent - 1, string, 1);
4414 XDrawString(xDisplay, xBoardWindow, coordGC,
4415 x + squareSize - overall.width - 2,
4416 y + squareSize - font_descent - 1, string, 1);
4419 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4420 string[0] = ONE + row;
4421 XTextExtents(coordFontStruct, string, 1, &direction,
4422 &font_ascent, &font_descent, &overall);
4423 if (appData.monoMode) {
4424 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4425 x + 2, y + font_ascent + 1, string, 1);
4427 XDrawString(xDisplay, xBoardWindow, coordGC,
4428 x + 2, y + font_ascent + 1, string, 1);
4431 if(!partnerUp && marker[row][column]) {
4432 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4433 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4438 /* Why is this needed on some versions of X? */
4439 void EventProc(widget, unused, event)
4444 if (!XtIsRealized(widget))
4447 switch (event->type) {
4449 if (event->xexpose.count > 0) return; /* no clipping is done */
4450 XDrawPosition(widget, True, NULL);
4451 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4452 flipView = !flipView; partnerUp = !partnerUp;
4453 XDrawPosition(widget, True, NULL);
4454 flipView = !flipView; partnerUp = !partnerUp;
4458 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
\r
4465 void DrawPosition(fullRedraw, board)
4466 /*Boolean*/int fullRedraw;
4469 XDrawPosition(boardWidget, fullRedraw, board);
4472 /* Returns 1 if there are "too many" differences between b1 and b2
4473 (i.e. more than 1 move was made) */
4474 static int too_many_diffs(b1, b2)
4480 for (i=0; i<BOARD_HEIGHT; ++i) {
4481 for (j=0; j<BOARD_WIDTH; ++j) {
4482 if (b1[i][j] != b2[i][j]) {
4483 if (++c > 4) /* Castling causes 4 diffs */
4492 /* Matrix describing castling maneuvers */
4493 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4494 static int castling_matrix[4][5] = {
4495 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4496 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4497 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4498 { 7, 7, 4, 5, 6 } /* 0-0, black */
4501 /* Checks whether castling occurred. If it did, *rrow and *rcol
4502 are set to the destination (row,col) of the rook that moved.
4504 Returns 1 if castling occurred, 0 if not.
4506 Note: Only handles a max of 1 castling move, so be sure
4507 to call too_many_diffs() first.
4509 static int check_castle_draw(newb, oldb, rrow, rcol)
4516 /* For each type of castling... */
4517 for (i=0; i<4; ++i) {
4518 r = castling_matrix[i];
4520 /* Check the 4 squares involved in the castling move */
4522 for (j=1; j<=4; ++j) {
4523 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4530 /* All 4 changed, so it must be a castling move */
4539 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4540 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4542 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4545 void DrawSeekBackground( int left, int top, int right, int bottom )
4547 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4550 void DrawSeekText(char *buf, int x, int y)
4552 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4555 void DrawSeekDot(int x, int y, int colorNr)
4557 int square = colorNr & 0x80;
4560 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4562 XFillRectangle(xDisplay, xBoardWindow, color,
4563 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4565 XFillArc(xDisplay, xBoardWindow, color,
4566 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4569 static int damage[2][BOARD_RANKS][BOARD_FILES];
4572 * event handler for redrawing the board
4574 void XDrawPosition(w, repaint, board)
4576 /*Boolean*/int repaint;
4580 static int lastFlipView = 0;
4581 static int lastBoardValid[2] = {0, 0};
4582 static Board lastBoard[2];
4585 int nr = twoBoards*partnerUp;
4587 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4589 if (board == NULL) {
4590 if (!lastBoardValid[nr]) return;
4591 board = lastBoard[nr];
4593 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4594 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4595 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Flip View"),
4600 * It would be simpler to clear the window with XClearWindow()
4601 * but this causes a very distracting flicker.
4604 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4606 /* If too much changes (begin observing new game, etc.), don't
4608 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4610 /* Special check for castling so we don't flash both the king
4611 and the rook (just flash the king). */
4613 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4614 /* Draw rook with NO flashing. King will be drawn flashing later */
4615 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4616 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4620 /* First pass -- Draw (newly) empty squares and repair damage.
4621 This prevents you from having a piece show up twice while it
4622 is flashing on its new square */
4623 for (i = 0; i < BOARD_HEIGHT; i++)
4624 for (j = 0; j < BOARD_WIDTH; j++)
4625 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4626 || damage[nr][i][j]) {
4627 DrawSquare(i, j, board[i][j], 0);
4628 damage[nr][i][j] = False;
4631 /* Second pass -- Draw piece(s) in new position and flash them */
4632 for (i = 0; i < BOARD_HEIGHT; i++)
4633 for (j = 0; j < BOARD_WIDTH; j++)
4634 if (board[i][j] != lastBoard[nr][i][j]) {
4635 DrawSquare(i, j, board[i][j], do_flash);
4639 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4640 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4641 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4643 for (i = 0; i < BOARD_HEIGHT; i++)
4644 for (j = 0; j < BOARD_WIDTH; j++) {
4645 DrawSquare(i, j, board[i][j], 0);
4646 damage[nr][i][j] = False;
4650 CopyBoard(lastBoard[nr], board);
4651 lastBoardValid[nr] = 1;
4652 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4653 lastFlipView = flipView;
4655 /* Draw highlights */
4656 if (pm1X >= 0 && pm1Y >= 0) {
4657 drawHighlight(pm1X, pm1Y, prelineGC);
4659 if (pm2X >= 0 && pm2Y >= 0) {
4660 drawHighlight(pm2X, pm2Y, prelineGC);
4662 if (hi1X >= 0 && hi1Y >= 0) {
4663 drawHighlight(hi1X, hi1Y, highlineGC);
4665 if (hi2X >= 0 && hi2Y >= 0) {
4666 drawHighlight(hi2X, hi2Y, highlineGC);
4669 /* If piece being dragged around board, must redraw that too */
4672 XSync(xDisplay, False);
4677 * event handler for redrawing the board
4679 void DrawPositionProc(w, event, prms, nprms)
4685 XDrawPosition(w, True, NULL);
4690 * event handler for parsing user moves
4692 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4693 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4694 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4695 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4696 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4697 // and at the end FinishMove() to perform the move after optional promotion popups.
4698 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4699 void HandleUserMove(w, event, prms, nprms)
4705 if (w != boardWidget || errorExitStatus != -1) return;
4706 if(nprms) shiftKey = !strcmp(prms[0], "1");
4709 if (event->type == ButtonPress) {
4710 XtPopdown(promotionShell);
4711 XtDestroyWidget(promotionShell);
4712 promotionUp = False;
4720 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4721 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4722 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4725 void AnimateUserMove (Widget w, XEvent * event,
4726 String * params, Cardinal * nParams)
4728 DragPieceMove(event->xmotion.x, event->xmotion.y);
4731 void HandlePV (Widget w, XEvent * event,
4732 String * params, Cardinal * nParams)
4733 { // [HGM] pv: walk PV
4734 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4737 Widget CommentCreate(name, text, mutable, callback, lines)
4739 int /*Boolean*/ mutable;
4740 XtCallbackProc callback;
4744 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4749 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4750 XtGetValues(boardWidget, args, j);
4753 XtSetArg(args[j], XtNresizable, True); j++;
4756 XtCreatePopupShell(name, topLevelShellWidgetClass,
4757 shellWidget, args, j);
4760 XtCreatePopupShell(name, transientShellWidgetClass,
4761 shellWidget, args, j);
4764 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4765 layoutArgs, XtNumber(layoutArgs));
4767 XtCreateManagedWidget("form", formWidgetClass, layout,
4768 formArgs, XtNumber(formArgs));
4772 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4773 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4775 XtSetArg(args[j], XtNstring, text); j++;
4776 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4777 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4778 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4779 XtSetArg(args[j], XtNright, XtChainRight); j++;
4780 XtSetArg(args[j], XtNresizable, True); j++;
4781 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4782 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4783 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4784 XtSetArg(args[j], XtNautoFill, True); j++;
4785 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4787 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4788 XtOverrideTranslations(edit, XtParseTranslationTable(commentTranslations));
4792 XtSetArg(args[j], XtNfromVert, edit); j++;
4793 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4794 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4795 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4796 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4798 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4799 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4802 XtSetArg(args[j], XtNfromVert, edit); j++;
4803 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4804 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4805 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4806 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4807 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4809 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4810 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4813 XtSetArg(args[j], XtNfromVert, edit); j++;
4814 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4815 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4816 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4817 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4818 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4820 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4821 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4824 XtSetArg(args[j], XtNfromVert, edit); j++;
4825 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4826 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4827 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4828 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4830 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4831 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4834 XtSetArg(args[j], XtNfromVert, edit); j++;
4835 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4836 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4837 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4838 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4839 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4841 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4842 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4845 XtRealizeWidget(shell);
4847 if (commentX == -1) {
4850 Dimension pw_height;
4851 Dimension ew_height;
4854 XtSetArg(args[j], XtNheight, &ew_height); j++;
4855 XtGetValues(edit, args, j);
4858 XtSetArg(args[j], XtNheight, &pw_height); j++;
4859 XtGetValues(shell, args, j);
4860 commentH = pw_height + (lines - 1) * ew_height;
4861 commentW = bw_width - 16;
4863 XSync(xDisplay, False);
4865 /* This code seems to tickle an X bug if it is executed too soon
4866 after xboard starts up. The coordinates get transformed as if
4867 the main window was positioned at (0, 0).
4869 XtTranslateCoords(shellWidget,
4870 (bw_width - commentW) / 2, 0 - commentH / 2,
4871 &commentX, &commentY);
4873 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4874 RootWindowOfScreen(XtScreen(shellWidget)),
4875 (bw_width - commentW) / 2, 0 - commentH / 2,
4880 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4883 if(wpComment.width > 0) {
4884 commentX = wpComment.x;
4885 commentY = wpComment.y;
4886 commentW = wpComment.width;
4887 commentH = wpComment.height;
4891 XtSetArg(args[j], XtNheight, commentH); j++;
4892 XtSetArg(args[j], XtNwidth, commentW); j++;
4893 XtSetArg(args[j], XtNx, commentX); j++;
4894 XtSetArg(args[j], XtNy, commentY); j++;
4895 XtSetValues(shell, args, j);
4896 XtSetKeyboardFocus(shell, edit);
4901 /* Used for analysis window and ICS input window */
4902 Widget MiscCreate(name, text, mutable, callback, lines)
4904 int /*Boolean*/ mutable;
4905 XtCallbackProc callback;
4909 Widget shell, layout, form, edit;
4911 Dimension bw_width, pw_height, ew_height, w, h;
4917 XtSetArg(args[j], XtNresizable, True); j++;
4920 XtCreatePopupShell(name, topLevelShellWidgetClass,
4921 shellWidget, args, j);
4924 XtCreatePopupShell(name, transientShellWidgetClass,
4925 shellWidget, args, j);
4928 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4929 layoutArgs, XtNumber(layoutArgs));
4931 XtCreateManagedWidget("form", formWidgetClass, layout,
4932 formArgs, XtNumber(formArgs));
4936 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4937 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4939 XtSetArg(args[j], XtNstring, text); j++;
4940 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4941 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4942 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4943 XtSetArg(args[j], XtNright, XtChainRight); j++;
4944 XtSetArg(args[j], XtNresizable, True); j++;
4945 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4946 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4947 XtSetArg(args[j], XtNautoFill, True); j++;
4948 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4950 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4952 XtRealizeWidget(shell);
4955 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4956 XtGetValues(boardWidget, args, j);
4959 XtSetArg(args[j], XtNheight, &ew_height); j++;
4960 XtGetValues(edit, args, j);
4963 XtSetArg(args[j], XtNheight, &pw_height); j++;
4964 XtGetValues(shell, args, j);
4965 h = pw_height + (lines - 1) * ew_height;
4968 XSync(xDisplay, False);
4970 /* This code seems to tickle an X bug if it is executed too soon
4971 after xboard starts up. The coordinates get transformed as if
4972 the main window was positioned at (0, 0).
4974 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4976 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4977 RootWindowOfScreen(XtScreen(shellWidget)),
4978 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4982 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4985 XtSetArg(args[j], XtNheight, h); j++;
4986 XtSetArg(args[j], XtNwidth, w); j++;
4987 XtSetArg(args[j], XtNx, x); j++;
4988 XtSetArg(args[j], XtNy, y); j++;
4989 XtSetValues(shell, args, j);
4995 static int savedIndex; /* gross that this is global */
4997 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
5000 XawTextPosition index, dummy;
5003 XawTextGetSelectionPos(w, &index, &dummy);
5004 XtSetArg(arg, XtNstring, &val);
5005 XtGetValues(w, &arg, 1);
5006 ReplaceComment(savedIndex, val);
5007 if(savedIndex != currentMove) ToNrEvent(savedIndex);
5008 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
5011 void EditCommentPopUp(index, title, text)
5020 if (text == NULL) text = "";
5022 if (editShell == NULL) {
5024 CommentCreate(title, text, True, EditCommentCallback, 4);
5025 XtRealizeWidget(editShell);
5026 CatchDeleteWindow(editShell, "EditCommentPopDown");
5028 edit = XtNameToWidget(editShell, "*form.text");
5030 XtSetArg(args[j], XtNstring, text); j++;
5031 XtSetValues(edit, args, j);
5033 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5034 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5035 XtSetValues(editShell, args, j);
5038 XtPopup(editShell, XtGrabNone);
5042 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5043 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"),
5045 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"),
5049 void EditCommentCallback(w, client_data, call_data)
5051 XtPointer client_data, call_data;
5059 XtSetArg(args[j], XtNlabel, &name); j++;
5060 XtGetValues(w, args, j);
5062 if (strcmp(name, _("ok")) == 0) {
5063 edit = XtNameToWidget(editShell, "*form.text");
5065 XtSetArg(args[j], XtNstring, &val); j++;
5066 XtGetValues(edit, args, j);
5067 ReplaceComment(savedIndex, val);
5068 EditCommentPopDown();
5069 } else if (strcmp(name, _("cancel")) == 0) {
5070 EditCommentPopDown();
5071 } else if (strcmp(name, _("clear")) == 0) {
5072 edit = XtNameToWidget(editShell, "*form.text");
5073 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5074 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5078 void EditCommentPopDown()
5083 if (!editUp) return;
5085 XtSetArg(args[j], XtNx, &commentX); j++;
5086 XtSetArg(args[j], XtNy, &commentY); j++;
5087 XtSetArg(args[j], XtNheight, &commentH); j++;
5088 XtSetArg(args[j], XtNwidth, &commentW); j++;
5089 XtGetValues(editShell, args, j);
5090 XtPopdown(editShell);
5093 XtSetArg(args[j], XtNleftBitmap, None); j++;
5094 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"),
5096 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"),
5100 void ICSInputBoxPopUp()
5105 char *title = _("ICS Input");
5108 if (ICSInputShell == NULL) {
5109 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
5110 tr = XtParseTranslationTable(ICSInputTranslations);
5111 edit = XtNameToWidget(ICSInputShell, "*form.text");
5112 XtOverrideTranslations(edit, tr);
5113 XtRealizeWidget(ICSInputShell);
5114 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
5117 edit = XtNameToWidget(ICSInputShell, "*form.text");
5119 XtSetArg(args[j], XtNstring, ""); j++;
5120 XtSetValues(edit, args, j);
5122 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5123 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5124 XtSetValues(ICSInputShell, args, j);
5127 XtPopup(ICSInputShell, XtGrabNone);
5128 XtSetKeyboardFocus(ICSInputShell, edit);
5130 ICSInputBoxUp = True;
5132 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5133 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.ICS Input Box"),
5137 void ICSInputSendText()
5144 edit = XtNameToWidget(ICSInputShell, "*form.text");
5146 XtSetArg(args[j], XtNstring, &val); j++;
5147 XtGetValues(edit, args, j);
5149 SendMultiLineToICS(val);
5150 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5151 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5154 void ICSInputBoxPopDown()
5159 if (!ICSInputBoxUp) return;
5161 XtPopdown(ICSInputShell);
5162 ICSInputBoxUp = False;
5164 XtSetArg(args[j], XtNleftBitmap, None); j++;
5165 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.ICS Input Box"),
5169 void CommentPopUp(title, text)
5176 savedIndex = currentMove; // [HGM] vari
5177 if (commentShell == NULL) {
5179 CommentCreate(title, text, False, CommentCallback, 4);
5180 XtRealizeWidget(commentShell);
5181 CatchDeleteWindow(commentShell, "CommentPopDown");
5183 edit = XtNameToWidget(commentShell, "*form.text");
5185 XtSetArg(args[j], XtNstring, text); j++;
5186 XtSetValues(edit, args, j);
5188 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5189 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5190 XtSetValues(commentShell, args, j);
5193 XtPopup(commentShell, XtGrabNone);
5194 XSync(xDisplay, False);
5199 void CommentCallback(w, client_data, call_data)
5201 XtPointer client_data, call_data;
5208 XtSetArg(args[j], XtNlabel, &name); j++;
5209 XtGetValues(w, args, j);
5211 if (strcmp(name, _("close")) == 0) {
5213 } else if (strcmp(name, _("edit")) == 0) {
5220 void CommentPopDown()
5225 if (!commentUp) return;
5227 XtSetArg(args[j], XtNx, &commentX); j++;
5228 XtSetArg(args[j], XtNy, &commentY); j++;
5229 XtSetArg(args[j], XtNwidth, &commentW); j++;
5230 XtSetArg(args[j], XtNheight, &commentH); j++;
5231 XtGetValues(commentShell, args, j);
5232 XtPopdown(commentShell);
5233 XSync(xDisplay, False);
5237 void FileNamePopUp(label, def, proc, openMode)
5243 fileProc = proc; /* I can't see a way not */
5244 fileOpenMode = openMode; /* to use globals here */
5245 { // [HGM] use file-selector dialog stolen from Ghostview
5247 int index; // this is not supported yet
5249 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5250 def, openMode, NULL, &name))
5251 (void) (*fileProc)(f, index=0, name);
5255 void FileNamePopDown()
5257 if (!filenameUp) return;
5258 XtPopdown(fileNameShell);
5259 XtDestroyWidget(fileNameShell);
5264 void FileNameCallback(w, client_data, call_data)
5266 XtPointer client_data, call_data;
5271 XtSetArg(args[0], XtNlabel, &name);
5272 XtGetValues(w, args, 1);
5274 if (strcmp(name, _("cancel")) == 0) {
5279 FileNameAction(w, NULL, NULL, NULL);
5282 void FileNameAction(w, event, prms, nprms)
5294 name = XawDialogGetValueString(w = XtParent(w));
5296 if ((name != NULL) && (*name != NULLCHAR)) {
5297 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
5298 XtPopdown(w = XtParent(XtParent(w)));
5302 p = strrchr(buf, ' ');
5309 fullname = ExpandPathName(buf);
5311 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5314 f = fopen(fullname, fileOpenMode);
5316 DisplayError(_("Failed to open file"), errno);
5318 (void) (*fileProc)(f, index, buf);
5325 XtPopdown(w = XtParent(XtParent(w)));
5331 void PromotionPopUp()
5334 Widget dialog, layout;
5336 Dimension bw_width, pw_width;
5340 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5341 XtGetValues(boardWidget, args, j);
5344 XtSetArg(args[j], XtNresizable, True); j++;
5345 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5347 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5348 shellWidget, args, j);
5350 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5351 layoutArgs, XtNumber(layoutArgs));
5354 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5355 XtSetArg(args[j], XtNborderWidth, 0); j++;
5356 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5359 if(gameInfo.variant != VariantShogi) {
5360 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5361 (XtPointer) dialog);
5362 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5363 (XtPointer) dialog);
5364 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5365 (XtPointer) dialog);
5366 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5367 (XtPointer) dialog);
5368 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5369 gameInfo.variant == VariantGiveaway) {
5370 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5371 (XtPointer) dialog);
5373 if(gameInfo.variant == VariantCapablanca ||
5374 gameInfo.variant == VariantGothic ||
5375 gameInfo.variant == VariantCapaRandom) {
5376 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5377 (XtPointer) dialog);
5378 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5379 (XtPointer) dialog);
5381 } else // [HGM] shogi
5383 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5384 (XtPointer) dialog);
5385 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5386 (XtPointer) dialog);
5388 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5389 (XtPointer) dialog);
5391 XtRealizeWidget(promotionShell);
5392 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5395 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5396 XtGetValues(promotionShell, args, j);
5398 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5399 lineGap + squareSize/3 +
5400 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5401 0 : 6*(squareSize + lineGap)), &x, &y);
5404 XtSetArg(args[j], XtNx, x); j++;
5405 XtSetArg(args[j], XtNy, y); j++;
5406 XtSetValues(promotionShell, args, j);
5408 XtPopup(promotionShell, XtGrabNone);
5413 void PromotionPopDown()
5415 if (!promotionUp) return;
5416 XtPopdown(promotionShell);
5417 XtDestroyWidget(promotionShell);
5418 promotionUp = False;
5421 void PromotionCallback(w, client_data, call_data)
5423 XtPointer client_data, call_data;
5429 XtSetArg(args[0], XtNlabel, &name);
5430 XtGetValues(w, args, 1);
5434 if (fromX == -1) return;
5436 if (strcmp(name, _("cancel")) == 0) {
5440 } else if (strcmp(name, _("Knight")) == 0) {
5442 } else if (strcmp(name, _("Promote")) == 0) {
5444 } else if (strcmp(name, _("Defer")) == 0) {
5447 promoChar = ToLower(name[0]);
5450 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5452 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5453 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5458 void ErrorCallback(w, client_data, call_data)
5460 XtPointer client_data, call_data;
5463 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5465 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5471 if (!errorUp) return;
5473 XtPopdown(errorShell);
5474 XtDestroyWidget(errorShell);
5475 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5478 void ErrorPopUp(title, label, modal)
5479 char *title, *label;
5483 Widget dialog, layout;
5487 Dimension bw_width, pw_width;
5488 Dimension pw_height;
5492 XtSetArg(args[i], XtNresizable, True); i++;
5493 XtSetArg(args[i], XtNtitle, title); i++;
5495 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5496 shellWidget, args, i);
5498 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5499 layoutArgs, XtNumber(layoutArgs));
5502 XtSetArg(args[i], XtNlabel, label); i++;
5503 XtSetArg(args[i], XtNborderWidth, 0); i++;
5504 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5507 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5509 XtRealizeWidget(errorShell);
5510 CatchDeleteWindow(errorShell, "ErrorPopDown");
5513 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5514 XtGetValues(boardWidget, args, i);
5516 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5517 XtSetArg(args[i], XtNheight, &pw_height); i++;
5518 XtGetValues(errorShell, args, i);
5521 /* This code seems to tickle an X bug if it is executed too soon
5522 after xboard starts up. The coordinates get transformed as if
5523 the main window was positioned at (0, 0).
5525 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5526 0 - pw_height + squareSize / 3, &x, &y);
5528 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5529 RootWindowOfScreen(XtScreen(boardWidget)),
5530 (bw_width - pw_width) / 2,
5531 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5535 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5538 XtSetArg(args[i], XtNx, x); i++;
5539 XtSetArg(args[i], XtNy, y); i++;
5540 XtSetValues(errorShell, args, i);
5543 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5546 /* Disable all user input other than deleting the window */
5547 static int frozen = 0;
5551 /* Grab by a widget that doesn't accept input */
5552 XtAddGrab(messageWidget, TRUE, FALSE);
5556 /* Undo a FreezeUI */
5559 if (!frozen) return;
5560 XtRemoveGrab(messageWidget);
5564 char *ModeToWidgetName(mode)
5568 case BeginningOfGame:
5569 if (appData.icsActive)
5570 return "menuMode.ICS Client";
5571 else if (appData.noChessProgram ||
5572 *appData.cmailGameName != NULLCHAR)
5573 return "menuMode.Edit Game";
5575 return "menuMode.Machine Black";
5576 case MachinePlaysBlack:
5577 return "menuMode.Machine Black";
5578 case MachinePlaysWhite:
5579 return "menuMode.Machine White";
5581 return "menuMode.Analysis Mode";
5583 return "menuMode.Analyze File";
5584 case TwoMachinesPlay:
5585 return "menuMode.Two Machines";
5587 return "menuMode.Edit Game";
5588 case PlayFromGameFile:
5589 return "menuFile.Load Game";
5591 return "menuMode.Edit Position";
5593 return "menuMode.Training";
5594 case IcsPlayingWhite:
5595 case IcsPlayingBlack:
5599 return "menuMode.ICS Client";
5606 void ModeHighlight()
5609 static int oldPausing = FALSE;
5610 static GameMode oldmode = (GameMode) -1;
5613 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5615 if (pausing != oldPausing) {
5616 oldPausing = pausing;
5618 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5620 XtSetArg(args[0], XtNleftBitmap, None);
5622 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5625 if (appData.showButtonBar) {
5626 /* Always toggle, don't set. Previous code messes up when
5627 invoked while the button is pressed, as releasing it
5628 toggles the state again. */
5631 XtSetArg(args[0], XtNbackground, &oldbg);
5632 XtSetArg(args[1], XtNforeground, &oldfg);
5633 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5635 XtSetArg(args[0], XtNbackground, oldfg);
5636 XtSetArg(args[1], XtNforeground, oldbg);
5638 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5642 wname = ModeToWidgetName(oldmode);
5643 if (wname != NULL) {
5644 XtSetArg(args[0], XtNleftBitmap, None);
5645 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5647 wname = ModeToWidgetName(gameMode);
5648 if (wname != NULL) {
5649 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5650 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5654 /* Maybe all the enables should be handled here, not just this one */
5655 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5656 gameMode == Training || gameMode == PlayFromGameFile);
5661 * Button/menu procedures
5663 void ResetProc(w, event, prms, nprms)
5672 int LoadGamePopUp(f, gameNumber, title)
5677 cmailMsgLoaded = FALSE;
5678 if (gameNumber == 0) {
5679 int error = GameListBuild(f);
5681 DisplayError(_("Cannot build game list"), error);
5682 } else if (!ListEmpty(&gameList) &&
5683 ((ListGame *) gameList.tailPred)->number > 1) {
5684 GameListPopUp(f, title);
5690 return LoadGame(f, gameNumber, title, FALSE);
5693 void LoadGameProc(w, event, prms, nprms)
5699 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5702 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5705 void LoadNextGameProc(w, event, prms, nprms)
5714 void LoadPrevGameProc(w, event, prms, nprms)
5723 void ReloadGameProc(w, event, prms, nprms)
5732 void LoadNextPositionProc(w, event, prms, nprms)
5741 void LoadPrevPositionProc(w, event, prms, nprms)
5750 void ReloadPositionProc(w, event, prms, nprms)
5759 void LoadPositionProc(w, event, prms, nprms)
5765 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5768 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5771 void SaveGameProc(w, event, prms, nprms)
5777 FileNamePopUp(_("Save game file name?"),
5778 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5782 void SavePositionProc(w, event, prms, nprms)
5788 FileNamePopUp(_("Save position file name?"),
5789 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5793 void ReloadCmailMsgProc(w, event, prms, nprms)
5799 ReloadCmailMsgEvent(FALSE);
5802 void MailMoveProc(w, event, prms, nprms)
5811 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5812 char *selected_fen_position=NULL;
5815 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5816 Atom *type_return, XtPointer *value_return,
5817 unsigned long *length_return, int *format_return)
5819 char *selection_tmp;
5821 if (!selected_fen_position) return False; /* should never happen */
5822 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5823 /* note: since no XtSelectionDoneProc was registered, Xt will
5824 * automatically call XtFree on the value returned. So have to
5825 * make a copy of it allocated with XtMalloc */
5826 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5827 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
5829 *value_return=selection_tmp;
5830 *length_return=strlen(selection_tmp);
5831 *type_return=*target;
5832 *format_return = 8; /* bits per byte */
5834 } else if (*target == XA_TARGETS(xDisplay)) {
5835 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5836 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5837 targets_tmp[1] = XA_STRING;
5838 *value_return = targets_tmp;
5839 *type_return = XA_ATOM;
5841 *format_return = 8 * sizeof(Atom);
5842 if (*format_return > 32) {
5843 *length_return *= *format_return / 32;
5844 *format_return = 32;
5852 /* note: when called from menu all parameters are NULL, so no clue what the
5853 * Widget which was clicked on was, or what the click event was
5855 void CopyPositionProc(w, event, prms, nprms)
5862 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5863 * have a notion of a position that is selected but not copied.
5864 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5866 if(gameMode == EditPosition) EditPositionDone(TRUE);
5867 if (selected_fen_position) free(selected_fen_position);
5868 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5869 if (!selected_fen_position) return;
5870 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5872 SendPositionSelection,
5873 NULL/* lose_ownership_proc */ ,
5874 NULL/* transfer_done_proc */);
5875 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5877 SendPositionSelection,
5878 NULL/* lose_ownership_proc */ ,
5879 NULL/* transfer_done_proc */);
5882 /* function called when the data to Paste is ready */
5884 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5885 Atom *type, XtPointer value, unsigned long *len, int *format)
5888 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5889 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5890 EditPositionPasteFEN(fenstr);
5894 /* called when Paste Position button is pressed,
5895 * all parameters will be NULL */
5896 void PastePositionProc(w, event, prms, nprms)
5902 XtGetSelectionValue(menuBarWidget,
5903 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5904 /* (XtSelectionCallbackProc) */ PastePositionCB,
5905 NULL, /* client_data passed to PastePositionCB */
5907 /* better to use the time field from the event that triggered the
5908 * call to this function, but that isn't trivial to get
5916 SendGameSelection(Widget w, Atom *selection, Atom *target,
5917 Atom *type_return, XtPointer *value_return,
5918 unsigned long *length_return, int *format_return)
5920 char *selection_tmp;
5922 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5923 FILE* f = fopen(gameCopyFilename, "r");
5926 if (f == NULL) return False;
5930 selection_tmp = XtMalloc(len + 1);
5931 count = fread(selection_tmp, 1, len, f);
5933 XtFree(selection_tmp);
5936 selection_tmp[len] = NULLCHAR;
5937 *value_return = selection_tmp;
5938 *length_return = len;
5939 *type_return = *target;
5940 *format_return = 8; /* bits per byte */
5942 } else if (*target == XA_TARGETS(xDisplay)) {
5943 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5944 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5945 targets_tmp[1] = XA_STRING;
5946 *value_return = targets_tmp;
5947 *type_return = XA_ATOM;
5949 *format_return = 8 * sizeof(Atom);
5950 if (*format_return > 32) {
5951 *length_return *= *format_return / 32;
5952 *format_return = 32;
5960 /* note: when called from menu all parameters are NULL, so no clue what the
5961 * Widget which was clicked on was, or what the click event was
5963 void CopyGameProc(w, event, prms, nprms)
5971 ret = SaveGameToFile(gameCopyFilename, FALSE);
5975 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5976 * have a notion of a game that is selected but not copied.
5977 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5979 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5982 NULL/* lose_ownership_proc */ ,
5983 NULL/* transfer_done_proc */);
5984 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5987 NULL/* lose_ownership_proc */ ,
5988 NULL/* transfer_done_proc */);
5991 /* function called when the data to Paste is ready */
5993 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5994 Atom *type, XtPointer value, unsigned long *len, int *format)
5997 if (value == NULL || *len == 0) {
5998 return; /* nothing had been selected to copy */
6000 f = fopen(gamePasteFilename, "w");
6002 DisplayError(_("Can't open temp file"), errno);
6005 fwrite(value, 1, *len, f);
6008 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
6011 /* called when Paste Game button is pressed,
6012 * all parameters will be NULL */
6013 void PasteGameProc(w, event, prms, nprms)
6019 XtGetSelectionValue(menuBarWidget,
6020 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
6021 /* (XtSelectionCallbackProc) */ PasteGameCB,
6022 NULL, /* client_data passed to PasteGameCB */
6024 /* better to use the time field from the event that triggered the
6025 * call to this function, but that isn't trivial to get
6035 SaveGameProc(NULL, NULL, NULL, NULL);
6039 void QuitProc(w, event, prms, nprms)
6048 void PauseProc(w, event, prms, nprms)
6058 void MachineBlackProc(w, event, prms, nprms)
6064 MachineBlackEvent();
6067 void MachineWhiteProc(w, event, prms, nprms)
6073 MachineWhiteEvent();
6076 void AnalyzeModeProc(w, event, prms, nprms)
6084 if (!first.analysisSupport) {
6085 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6086 DisplayError(buf, 0);
6089 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
6090 if (appData.icsActive) {
6091 if (gameMode != IcsObserving) {
6092 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
6093 DisplayError(buf, 0);
6095 if (appData.icsEngineAnalyze) {
6096 if (appData.debugMode)
6097 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
6103 /* if enable, use want disable icsEngineAnalyze */
6104 if (appData.icsEngineAnalyze) {
6109 appData.icsEngineAnalyze = TRUE;
6110 if (appData.debugMode)
6111 fprintf(debugFP, _("ICS engine analyze starting... \n"));
6113 if (!appData.showThinking)
6114 ShowThinkingProc(w,event,prms,nprms);
6119 void AnalyzeFileProc(w, event, prms, nprms)
6125 if (!first.analysisSupport) {
6127 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6128 DisplayError(buf, 0);
6133 if (!appData.showThinking)
6134 ShowThinkingProc(w,event,prms,nprms);
6137 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
6138 AnalysisPeriodicEvent(1);
6141 void TwoMachinesProc(w, event, prms, nprms)
6150 void IcsClientProc(w, event, prms, nprms)
6159 void EditGameProc(w, event, prms, nprms)
6168 void EditPositionProc(w, event, prms, nprms)
6174 EditPositionEvent();
6177 void TrainingProc(w, event, prms, nprms)
6186 void EditCommentProc(w, event, prms, nprms)
6193 EditCommentPopDown();
6199 void IcsInputBoxProc(w, event, prms, nprms)
6205 if (ICSInputBoxUp) {
6206 ICSInputBoxPopDown();
6212 void AcceptProc(w, event, prms, nprms)
6221 void DeclineProc(w, event, prms, nprms)
6230 void RematchProc(w, event, prms, nprms)
6239 void CallFlagProc(w, event, prms, nprms)
6248 void DrawProc(w, event, prms, nprms)
6257 void AbortProc(w, event, prms, nprms)
6266 void AdjournProc(w, event, prms, nprms)
6275 void ResignProc(w, event, prms, nprms)
6284 void AdjuWhiteProc(w, event, prms, nprms)
6290 UserAdjudicationEvent(+1);
6293 void AdjuBlackProc(w, event, prms, nprms)
6299 UserAdjudicationEvent(-1);
6302 void AdjuDrawProc(w, event, prms, nprms)
6308 UserAdjudicationEvent(0);
6311 void EnterKeyProc(w, event, prms, nprms)
6317 if (ICSInputBoxUp == True)
6321 void UpKeyProc(w, event, prms, nprms)
6326 { // [HGM] input: let up-arrow recall previous line from history
6333 if (!ICSInputBoxUp) return;
6334 edit = XtNameToWidget(ICSInputShell, "*form.text");
6336 XtSetArg(args[j], XtNstring, &val); j++;
6337 XtGetValues(edit, args, j);
6338 val = PrevInHistory(val);
6339 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6340 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6342 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6343 XawTextReplace(edit, 0, 0, &t);
6344 XawTextSetInsertionPoint(edit, 9999);
6348 void DownKeyProc(w, event, prms, nprms)
6353 { // [HGM] input: let down-arrow recall next line from history
6358 if (!ICSInputBoxUp) return;
6359 edit = XtNameToWidget(ICSInputShell, "*form.text");
6360 val = NextInHistory();
6361 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6362 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6364 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6365 XawTextReplace(edit, 0, 0, &t);
6366 XawTextSetInsertionPoint(edit, 9999);
6370 void StopObservingProc(w, event, prms, nprms)
6376 StopObservingEvent();
6379 void StopExaminingProc(w, event, prms, nprms)
6385 StopExaminingEvent();
6388 void UploadProc(w, event, prms, nprms)
6398 void ForwardProc(w, event, prms, nprms)
6408 void BackwardProc(w, event, prms, nprms)
6417 void ToStartProc(w, event, prms, nprms)
6426 void ToEndProc(w, event, prms, nprms)
6435 void RevertProc(w, event, prms, nprms)
6444 void AnnotateProc(w, event, prms, nprms)
6453 void TruncateGameProc(w, event, prms, nprms)
6459 TruncateGameEvent();
6461 void RetractMoveProc(w, event, prms, nprms)
6470 void MoveNowProc(w, event, prms, nprms)
6480 void AlwaysQueenProc(w, event, prms, nprms)
6488 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6490 if (appData.alwaysPromoteToQueen) {
6491 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6493 XtSetArg(args[0], XtNleftBitmap, None);
6495 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6499 void AnimateDraggingProc(w, event, prms, nprms)
6507 appData.animateDragging = !appData.animateDragging;
6509 if (appData.animateDragging) {
6510 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6513 XtSetArg(args[0], XtNleftBitmap, None);
6515 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6519 void AnimateMovingProc(w, event, prms, nprms)
6527 appData.animate = !appData.animate;
6529 if (appData.animate) {
6530 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6533 XtSetArg(args[0], XtNleftBitmap, None);
6535 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6539 void AutocommProc(w, event, prms, nprms)
6547 appData.autoComment = !appData.autoComment;
6549 if (appData.autoComment) {
6550 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6552 XtSetArg(args[0], XtNleftBitmap, None);
6554 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6559 void AutoflagProc(w, event, prms, nprms)
6567 appData.autoCallFlag = !appData.autoCallFlag;
6569 if (appData.autoCallFlag) {
6570 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6572 XtSetArg(args[0], XtNleftBitmap, None);
6574 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6578 void AutoflipProc(w, event, prms, nprms)
6586 appData.autoFlipView = !appData.autoFlipView;
6588 if (appData.autoFlipView) {
6589 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6591 XtSetArg(args[0], XtNleftBitmap, None);
6593 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6597 void AutobsProc(w, event, prms, nprms)
6605 appData.autoObserve = !appData.autoObserve;
6607 if (appData.autoObserve) {
6608 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6610 XtSetArg(args[0], XtNleftBitmap, None);
6612 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6616 void AutoraiseProc(w, event, prms, nprms)
6624 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6626 if (appData.autoRaiseBoard) {
6627 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6629 XtSetArg(args[0], XtNleftBitmap, None);
6631 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6635 void AutosaveProc(w, event, prms, nprms)
6643 appData.autoSaveGames = !appData.autoSaveGames;
6645 if (appData.autoSaveGames) {
6646 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6648 XtSetArg(args[0], XtNleftBitmap, None);
6650 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6654 void BlindfoldProc(w, event, prms, nprms)
6662 appData.blindfold = !appData.blindfold;
6664 if (appData.blindfold) {
6665 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6667 XtSetArg(args[0], XtNleftBitmap, None);
6669 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6672 DrawPosition(True, NULL);
6675 void TestLegalityProc(w, event, prms, nprms)
6683 appData.testLegality = !appData.testLegality;
6685 if (appData.testLegality) {
6686 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6688 XtSetArg(args[0], XtNleftBitmap, None);
6690 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6695 void FlashMovesProc(w, event, prms, nprms)
6703 if (appData.flashCount == 0) {
6704 appData.flashCount = 3;
6706 appData.flashCount = -appData.flashCount;
6709 if (appData.flashCount > 0) {
6710 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6712 XtSetArg(args[0], XtNleftBitmap, None);
6714 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6718 void FlipViewProc(w, event, prms, nprms)
6724 flipView = !flipView;
6725 DrawPosition(True, NULL);
6728 void GetMoveListProc(w, event, prms, nprms)
6736 appData.getMoveList = !appData.getMoveList;
6738 if (appData.getMoveList) {
6739 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6742 XtSetArg(args[0], XtNleftBitmap, None);
6744 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6749 void HighlightDraggingProc(w, event, prms, nprms)
6757 appData.highlightDragging = !appData.highlightDragging;
6759 if (appData.highlightDragging) {
6760 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6762 XtSetArg(args[0], XtNleftBitmap, None);
6764 XtSetValues(XtNameToWidget(menuBarWidget,
6765 "menuOptions.Highlight Dragging"), args, 1);
6769 void HighlightLastMoveProc(w, event, prms, nprms)
6777 appData.highlightLastMove = !appData.highlightLastMove;
6779 if (appData.highlightLastMove) {
6780 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6782 XtSetArg(args[0], XtNleftBitmap, None);
6784 XtSetValues(XtNameToWidget(menuBarWidget,
6785 "menuOptions.Highlight Last Move"), args, 1);
6788 void IcsAlarmProc(w, event, prms, nprms)
6796 appData.icsAlarm = !appData.icsAlarm;
6798 if (appData.icsAlarm) {
6799 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6801 XtSetArg(args[0], XtNleftBitmap, None);
6803 XtSetValues(XtNameToWidget(menuBarWidget,
6804 "menuOptions.ICS Alarm"), args, 1);
6807 void MoveSoundProc(w, event, prms, nprms)
6815 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6817 if (appData.ringBellAfterMoves) {
6818 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6820 XtSetArg(args[0], XtNleftBitmap, None);
6822 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6827 void OldSaveStyleProc(w, event, prms, nprms)
6835 appData.oldSaveStyle = !appData.oldSaveStyle;
6837 if (appData.oldSaveStyle) {
6838 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6840 XtSetArg(args[0], XtNleftBitmap, None);
6842 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6846 void PeriodicUpdatesProc(w, event, prms, nprms)
6854 PeriodicUpdatesEvent(!appData.periodicUpdates);
6856 if (appData.periodicUpdates) {
6857 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6859 XtSetArg(args[0], XtNleftBitmap, None);
6861 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6865 void PonderNextMoveProc(w, event, prms, nprms)
6873 PonderNextMoveEvent(!appData.ponderNextMove);
6875 if (appData.ponderNextMove) {
6876 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6878 XtSetArg(args[0], XtNleftBitmap, None);
6880 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6884 void PopupExitMessageProc(w, event, prms, nprms)
6892 appData.popupExitMessage = !appData.popupExitMessage;
6894 if (appData.popupExitMessage) {
6895 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6897 XtSetArg(args[0], XtNleftBitmap, None);
6899 XtSetValues(XtNameToWidget(menuBarWidget,
6900 "menuOptions.Popup Exit Message"), args, 1);
6903 void PopupMoveErrorsProc(w, event, prms, nprms)
6911 appData.popupMoveErrors = !appData.popupMoveErrors;
6913 if (appData.popupMoveErrors) {
6914 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6916 XtSetArg(args[0], XtNleftBitmap, None);
6918 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6922 void PremoveProc(w, event, prms, nprms)
6930 appData.premove = !appData.premove;
6932 if (appData.premove) {
6933 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6935 XtSetArg(args[0], XtNleftBitmap, None);
6937 XtSetValues(XtNameToWidget(menuBarWidget,
6938 "menuOptions.Premove"), args, 1);
6941 void QuietPlayProc(w, event, prms, nprms)
6949 appData.quietPlay = !appData.quietPlay;
6951 if (appData.quietPlay) {
6952 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6954 XtSetArg(args[0], XtNleftBitmap, None);
6956 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6960 void ShowCoordsProc(w, event, prms, nprms)
6968 appData.showCoords = !appData.showCoords;
6970 if (appData.showCoords) {
6971 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6973 XtSetArg(args[0], XtNleftBitmap, None);
6975 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6978 DrawPosition(True, NULL);
6981 void ShowThinkingProc(w, event, prms, nprms)
6987 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6988 ShowThinkingEvent();
6991 void HideThinkingProc(w, event, prms, nprms)
6999 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
7000 ShowThinkingEvent();
7002 if (appData.hideThinkingFromHuman) {
7003 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
7005 XtSetArg(args[0], XtNleftBitmap, None);
7007 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
7011 void SaveOnExitProc(w, event, prms, nprms)
7019 saveSettingsOnExit = !saveSettingsOnExit;
7021 if (saveSettingsOnExit) {
7022 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
7024 XtSetArg(args[0], XtNleftBitmap, None);
7026 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
7030 void SaveSettingsProc(w, event, prms, nprms)
7036 SaveSettings(settingsFileName);
7039 void InfoProc(w, event, prms, nprms)
7046 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
7051 void ManProc(w, event, prms, nprms)
7059 if (nprms && *nprms > 0)
7063 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
7067 void HintProc(w, event, prms, nprms)
7076 void BookProc(w, event, prms, nprms)
7085 void AboutProc(w, event, prms, nprms)
7093 char *zippy = " (with Zippy code)";
7097 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
7098 programVersion, zippy,
7099 "Copyright 1991 Digital Equipment Corporation",
7100 "Enhancements Copyright 1992-2009 Free Software Foundation",
7101 "Enhancements Copyright 2005 Alessandro Scotti",
7102 PACKAGE, " is free software and carries NO WARRANTY;",
7103 "see the file COPYING for more information.");
7104 ErrorPopUp(_("About XBoard"), buf, FALSE);
7107 void DebugProc(w, event, prms, nprms)
7113 appData.debugMode = !appData.debugMode;
7116 void AboutGameProc(w, event, prms, nprms)
7125 void NothingProc(w, event, prms, nprms)
7134 void Iconify(w, event, prms, nprms)
7143 XtSetArg(args[0], XtNiconic, True);
7144 XtSetValues(shellWidget, args, 1);
7147 void DisplayMessage(message, extMessage)
7148 char *message, *extMessage;
7150 /* display a message in the message widget */
7159 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
7164 message = extMessage;
7168 /* need to test if messageWidget already exists, since this function
7169 can also be called during the startup, if for example a Xresource
7170 is not set up correctly */
7173 XtSetArg(arg, XtNlabel, message);
7174 XtSetValues(messageWidget, &arg, 1);
7180 void DisplayTitle(text)
7185 char title[MSG_SIZ];
7188 if (text == NULL) text = "";
7190 if (appData.titleInWindow) {
7192 XtSetArg(args[i], XtNlabel, text); i++;
7193 XtSetValues(titleWidget, args, i);
7196 if (*text != NULLCHAR) {
7197 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
7198 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
7199 } else if (appData.icsActive) {
7200 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7201 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7202 } else if (appData.cmailGameName[0] != NULLCHAR) {
7203 snprintf(icon, sizeof(icon), "%s", "CMail");
7204 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7206 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7207 } else if (gameInfo.variant == VariantGothic) {
7208 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7209 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
7212 } else if (gameInfo.variant == VariantFalcon) {
7213 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7214 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
7216 } else if (appData.noChessProgram) {
7217 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7218 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
7220 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
7221 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7224 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7225 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7226 XtSetValues(shellWidget, args, i);
7231 DisplayError(message, error)
7238 if (appData.debugMode || appData.matchMode) {
7239 fprintf(stderr, "%s: %s\n", programName, message);
7242 if (appData.debugMode || appData.matchMode) {
7243 fprintf(stderr, "%s: %s: %s\n",
7244 programName, message, strerror(error));
7246 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7249 ErrorPopUp(_("Error"), message, FALSE);
7253 void DisplayMoveError(message)
7258 DrawPosition(FALSE, NULL);
7259 if (appData.debugMode || appData.matchMode) {
7260 fprintf(stderr, "%s: %s\n", programName, message);
7262 if (appData.popupMoveErrors) {
7263 ErrorPopUp(_("Error"), message, FALSE);
7265 DisplayMessage(message, "");
7270 void DisplayFatalError(message, error, status)
7276 errorExitStatus = status;
7278 fprintf(stderr, "%s: %s\n", programName, message);
7280 fprintf(stderr, "%s: %s: %s\n",
7281 programName, message, strerror(error));
7282 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7285 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7286 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7292 void DisplayInformation(message)
7296 ErrorPopUp(_("Information"), message, TRUE);
7299 void DisplayNote(message)
7303 ErrorPopUp(_("Note"), message, FALSE);
7307 NullXErrorCheck(dpy, error_event)
7309 XErrorEvent *error_event;
7314 void DisplayIcsInteractionTitle(message)
7317 if (oldICSInteractionTitle == NULL) {
7318 /* Magic to find the old window title, adapted from vim */
7319 char *wina = getenv("WINDOWID");
7321 Window win = (Window) atoi(wina);
7322 Window root, parent, *children;
7323 unsigned int nchildren;
7324 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7326 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7327 if (!XQueryTree(xDisplay, win, &root, &parent,
7328 &children, &nchildren)) break;
7329 if (children) XFree((void *)children);
7330 if (parent == root || parent == 0) break;
7333 XSetErrorHandler(oldHandler);
7335 if (oldICSInteractionTitle == NULL) {
7336 oldICSInteractionTitle = "xterm";
7339 printf("\033]0;%s\007", message);
7343 char pendingReplyPrefix[MSG_SIZ];
7344 ProcRef pendingReplyPR;
7346 void AskQuestionProc(w, event, prms, nprms)
7353 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7357 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7360 void AskQuestionPopDown()
7362 if (!askQuestionUp) return;
7363 XtPopdown(askQuestionShell);
7364 XtDestroyWidget(askQuestionShell);
7365 askQuestionUp = False;
7368 void AskQuestionReplyAction(w, event, prms, nprms)
7378 reply = XawDialogGetValueString(w = XtParent(w));
7379 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
7380 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
7381 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
7382 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
7383 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7384 AskQuestionPopDown();
7386 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7389 void AskQuestionCallback(w, client_data, call_data)
7391 XtPointer client_data, call_data;
7396 XtSetArg(args[0], XtNlabel, &name);
7397 XtGetValues(w, args, 1);
7399 if (strcmp(name, _("cancel")) == 0) {
7400 AskQuestionPopDown();
7402 AskQuestionReplyAction(w, NULL, NULL, NULL);
7406 void AskQuestion(title, question, replyPrefix, pr)
7407 char *title, *question, *replyPrefix;
7411 Widget popup, layout, dialog, edit;
7417 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
7418 pendingReplyPR = pr;
7421 XtSetArg(args[i], XtNresizable, True); i++;
7422 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7423 askQuestionShell = popup =
7424 XtCreatePopupShell(title, transientShellWidgetClass,
7425 shellWidget, args, i);
7428 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7429 layoutArgs, XtNumber(layoutArgs));
7432 XtSetArg(args[i], XtNlabel, question); i++;
7433 XtSetArg(args[i], XtNvalue, ""); i++;
7434 XtSetArg(args[i], XtNborderWidth, 0); i++;
7435 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7438 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7439 (XtPointer) dialog);
7440 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7441 (XtPointer) dialog);
7443 XtRealizeWidget(popup);
7444 CatchDeleteWindow(popup, "AskQuestionPopDown");
7446 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7447 &x, &y, &win_x, &win_y, &mask);
7449 XtSetArg(args[0], XtNx, x - 10);
7450 XtSetArg(args[1], XtNy, y - 30);
7451 XtSetValues(popup, args, 2);
7453 XtPopup(popup, XtGrabExclusive);
7454 askQuestionUp = True;
7456 edit = XtNameToWidget(dialog, "*value");
7457 XtSetKeyboardFocus(popup, edit);
7465 if (*name == NULLCHAR) {
7467 } else if (strcmp(name, "$") == 0) {
7468 putc(BELLCHAR, stderr);
7471 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7479 PlaySound(appData.soundMove);
7485 PlaySound(appData.soundIcsWin);
7491 PlaySound(appData.soundIcsLoss);
7497 PlaySound(appData.soundIcsDraw);
7501 PlayIcsUnfinishedSound()
7503 PlaySound(appData.soundIcsUnfinished);
7509 PlaySound(appData.soundIcsAlarm);
7515 system("stty echo");
7521 system("stty -echo");
7525 Colorize(cc, continuation)
7530 int count, outCount, error;
7532 if (textColors[(int)cc].bg > 0) {
7533 if (textColors[(int)cc].fg > 0) {
7534 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7535 textColors[(int)cc].fg, textColors[(int)cc].bg);
7537 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7538 textColors[(int)cc].bg);
7541 if (textColors[(int)cc].fg > 0) {
7542 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7543 textColors[(int)cc].fg);
7545 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7548 count = strlen(buf);
7549 outCount = OutputToProcess(NoProc, buf, count, &error);
7550 if (outCount < count) {
7551 DisplayFatalError(_("Error writing to display"), error, 1);
7554 if (continuation) return;
7557 PlaySound(appData.soundShout);
7560 PlaySound(appData.soundSShout);
7563 PlaySound(appData.soundChannel1);
7566 PlaySound(appData.soundChannel);
7569 PlaySound(appData.soundKibitz);
7572 PlaySound(appData.soundTell);
7574 case ColorChallenge:
7575 PlaySound(appData.soundChallenge);
7578 PlaySound(appData.soundRequest);
7581 PlaySound(appData.soundSeek);
7592 return getpwuid(getuid())->pw_name;
7596 ExpandPathName(path)
7599 static char static_buf[4*MSG_SIZ];
7600 char *d, *s, buf[4*MSG_SIZ];
7606 while (*s && isspace(*s))
7615 if (*(s+1) == '/') {
7616 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7620 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7621 { char *p; if(p = strchr(buf, '/')) *p = 0; }
7622 pwd = getpwnam(buf);
7625 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7629 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7630 strcat(d, strchr(s+1, '/'));
7634 safeStrCpy(d, s, 4*MSG_SIZ );
7641 static char host_name[MSG_SIZ];
7643 #if HAVE_GETHOSTNAME
7644 gethostname(host_name, MSG_SIZ);
7646 #else /* not HAVE_GETHOSTNAME */
7647 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7648 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7650 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7652 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7653 #endif /* not HAVE_GETHOSTNAME */
7656 XtIntervalId delayedEventTimerXID = 0;
7657 DelayedEventCallback delayedEventCallback = 0;
7662 delayedEventTimerXID = 0;
7663 delayedEventCallback();
7667 ScheduleDelayedEvent(cb, millisec)
7668 DelayedEventCallback cb; long millisec;
7670 if(delayedEventTimerXID && delayedEventCallback == cb)
7671 // [HGM] alive: replace, rather than add or flush identical event
7672 XtRemoveTimeOut(delayedEventTimerXID);
7673 delayedEventCallback = cb;
7674 delayedEventTimerXID =
7675 XtAppAddTimeOut(appContext, millisec,
7676 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7679 DelayedEventCallback
7682 if (delayedEventTimerXID) {
7683 return delayedEventCallback;
7690 CancelDelayedEvent()
7692 if (delayedEventTimerXID) {
7693 XtRemoveTimeOut(delayedEventTimerXID);
7694 delayedEventTimerXID = 0;
7698 XtIntervalId loadGameTimerXID = 0;
7700 int LoadGameTimerRunning()
7702 return loadGameTimerXID != 0;
7705 int StopLoadGameTimer()
7707 if (loadGameTimerXID != 0) {
7708 XtRemoveTimeOut(loadGameTimerXID);
7709 loadGameTimerXID = 0;
7717 LoadGameTimerCallback(arg, id)
7721 loadGameTimerXID = 0;
7726 StartLoadGameTimer(millisec)
7730 XtAppAddTimeOut(appContext, millisec,
7731 (XtTimerCallbackProc) LoadGameTimerCallback,
7735 XtIntervalId analysisClockXID = 0;
7738 AnalysisClockCallback(arg, id)
7742 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7743 || appData.icsEngineAnalyze) { // [DM]
7744 AnalysisPeriodicEvent(0);
7745 StartAnalysisClock();
7750 StartAnalysisClock()
7753 XtAppAddTimeOut(appContext, 2000,
7754 (XtTimerCallbackProc) AnalysisClockCallback,
7758 XtIntervalId clockTimerXID = 0;
7760 int ClockTimerRunning()
7762 return clockTimerXID != 0;
7765 int StopClockTimer()
7767 if (clockTimerXID != 0) {
7768 XtRemoveTimeOut(clockTimerXID);
7777 ClockTimerCallback(arg, id)
7786 StartClockTimer(millisec)
7790 XtAppAddTimeOut(appContext, millisec,
7791 (XtTimerCallbackProc) ClockTimerCallback,
7796 DisplayTimerLabel(w, color, timer, highlight)
7805 /* check for low time warning */
7806 Pixel foregroundOrWarningColor = timerForegroundPixel;
7809 appData.lowTimeWarning &&
7810 (timer / 1000) < appData.icsAlarmTime)
7811 foregroundOrWarningColor = lowTimeWarningColor;
7813 if (appData.clockMode) {
7814 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7815 XtSetArg(args[0], XtNlabel, buf);
7817 snprintf(buf, MSG_SIZ, "%s ", color);
7818 XtSetArg(args[0], XtNlabel, buf);
7823 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7824 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7826 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7827 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7830 XtSetValues(w, args, 3);
7834 DisplayWhiteClock(timeRemaining, highlight)
7840 if(appData.noGUI) return;
7841 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7842 if (highlight && iconPixmap == bIconPixmap) {
7843 iconPixmap = wIconPixmap;
7844 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7845 XtSetValues(shellWidget, args, 1);
7850 DisplayBlackClock(timeRemaining, highlight)
7856 if(appData.noGUI) return;
7857 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7858 if (highlight && iconPixmap == wIconPixmap) {
7859 iconPixmap = bIconPixmap;
7860 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7861 XtSetValues(shellWidget, args, 1);
7879 int StartChildProcess(cmdLine, dir, pr)
7886 int to_prog[2], from_prog[2];
7890 if (appData.debugMode) {
7891 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7894 /* We do NOT feed the cmdLine to the shell; we just
7895 parse it into blank-separated arguments in the
7896 most simple-minded way possible.
7899 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7902 while(*p == ' ') p++;
7904 if(*p == '"' || *p == '\'')
7905 p = strchr(++argv[i-1], *p);
7906 else p = strchr(p, ' ');
7907 if (p == NULL) break;
7912 SetUpChildIO(to_prog, from_prog);
7914 if ((pid = fork()) == 0) {
7916 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7917 close(to_prog[1]); // first close the unused pipe ends
7918 close(from_prog[0]);
7919 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7920 dup2(from_prog[1], 1);
7921 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7922 close(from_prog[1]); // and closing again loses one of the pipes!
7923 if(fileno(stderr) >= 2) // better safe than sorry...
7924 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7926 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7931 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7933 execvp(argv[0], argv);
7935 /* If we get here, exec failed */
7940 /* Parent process */
7942 close(from_prog[1]);
7944 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7947 cp->fdFrom = from_prog[0];
7948 cp->fdTo = to_prog[1];
7953 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7954 static RETSIGTYPE AlarmCallBack(int n)
7960 DestroyChildProcess(pr, signalType)
7964 ChildProc *cp = (ChildProc *) pr;
7966 if (cp->kind != CPReal) return;
7968 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7969 signal(SIGALRM, AlarmCallBack);
7971 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7972 kill(cp->pid, SIGKILL); // kill it forcefully
7973 wait((int *) 0); // and wait again
7977 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7979 /* Process is exiting either because of the kill or because of
7980 a quit command sent by the backend; either way, wait for it to die.
7989 InterruptChildProcess(pr)
7992 ChildProc *cp = (ChildProc *) pr;
7994 if (cp->kind != CPReal) return;
7995 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7998 int OpenTelnet(host, port, pr)
8003 char cmdLine[MSG_SIZ];
8005 if (port[0] == NULLCHAR) {
8006 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
8008 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
8010 return StartChildProcess(cmdLine, "", pr);
8013 int OpenTCP(host, port, pr)
8019 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
8020 #else /* !OMIT_SOCKETS */
8022 struct sockaddr_in sa;
8024 unsigned short uport;
8027 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
8031 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
8032 sa.sin_family = AF_INET;
8033 sa.sin_addr.s_addr = INADDR_ANY;
8034 uport = (unsigned short) 0;
8035 sa.sin_port = htons(uport);
8036 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
8040 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
8041 if (!(hp = gethostbyname(host))) {
8043 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
8044 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
8045 hp->h_addrtype = AF_INET;
8047 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
8048 hp->h_addr_list[0] = (char *) malloc(4);
8049 hp->h_addr_list[0][0] = b0;
8050 hp->h_addr_list[0][1] = b1;
8051 hp->h_addr_list[0][2] = b2;
8052 hp->h_addr_list[0][3] = b3;
8057 sa.sin_family = hp->h_addrtype;
8058 uport = (unsigned short) atoi(port);
8059 sa.sin_port = htons(uport);
8060 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
8062 if (connect(s, (struct sockaddr *) &sa,
8063 sizeof(struct sockaddr_in)) < 0) {
8067 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8074 #endif /* !OMIT_SOCKETS */
8079 int OpenCommPort(name, pr)
8086 fd = open(name, 2, 0);
8087 if (fd < 0) return errno;
8089 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8099 int OpenLoopback(pr)
8105 SetUpChildIO(to, from);
8107 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8110 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
8117 int OpenRcmd(host, user, cmd, pr)
8118 char *host, *user, *cmd;
8121 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
8125 #define INPUT_SOURCE_BUF_SIZE 8192
8134 char buf[INPUT_SOURCE_BUF_SIZE];
8139 DoInputCallback(closure, source, xid)
8144 InputSource *is = (InputSource *) closure;
8149 if (is->lineByLine) {
8150 count = read(is->fd, is->unused,
8151 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
8153 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
8156 is->unused += count;
8158 while (p < is->unused) {
8159 q = memchr(p, '\n', is->unused - p);
8160 if (q == NULL) break;
8162 (is->func)(is, is->closure, p, q - p, 0);
8166 while (p < is->unused) {
8171 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8176 (is->func)(is, is->closure, is->buf, count, error);
8180 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8187 ChildProc *cp = (ChildProc *) pr;
8189 is = (InputSource *) calloc(1, sizeof(InputSource));
8190 is->lineByLine = lineByLine;
8194 is->fd = fileno(stdin);
8196 is->kind = cp->kind;
8197 is->fd = cp->fdFrom;
8200 is->unused = is->buf;
8203 is->xid = XtAppAddInput(appContext, is->fd,
8204 (XtPointer) (XtInputReadMask),
8205 (XtInputCallbackProc) DoInputCallback,
8207 is->closure = closure;
8208 return (InputSourceRef) is;
8212 RemoveInputSource(isr)
8215 InputSource *is = (InputSource *) isr;
8217 if (is->xid == 0) return;
8218 XtRemoveInput(is->xid);
8222 int OutputToProcess(pr, message, count, outError)
8228 static int line = 0;
8229 ChildProc *cp = (ChildProc *) pr;
8234 if (appData.noJoin || !appData.useInternalWrap)
8235 outCount = fwrite(message, 1, count, stdout);
8238 int width = get_term_width();
8239 int len = wrap(NULL, message, count, width, &line);
8240 char *msg = malloc(len);
8244 outCount = fwrite(message, 1, count, stdout);
8247 dbgchk = wrap(msg, message, count, width, &line);
8248 if (dbgchk != len && appData.debugMode)
8249 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8250 outCount = fwrite(msg, 1, dbgchk, stdout);
8256 outCount = write(cp->fdTo, message, count);
8266 /* Output message to process, with "ms" milliseconds of delay
8267 between each character. This is needed when sending the logon
8268 script to ICC, which for some reason doesn't like the
8269 instantaneous send. */
8270 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8277 ChildProc *cp = (ChildProc *) pr;
8282 r = write(cp->fdTo, message++, 1);
8295 /**** Animation code by Hugh Fisher, DCS, ANU.
8297 Known problem: if a window overlapping the board is
8298 moved away while a piece is being animated underneath,
8299 the newly exposed area won't be updated properly.
8300 I can live with this.
8302 Known problem: if you look carefully at the animation
8303 of pieces in mono mode, they are being drawn as solid
8304 shapes without interior detail while moving. Fixing
8305 this would be a major complication for minimal return.
8308 /* Masks for XPM pieces. Black and white pieces can have
8309 different shapes, but in the interest of retaining my
8310 sanity pieces must have the same outline on both light
8311 and dark squares, and all pieces must use the same
8312 background square colors/images. */
8314 static int xpmDone = 0;
8317 CreateAnimMasks (pieceDepth)
8324 unsigned long plane;
8327 /* Need a bitmap just to get a GC with right depth */
8328 buf = XCreatePixmap(xDisplay, xBoardWindow,
8330 values.foreground = 1;
8331 values.background = 0;
8332 /* Don't use XtGetGC, not read only */
8333 maskGC = XCreateGC(xDisplay, buf,
8334 GCForeground | GCBackground, &values);
8335 XFreePixmap(xDisplay, buf);
8337 buf = XCreatePixmap(xDisplay, xBoardWindow,
8338 squareSize, squareSize, pieceDepth);
8339 values.foreground = XBlackPixel(xDisplay, xScreen);
8340 values.background = XWhitePixel(xDisplay, xScreen);
8341 bufGC = XCreateGC(xDisplay, buf,
8342 GCForeground | GCBackground, &values);
8344 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8345 /* Begin with empty mask */
8346 if(!xpmDone) // [HGM] pieces: keep using existing
8347 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8348 squareSize, squareSize, 1);
8349 XSetFunction(xDisplay, maskGC, GXclear);
8350 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8351 0, 0, squareSize, squareSize);
8353 /* Take a copy of the piece */
8358 XSetFunction(xDisplay, bufGC, GXcopy);
8359 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8361 0, 0, squareSize, squareSize, 0, 0);
8363 /* XOR the background (light) over the piece */
8364 XSetFunction(xDisplay, bufGC, GXxor);
8366 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8367 0, 0, squareSize, squareSize, 0, 0);
8369 XSetForeground(xDisplay, bufGC, lightSquareColor);
8370 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8373 /* We now have an inverted piece image with the background
8374 erased. Construct mask by just selecting all the non-zero
8375 pixels - no need to reconstruct the original image. */
8376 XSetFunction(xDisplay, maskGC, GXor);
8378 /* Might be quicker to download an XImage and create bitmap
8379 data from it rather than this N copies per piece, but it
8380 only takes a fraction of a second and there is a much
8381 longer delay for loading the pieces. */
8382 for (n = 0; n < pieceDepth; n ++) {
8383 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8384 0, 0, squareSize, squareSize,
8390 XFreePixmap(xDisplay, buf);
8391 XFreeGC(xDisplay, bufGC);
8392 XFreeGC(xDisplay, maskGC);
8396 InitAnimState (anim, info)
8398 XWindowAttributes * info;
8403 /* Each buffer is square size, same depth as window */
8404 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8405 squareSize, squareSize, info->depth);
8406 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8407 squareSize, squareSize, info->depth);
8409 /* Create a plain GC for blitting */
8410 mask = GCForeground | GCBackground | GCFunction |
8411 GCPlaneMask | GCGraphicsExposures;
8412 values.foreground = XBlackPixel(xDisplay, xScreen);
8413 values.background = XWhitePixel(xDisplay, xScreen);
8414 values.function = GXcopy;
8415 values.plane_mask = AllPlanes;
8416 values.graphics_exposures = False;
8417 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8419 /* Piece will be copied from an existing context at
8420 the start of each new animation/drag. */
8421 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8423 /* Outline will be a read-only copy of an existing */
8424 anim->outlineGC = None;
8430 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8431 XWindowAttributes info;
8433 if (xpmDone && gameInfo.variant == old) return;
8434 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8435 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8437 InitAnimState(&game, &info);
8438 InitAnimState(&player, &info);
8440 /* For XPM pieces, we need bitmaps to use as masks. */
8442 CreateAnimMasks(info.depth);
8448 static Boolean frameWaiting;
8450 static RETSIGTYPE FrameAlarm (sig)
8453 frameWaiting = False;
8454 /* In case System-V style signals. Needed?? */
8455 signal(SIGALRM, FrameAlarm);
8462 struct itimerval delay;
8464 XSync(xDisplay, False);
8467 frameWaiting = True;
8468 signal(SIGALRM, FrameAlarm);
8469 delay.it_interval.tv_sec =
8470 delay.it_value.tv_sec = time / 1000;
8471 delay.it_interval.tv_usec =
8472 delay.it_value.tv_usec = (time % 1000) * 1000;
8473 setitimer(ITIMER_REAL, &delay, NULL);
8474 while (frameWaiting) pause();
8475 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8476 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8477 setitimer(ITIMER_REAL, &delay, NULL);
8487 XSync(xDisplay, False);
8489 usleep(time * 1000);
8494 /* Convert board position to corner of screen rect and color */
8497 ScreenSquare(column, row, pt, color)
8498 int column; int row; XPoint * pt; int * color;
8501 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8502 pt->y = lineGap + row * (squareSize + lineGap);
8504 pt->x = lineGap + column * (squareSize + lineGap);
8505 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8507 *color = SquareColor(row, column);
8510 /* Convert window coords to square */
8513 BoardSquare(x, y, column, row)
8514 int x; int y; int * column; int * row;
8516 *column = EventToSquare(x, BOARD_WIDTH);
8517 if (flipView && *column >= 0)
8518 *column = BOARD_WIDTH - 1 - *column;
8519 *row = EventToSquare(y, BOARD_HEIGHT);
8520 if (!flipView && *row >= 0)
8521 *row = BOARD_HEIGHT - 1 - *row;
8526 #undef Max /* just in case */
8528 #define Max(a, b) ((a) > (b) ? (a) : (b))
8529 #define Min(a, b) ((a) < (b) ? (a) : (b))
8532 SetRect(rect, x, y, width, height)
8533 XRectangle * rect; int x; int y; int width; int height;
8537 rect->width = width;
8538 rect->height = height;
8541 /* Test if two frames overlap. If they do, return
8542 intersection rect within old and location of
8543 that rect within new. */
8546 Intersect(old, new, size, area, pt)
8547 XPoint * old; XPoint * new;
8548 int size; XRectangle * area; XPoint * pt;
8550 if (old->x > new->x + size || new->x > old->x + size ||
8551 old->y > new->y + size || new->y > old->y + size) {
8554 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8555 size - abs(old->x - new->x), size - abs(old->y - new->y));
8556 pt->x = Max(old->x - new->x, 0);
8557 pt->y = Max(old->y - new->y, 0);
8562 /* For two overlapping frames, return the rect(s)
8563 in the old that do not intersect with the new. */
8566 CalcUpdateRects(old, new, size, update, nUpdates)
8567 XPoint * old; XPoint * new; int size;
8568 XRectangle update[]; int * nUpdates;
8572 /* If old = new (shouldn't happen) then nothing to draw */
8573 if (old->x == new->x && old->y == new->y) {
8577 /* Work out what bits overlap. Since we know the rects
8578 are the same size we don't need a full intersect calc. */
8580 /* Top or bottom edge? */
8581 if (new->y > old->y) {
8582 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8584 } else if (old->y > new->y) {
8585 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8586 size, old->y - new->y);
8589 /* Left or right edge - don't overlap any update calculated above. */
8590 if (new->x > old->x) {
8591 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8592 new->x - old->x, size - abs(new->y - old->y));
8594 } else if (old->x > new->x) {
8595 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8596 old->x - new->x, size - abs(new->y - old->y));
8603 /* Generate a series of frame coords from start->mid->finish.
8604 The movement rate doubles until the half way point is
8605 reached, then halves back down to the final destination,
8606 which gives a nice slow in/out effect. The algorithmn
8607 may seem to generate too many intermediates for short
8608 moves, but remember that the purpose is to attract the
8609 viewers attention to the piece about to be moved and
8610 then to where it ends up. Too few frames would be less
8614 Tween(start, mid, finish, factor, frames, nFrames)
8615 XPoint * start; XPoint * mid;
8616 XPoint * finish; int factor;
8617 XPoint frames[]; int * nFrames;
8619 int fraction, n, count;
8623 /* Slow in, stepping 1/16th, then 1/8th, ... */
8625 for (n = 0; n < factor; n++)
8627 for (n = 0; n < factor; n++) {
8628 frames[count].x = start->x + (mid->x - start->x) / fraction;
8629 frames[count].y = start->y + (mid->y - start->y) / fraction;
8631 fraction = fraction / 2;
8635 frames[count] = *mid;
8638 /* Slow out, stepping 1/2, then 1/4, ... */
8640 for (n = 0; n < factor; n++) {
8641 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8642 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8644 fraction = fraction * 2;
8649 /* Draw a piece on the screen without disturbing what's there */
8652 SelectGCMask(piece, clip, outline, mask)
8653 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8657 /* Bitmap for piece being moved. */
8658 if (appData.monoMode) {
8659 *mask = *pieceToSolid(piece);
8660 } else if (useImages) {
8662 *mask = xpmMask[piece];
8664 *mask = ximMaskPm[piece];
8667 *mask = *pieceToSolid(piece);
8670 /* GC for piece being moved. Square color doesn't matter, but
8671 since it gets modified we make a copy of the original. */
8673 if (appData.monoMode)
8678 if (appData.monoMode)
8683 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8685 /* Outline only used in mono mode and is not modified */
8687 *outline = bwPieceGC;
8689 *outline = wbPieceGC;
8693 OverlayPiece(piece, clip, outline, dest)
8694 ChessSquare piece; GC clip; GC outline; Drawable dest;
8699 /* Draw solid rectangle which will be clipped to shape of piece */
8700 XFillRectangle(xDisplay, dest, clip,
8701 0, 0, squareSize, squareSize);
8702 if (appData.monoMode)
8703 /* Also draw outline in contrasting color for black
8704 on black / white on white cases */
8705 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8706 0, 0, squareSize, squareSize, 0, 0, 1);
8708 /* Copy the piece */
8713 if(appData.upsideDown && flipView) kind ^= 2;
8714 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8716 0, 0, squareSize, squareSize,
8721 /* Animate the movement of a single piece */
8724 BeginAnimation(anim, piece, startColor, start)
8732 /* The old buffer is initialised with the start square (empty) */
8733 BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0);
8734 anim->prevFrame = *start;
8736 /* The piece will be drawn using its own bitmap as a matte */
8737 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8738 XSetClipMask(xDisplay, anim->pieceGC, mask);
8742 AnimationFrame(anim, frame, piece)
8747 XRectangle updates[4];
8752 /* Save what we are about to draw into the new buffer */
8753 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8754 frame->x, frame->y, squareSize, squareSize,
8757 /* Erase bits of the previous frame */
8758 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8759 /* Where the new frame overlapped the previous,
8760 the contents in newBuf are wrong. */
8761 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8762 overlap.x, overlap.y,
8763 overlap.width, overlap.height,
8765 /* Repaint the areas in the old that don't overlap new */
8766 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8767 for (i = 0; i < count; i++)
8768 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8769 updates[i].x - anim->prevFrame.x,
8770 updates[i].y - anim->prevFrame.y,
8771 updates[i].width, updates[i].height,
8772 updates[i].x, updates[i].y);
8774 /* Easy when no overlap */
8775 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8776 0, 0, squareSize, squareSize,
8777 anim->prevFrame.x, anim->prevFrame.y);
8780 /* Save this frame for next time round */
8781 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8782 0, 0, squareSize, squareSize,
8784 anim->prevFrame = *frame;
8786 /* Draw piece over original screen contents, not current,
8787 and copy entire rect. Wipes out overlapping piece images. */
8788 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8789 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8790 0, 0, squareSize, squareSize,
8791 frame->x, frame->y);
8795 EndAnimation (anim, finish)
8799 XRectangle updates[4];
8804 /* The main code will redraw the final square, so we
8805 only need to erase the bits that don't overlap. */
8806 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8807 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8808 for (i = 0; i < count; i++)
8809 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8810 updates[i].x - anim->prevFrame.x,
8811 updates[i].y - anim->prevFrame.y,
8812 updates[i].width, updates[i].height,
8813 updates[i].x, updates[i].y);
8815 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8816 0, 0, squareSize, squareSize,
8817 anim->prevFrame.x, anim->prevFrame.y);
8822 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8824 ChessSquare piece; int startColor;
8825 XPoint * start; XPoint * finish;
8826 XPoint frames[]; int nFrames;
8830 BeginAnimation(anim, piece, startColor, start);
8831 for (n = 0; n < nFrames; n++) {
8832 AnimationFrame(anim, &(frames[n]), piece);
8833 FrameDelay(appData.animSpeed);
8835 EndAnimation(anim, finish);
8839 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
8842 ChessSquare piece = board[fromY][toY];
8843 board[fromY][toY] = EmptySquare;
8844 DrawPosition(FALSE, board);
8846 x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap);
8847 y = lineGap + toY * (squareSize + lineGap);
8849 x = lineGap + toX * (squareSize + lineGap);
8850 y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap);
8852 for(i=1; i<4*kFactor; i++) {
8853 int r = squareSize * 9 * i/(20*kFactor - 5);
8854 XFillArc(xDisplay, xBoardWindow, highlineGC,
8855 x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360);
8856 FrameDelay(appData.animSpeed);
8858 board[fromY][toY] = piece;
8861 /* Main control logic for deciding what to animate and how */
8864 AnimateMove(board, fromX, fromY, toX, toY)
8873 XPoint start, finish, mid;
8874 XPoint frames[kFactor * 2 + 1];
8875 int nFrames, startColor, endColor;
8877 /* Are we animating? */
8878 if (!appData.animate || appData.blindfold)
8881 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8882 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8883 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8885 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8886 piece = board[fromY][fromX];
8887 if (piece >= EmptySquare) return;
8892 hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1;
8895 if (appData.debugMode) {
8896 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8897 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8898 piece, fromX, fromY, toX, toY); }
8900 ScreenSquare(fromX, fromY, &start, &startColor);
8901 ScreenSquare(toX, toY, &finish, &endColor);
8904 /* Knight: make straight movement then diagonal */
8905 if (abs(toY - fromY) < abs(toX - fromX)) {
8906 mid.x = start.x + (finish.x - start.x) / 2;
8910 mid.y = start.y + (finish.y - start.y) / 2;
8913 mid.x = start.x + (finish.x - start.x) / 2;
8914 mid.y = start.y + (finish.y - start.y) / 2;
8917 /* Don't use as many frames for very short moves */
8918 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8919 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8921 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8922 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8923 if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
8925 for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
8926 if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
8929 /* Be sure end square is redrawn */
8930 damage[0][toY][toX] = True;
8934 DragPieceBegin(x, y)
8937 int boardX, boardY, color;
8940 /* Are we animating? */
8941 if (!appData.animateDragging || appData.blindfold)
8944 /* Figure out which square we start in and the
8945 mouse position relative to top left corner. */
8946 BoardSquare(x, y, &boardX, &boardY);
8947 player.startBoardX = boardX;
8948 player.startBoardY = boardY;
8949 ScreenSquare(boardX, boardY, &corner, &color);
8950 player.startSquare = corner;
8951 player.startColor = color;
8952 /* As soon as we start dragging, the piece will jump slightly to
8953 be centered over the mouse pointer. */
8954 player.mouseDelta.x = squareSize/2;
8955 player.mouseDelta.y = squareSize/2;
8956 /* Initialise animation */
8957 player.dragPiece = PieceForSquare(boardX, boardY);
8959 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8960 player.dragActive = True;
8961 BeginAnimation(&player, player.dragPiece, color, &corner);
8962 /* Mark this square as needing to be redrawn. Note that
8963 we don't remove the piece though, since logically (ie
8964 as seen by opponent) the move hasn't been made yet. */
8965 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8966 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8967 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8968 corner.x, corner.y, squareSize, squareSize,
8969 0, 0); // [HGM] zh: unstack in stead of grab
8970 if(gatingPiece != EmptySquare) {
8971 /* Kludge alert: When gating we want the introduced
8972 piece to appear on the from square. To generate an
8973 image of it, we draw it on the board, copy the image,
8974 and draw the original piece again. */
8975 ChessSquare piece = boards[currentMove][boardY][boardX];
8976 DrawSquare(boardY, boardX, gatingPiece, 0);
8977 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8978 corner.x, corner.y, squareSize, squareSize, 0, 0);
8979 DrawSquare(boardY, boardX, piece, 0);
8981 damage[0][boardY][boardX] = True;
8983 player.dragActive = False;
8993 /* Are we animating? */
8994 if (!appData.animateDragging || appData.blindfold)
8998 if (! player.dragActive)
9000 /* Move piece, maintaining same relative position
9001 of mouse within square */
9002 corner.x = x - player.mouseDelta.x;
9003 corner.y = y - player.mouseDelta.y;
9004 AnimationFrame(&player, &corner, player.dragPiece);
9006 if (appData.highlightDragging) {
9008 BoardSquare(x, y, &boardX, &boardY);
9009 SetHighlights(fromX, fromY, boardX, boardY);
9018 int boardX, boardY, color;
9021 /* Are we animating? */
9022 if (!appData.animateDragging || appData.blindfold)
9026 if (! player.dragActive)
9028 /* Last frame in sequence is square piece is
9029 placed on, which may not match mouse exactly. */
9030 BoardSquare(x, y, &boardX, &boardY);
9031 ScreenSquare(boardX, boardY, &corner, &color);
9032 EndAnimation(&player, &corner);
9034 /* Be sure end square is redrawn */
9035 damage[0][boardY][boardX] = True;
9037 /* This prevents weird things happening with fast successive
9038 clicks which on my Sun at least can cause motion events
9039 without corresponding press/release. */
9040 player.dragActive = False;
9043 /* Handle expose event while piece being dragged */
9048 if (!player.dragActive || appData.blindfold)
9051 /* What we're doing: logically, the move hasn't been made yet,
9052 so the piece is still in it's original square. But visually
9053 it's being dragged around the board. So we erase the square
9054 that the piece is on and draw it at the last known drag point. */
9055 BlankSquare(player.startSquare.x, player.startSquare.y,
9056 player.startColor, EmptySquare, xBoardWindow, 1);
9057 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
9058 damage[0][player.startBoardY][player.startBoardX] = TRUE;
9061 #include <sys/ioctl.h>
9062 int get_term_width()
9064 int fd, default_width;
9067 default_width = 79; // this is FICS default anyway...
9069 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
9071 if (!ioctl(fd, TIOCGSIZE, &win))
9072 default_width = win.ts_cols;
9073 #elif defined(TIOCGWINSZ)
9075 if (!ioctl(fd, TIOCGWINSZ, &win))
9076 default_width = win.ws_col;
9078 return default_width;
9084 static int old_width = 0;
9085 int new_width = get_term_width();
9087 if (old_width != new_width)
9088 ics_printf("set width %d\n", new_width);
9089 old_width = new_width;
9092 void NotifyFrontendLogin()