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"
197 #include "xgamelist.h"
198 #include "xhistory.h"
199 #include "xedittags.h"
202 // must be moved to xengineoutput.h
204 void EngineOutputProc P((Widget w, XEvent *event,
205 String *prms, Cardinal *nprms));
206 void EvalGraphProc P((Widget w, XEvent *event,
207 String *prms, Cardinal *nprms));
214 #define usleep(t) _sleep2(((t)+500)/1000)
218 # define _(s) gettext (s)
219 # define N_(s) gettext_noop (s)
235 int main P((int argc, char **argv));
236 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
237 char *init_path, char *mode, int (*show_entry)(), char **name_return));
238 RETSIGTYPE CmailSigHandler P((int sig));
239 RETSIGTYPE IntSigHandler P((int sig));
240 RETSIGTYPE TermSizeSigHandler P((int sig));
241 void CreateGCs P((void));
242 void CreateXIMPieces P((void));
243 void CreateXPMPieces P((void));
244 void CreatePieces P((void));
245 void CreatePieceMenus P((void));
246 Widget CreateMenuBar P((Menu *mb));
247 Widget CreateButtonBar P ((MenuItem *mi));
248 char *FindFont P((char *pattern, int targetPxlSize));
249 void PieceMenuPopup P((Widget w, XEvent *event,
250 String *params, Cardinal *num_params));
251 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
252 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
253 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
254 u_int wreq, u_int hreq));
255 void CreateGrid P((void));
256 int EventToSquare P((int x, int limit));
257 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
258 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
259 void HandleUserMove P((Widget w, XEvent *event,
260 String *prms, Cardinal *nprms));
261 void AnimateUserMove P((Widget w, XEvent * event,
262 String * params, Cardinal * nParams));
263 void HandlePV P((Widget w, XEvent * event,
264 String * params, Cardinal * nParams));
265 void SelectPV P((Widget w, XEvent * event,
266 String * params, Cardinal * nParams));
267 void StopPV P((Widget w, XEvent * event,
268 String * params, Cardinal * nParams));
269 void WhiteClock P((Widget w, XEvent *event,
270 String *prms, Cardinal *nprms));
271 void BlackClock P((Widget w, XEvent *event,
272 String *prms, Cardinal *nprms));
273 void DrawPositionProc P((Widget w, XEvent *event,
274 String *prms, Cardinal *nprms));
275 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
277 void CommentPopUp P((char *title, char *label));
278 void CommentPopDown P((void));
279 void CommentCallback P((Widget w, XtPointer client_data,
280 XtPointer call_data));
281 void ICSInputBoxPopUp P((void));
282 void ICSInputBoxPopDown P((void));
283 void FileNamePopUp P((char *label, char *def,
284 FileProc proc, char *openMode));
285 void FileNamePopDown P((void));
286 void FileNameCallback P((Widget w, XtPointer client_data,
287 XtPointer call_data));
288 void FileNameAction P((Widget w, XEvent *event,
289 String *prms, Cardinal *nprms));
290 void AskQuestionReplyAction P((Widget w, XEvent *event,
291 String *prms, Cardinal *nprms));
292 void AskQuestionProc P((Widget w, XEvent *event,
293 String *prms, Cardinal *nprms));
294 void AskQuestionPopDown P((void));
295 void PromotionPopDown P((void));
296 void PromotionCallback P((Widget w, XtPointer client_data,
297 XtPointer call_data));
298 void EditCommentPopDown P((void));
299 void EditCommentCallback P((Widget w, XtPointer client_data,
300 XtPointer call_data));
301 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
302 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
303 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
304 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
306 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
308 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
310 void LoadPositionProc P((Widget w, XEvent *event,
311 String *prms, Cardinal *nprms));
312 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
314 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
316 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
318 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
320 void PastePositionProc P((Widget w, XEvent *event, String *prms,
322 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
323 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
324 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
325 void SavePositionProc P((Widget w, XEvent *event,
326 String *prms, Cardinal *nprms));
327 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
328 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
330 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
331 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
332 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
334 void MachineWhiteProc P((Widget w, XEvent *event,
335 String *prms, Cardinal *nprms));
336 void AnalyzeModeProc P((Widget w, XEvent *event,
337 String *prms, Cardinal *nprms));
338 void AnalyzeFileProc P((Widget w, XEvent *event,
339 String *prms, Cardinal *nprms));
340 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
342 void IcsClientProc P((Widget w, XEvent *event, String *prms,
344 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
345 void EditPositionProc P((Widget w, XEvent *event,
346 String *prms, Cardinal *nprms));
347 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
348 void EditCommentProc P((Widget w, XEvent *event,
349 String *prms, Cardinal *nprms));
350 void IcsInputBoxProc P((Widget w, XEvent *event,
351 String *prms, Cardinal *nprms));
352 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
353 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
354 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
355 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
356 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
357 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
358 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
365 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void StopObservingProc P((Widget w, XEvent *event, String *prms,
368 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
370 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
371 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
372 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
373 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
374 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
375 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
376 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
377 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
379 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
381 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
384 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
386 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
388 void AutocommProc P((Widget w, XEvent *event, String *prms,
390 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
391 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
392 void AutobsProc P((Widget w, XEvent *event, String *prms,
394 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
395 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
396 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
397 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
399 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
400 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
402 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
404 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
406 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
407 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
408 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
410 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
412 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
414 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
416 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
418 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
419 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
420 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
422 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
424 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
426 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
428 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
429 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
430 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
431 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
432 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
433 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
434 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
435 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
436 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void DisplayMove P((int moveNumber));
440 void DisplayTitle P((char *title));
441 void ICSInitScript P((void));
442 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
443 void ErrorPopUp P((char *title, char *text, int modal));
444 void ErrorPopDown P((void));
445 static char *ExpandPathName P((char *path));
446 static void CreateAnimVars P((void));
447 static void DragPieceMove P((int x, int y));
448 static void DrawDragPiece P((void));
449 char *ModeToWidgetName P((GameMode mode));
450 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
451 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
452 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
453 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
454 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
455 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
456 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
457 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
458 void GameListOptionsPopDown P(());
459 void ShufflePopDown P(());
460 void EnginePopDown P(());
461 void UciPopDown P(());
462 void TimeControlPopDown P(());
463 void NewVariantPopDown P(());
464 void SettingsPopDown P(());
465 void update_ics_width P(());
466 int get_term_width P(());
467 int CopyMemoProc P(());
469 * XBoard depends on Xt R4 or higher
471 int xtVersion = XtSpecificationRelease;
476 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
477 jailSquareColor, highlightSquareColor, premoveHighlightColor;
478 Pixel lowTimeWarningColor;
479 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
480 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
481 wjPieceGC, bjPieceGC, prelineGC, countGC;
482 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
483 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
484 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
485 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
486 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
487 ICSInputShell, fileNameShell, askQuestionShell;
488 Widget historyShell, evalGraphShell, gameListShell;
489 int hOffset; // [HGM] dual
490 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
491 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
492 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
493 Font clockFontID, coordFontID, countFontID;
494 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
495 XtAppContext appContext;
497 char *oldICSInteractionTitle;
501 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
503 Position commentX = -1, commentY = -1;
504 Dimension commentW, commentH;
505 typedef unsigned int BoardSize;
507 Boolean chessProgram;
509 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
510 int squareSize, smallLayout = 0, tinyLayout = 0,
511 marginW, marginH, // [HGM] for run-time resizing
512 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
513 ICSInputBoxUp = False, askQuestionUp = False,
514 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
515 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
516 Pixel timerForegroundPixel, timerBackgroundPixel;
517 Pixel buttonForegroundPixel, buttonBackgroundPixel;
518 char *chessDir, *programName, *programVersion,
519 *gameCopyFilename, *gamePasteFilename;
520 Boolean alwaysOnTop = False;
521 Boolean saveSettingsOnExit;
522 char *settingsFileName;
523 char *icsTextMenuString;
525 char *firstChessProgramNames;
526 char *secondChessProgramNames;
528 WindowPlacement wpMain;
529 WindowPlacement wpConsole;
530 WindowPlacement wpComment;
531 WindowPlacement wpMoveHistory;
532 WindowPlacement wpEvalGraph;
533 WindowPlacement wpEngineOutput;
534 WindowPlacement wpGameList;
535 WindowPlacement wpTags;
539 Pixmap pieceBitmap[2][(int)BlackPawn];
540 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
541 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
542 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
543 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
544 int useImages, useImageSqs;
545 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
546 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
547 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
548 XImage *ximLightSquare, *ximDarkSquare;
551 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
552 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
554 #define White(piece) ((int)(piece) < (int)BlackPawn)
556 /* Variables for doing smooth animation. This whole thing
557 would be much easier if the board was double-buffered,
558 but that would require a fairly major rewrite. */
563 GC blitGC, pieceGC, outlineGC;
564 XPoint startSquare, prevFrame, mouseDelta;
568 int startBoardX, startBoardY;
571 /* There can be two pieces being animated at once: a player
572 can begin dragging a piece before the remote opponent has moved. */
574 static AnimState game, player;
576 /* Bitmaps for use as masks when drawing XPM pieces.
577 Need one for each black and white piece. */
578 static Pixmap xpmMask[BlackKing + 1];
580 /* This magic number is the number of intermediate frames used
581 in each half of the animation. For short moves it's reduced
582 by 1. The total number of frames will be factor * 2 + 1. */
585 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
587 MenuItem fileMenu[] = {
588 {N_("New Game"), ResetProc},
589 {N_("New Shuffle Game ..."), ShuffleMenuProc},
590 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
591 {"----", NothingProc},
592 {N_("Load Game"), LoadGameProc},
593 {N_("Load Next Game"), LoadNextGameProc},
594 {N_("Load Previous Game"), LoadPrevGameProc},
595 {N_("Reload Same Game"), ReloadGameProc},
596 {N_("Save Game"), SaveGameProc},
597 {"----", NothingProc},
598 {N_("Copy Game"), CopyGameProc},
599 {N_("Paste Game"), PasteGameProc},
600 {"----", NothingProc},
601 {N_("Load Position"), LoadPositionProc},
602 {N_("Load Next Position"), LoadNextPositionProc},
603 {N_("Load Previous Position"), LoadPrevPositionProc},
604 {N_("Reload Same Position"), ReloadPositionProc},
605 {N_("Save Position"), SavePositionProc},
606 {"----", NothingProc},
607 {N_("Copy Position"), CopyPositionProc},
608 {N_("Paste Position"), PastePositionProc},
609 {"----", NothingProc},
610 {N_("Mail Move"), MailMoveProc},
611 {N_("Reload CMail Message"), ReloadCmailMsgProc},
612 {"----", NothingProc},
613 {N_("Exit"), QuitProc},
617 MenuItem modeMenu[] = {
618 {N_("Machine White"), MachineWhiteProc},
619 {N_("Machine Black"), MachineBlackProc},
620 {N_("Two Machines"), TwoMachinesProc},
621 {N_("Analysis Mode"), AnalyzeModeProc},
622 {N_("Analyze File"), AnalyzeFileProc },
623 {N_("ICS Client"), IcsClientProc},
624 {N_("Edit Game"), EditGameProc},
625 {N_("Edit Position"), EditPositionProc},
626 {N_("Training"), TrainingProc},
627 {"----", NothingProc},
628 {N_("Show Engine Output"), EngineOutputProc},
629 {N_("Show Evaluation Graph"), EvalGraphProc},
630 {N_("Show Game List"), ShowGameListProc},
631 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
632 {"----", NothingProc},
633 {N_("Edit Tags"), EditTagsProc},
634 {N_("Edit Comment"), EditCommentProc},
635 {N_("ICS Input Box"), IcsInputBoxProc},
636 {N_("Pause"), PauseProc},
640 MenuItem actionMenu[] = {
641 {N_("Accept"), AcceptProc},
642 {N_("Decline"), DeclineProc},
643 {N_("Rematch"), RematchProc},
644 {"----", NothingProc},
645 {N_("Call Flag"), CallFlagProc},
646 {N_("Draw"), DrawProc},
647 {N_("Adjourn"), AdjournProc},
648 {N_("Abort"), AbortProc},
649 {N_("Resign"), ResignProc},
650 {"----", NothingProc},
651 {N_("Stop Observing"), StopObservingProc},
652 {N_("Stop Examining"), StopExaminingProc},
653 {N_("Upload to Examine"), UploadProc},
654 {"----", NothingProc},
655 {N_("Adjudicate to White"), AdjuWhiteProc},
656 {N_("Adjudicate to Black"), AdjuBlackProc},
657 {N_("Adjudicate Draw"), AdjuDrawProc},
661 MenuItem stepMenu[] = {
662 {N_("Backward"), BackwardProc},
663 {N_("Forward"), ForwardProc},
664 {N_("Back to Start"), ToStartProc},
665 {N_("Forward to End"), ToEndProc},
666 {N_("Revert"), RevertProc},
667 {N_("Annotate"), AnnotateProc},
668 {N_("Truncate Game"), TruncateGameProc},
669 {"----", NothingProc},
670 {N_("Move Now"), MoveNowProc},
671 {N_("Retract Move"), RetractMoveProc},
675 MenuItem optionsMenu[] = {
676 {N_("Flip View"), FlipViewProc},
677 {"----", NothingProc},
678 {N_("Adjudications ..."), EngineMenuProc},
679 {N_("General Settings ..."), UciMenuProc},
680 {N_("Engine #1 Settings ..."), FirstSettingsProc},
681 {N_("Engine #2 Settings ..."), SecondSettingsProc},
682 {N_("Time Control ..."), TimeControlProc},
683 {N_("Game List ..."), GameListOptionsPopUp},
684 {"----", NothingProc},
685 {N_("Always Queen"), AlwaysQueenProc},
686 {N_("Animate Dragging"), AnimateDraggingProc},
687 {N_("Animate Moving"), AnimateMovingProc},
688 {N_("Auto Comment"), AutocommProc},
689 {N_("Auto Flag"), AutoflagProc},
690 {N_("Auto Flip View"), AutoflipProc},
691 {N_("Auto Observe"), AutobsProc},
692 {N_("Auto Raise Board"), AutoraiseProc},
693 {N_("Auto Save"), AutosaveProc},
694 {N_("Blindfold"), BlindfoldProc},
695 {N_("Flash Moves"), FlashMovesProc},
696 {N_("Get Move List"), GetMoveListProc},
698 {N_("Highlight Dragging"), HighlightDraggingProc},
700 {N_("Highlight Last Move"), HighlightLastMoveProc},
701 {N_("Move Sound"), MoveSoundProc},
702 {N_("ICS Alarm"), IcsAlarmProc},
703 {N_("Old Save Style"), OldSaveStyleProc},
704 {N_("Periodic Updates"), PeriodicUpdatesProc},
705 {N_("Ponder Next Move"), PonderNextMoveProc},
706 {N_("Popup Exit Message"), PopupExitMessageProc},
707 {N_("Popup Move Errors"), PopupMoveErrorsProc},
708 {N_("Premove"), PremoveProc},
709 {N_("Quiet Play"), QuietPlayProc},
710 {N_("Show Coords"), ShowCoordsProc},
711 {N_("Hide Thinking"), HideThinkingProc},
712 {N_("Test Legality"), TestLegalityProc},
713 {"----", NothingProc},
714 {N_("Save Settings Now"), SaveSettingsProc},
715 {N_("Save Settings on Exit"), SaveOnExitProc},
719 MenuItem helpMenu[] = {
720 {N_("Info XBoard"), InfoProc},
721 {N_("Man XBoard"), ManProc},
722 {"----", NothingProc},
723 {N_("Hint"), HintProc},
724 {N_("Book"), BookProc},
725 {"----", NothingProc},
726 {N_("About XBoard"), AboutProc},
731 {N_("File"), fileMenu},
732 {N_("Mode"), modeMenu},
733 {N_("Action"), actionMenu},
734 {N_("Step"), stepMenu},
735 {N_("Options"), optionsMenu},
736 {N_("Help"), helpMenu},
740 #define PAUSE_BUTTON N_("P")
741 MenuItem buttonBar[] = {
744 {PAUSE_BUTTON, PauseProc},
750 #define PIECE_MENU_SIZE 18
751 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
752 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
753 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
754 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
755 N_("Empty square"), N_("Clear board") },
756 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
757 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
758 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
759 N_("Empty square"), N_("Clear board") }
761 /* must be in same order as PieceMenuStrings! */
762 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
763 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
764 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
765 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
766 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
767 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
768 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
769 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
770 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
773 #define DROP_MENU_SIZE 6
774 String dropMenuStrings[DROP_MENU_SIZE] = {
775 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
777 /* must be in same order as PieceMenuStrings! */
778 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
779 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
780 WhiteRook, WhiteQueen
788 DropMenuEnables dmEnables[] = {
806 { XtNborderWidth, 0 },
807 { XtNdefaultDistance, 0 },
811 { XtNborderWidth, 0 },
812 { XtNresizable, (XtArgVal) True },
816 { XtNborderWidth, 0 },
822 { XtNjustify, (XtArgVal) XtJustifyRight },
823 { XtNlabel, (XtArgVal) "..." },
824 { XtNresizable, (XtArgVal) True },
825 { XtNresize, (XtArgVal) False }
828 Arg messageArgs[] = {
829 { XtNjustify, (XtArgVal) XtJustifyLeft },
830 { XtNlabel, (XtArgVal) "..." },
831 { XtNresizable, (XtArgVal) True },
832 { XtNresize, (XtArgVal) False }
836 { XtNborderWidth, 0 },
837 { XtNjustify, (XtArgVal) XtJustifyLeft }
840 XtResource clientResources[] = {
841 { "flashCount", "flashCount", XtRInt, sizeof(int),
842 XtOffset(AppDataPtr, flashCount), XtRImmediate,
843 (XtPointer) FLASH_COUNT },
846 XrmOptionDescRec shellOptions[] = {
847 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
848 { "-flash", "flashCount", XrmoptionNoArg, "3" },
849 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
852 XtActionsRec boardActions[] = {
853 { "DrawPosition", DrawPositionProc },
854 { "HandleUserMove", HandleUserMove },
855 { "AnimateUserMove", AnimateUserMove },
856 { "HandlePV", HandlePV },
857 { "SelectPV", SelectPV },
858 { "StopPV", StopPV },
859 { "FileNameAction", FileNameAction },
860 { "AskQuestionProc", AskQuestionProc },
861 { "AskQuestionReplyAction", AskQuestionReplyAction },
862 { "PieceMenuPopup", PieceMenuPopup },
863 { "WhiteClock", WhiteClock },
864 { "BlackClock", BlackClock },
865 { "Iconify", Iconify },
866 { "ResetProc", ResetProc },
867 { "LoadGameProc", LoadGameProc },
868 { "LoadNextGameProc", LoadNextGameProc },
869 { "LoadPrevGameProc", LoadPrevGameProc },
870 { "LoadSelectedProc", LoadSelectedProc },
871 { "SetFilterProc", SetFilterProc },
872 { "ReloadGameProc", ReloadGameProc },
873 { "LoadPositionProc", LoadPositionProc },
874 { "LoadNextPositionProc", LoadNextPositionProc },
875 { "LoadPrevPositionProc", LoadPrevPositionProc },
876 { "ReloadPositionProc", ReloadPositionProc },
877 { "CopyPositionProc", CopyPositionProc },
878 { "PastePositionProc", PastePositionProc },
879 { "CopyGameProc", CopyGameProc },
880 { "PasteGameProc", PasteGameProc },
881 { "SaveGameProc", SaveGameProc },
882 { "SavePositionProc", SavePositionProc },
883 { "MailMoveProc", MailMoveProc },
884 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
885 { "QuitProc", QuitProc },
886 { "MachineWhiteProc", MachineWhiteProc },
887 { "MachineBlackProc", MachineBlackProc },
888 { "AnalysisModeProc", AnalyzeModeProc },
889 { "AnalyzeFileProc", AnalyzeFileProc },
890 { "TwoMachinesProc", TwoMachinesProc },
891 { "IcsClientProc", IcsClientProc },
892 { "EditGameProc", EditGameProc },
893 { "EditPositionProc", EditPositionProc },
894 { "TrainingProc", EditPositionProc },
895 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
896 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
897 { "ShowGameListProc", ShowGameListProc },
898 { "ShowMoveListProc", HistoryShowProc},
899 { "EditTagsProc", EditCommentProc },
900 { "EditCommentProc", EditCommentProc },
901 { "IcsAlarmProc", IcsAlarmProc },
902 { "IcsInputBoxProc", IcsInputBoxProc },
903 { "PauseProc", PauseProc },
904 { "AcceptProc", AcceptProc },
905 { "DeclineProc", DeclineProc },
906 { "RematchProc", RematchProc },
907 { "CallFlagProc", CallFlagProc },
908 { "DrawProc", DrawProc },
909 { "AdjournProc", AdjournProc },
910 { "AbortProc", AbortProc },
911 { "ResignProc", ResignProc },
912 { "AdjuWhiteProc", AdjuWhiteProc },
913 { "AdjuBlackProc", AdjuBlackProc },
914 { "AdjuDrawProc", AdjuDrawProc },
915 { "EnterKeyProc", EnterKeyProc },
916 { "UpKeyProc", UpKeyProc },
917 { "DownKeyProc", DownKeyProc },
918 { "StopObservingProc", StopObservingProc },
919 { "StopExaminingProc", StopExaminingProc },
920 { "UploadProc", UploadProc },
921 { "BackwardProc", BackwardProc },
922 { "ForwardProc", ForwardProc },
923 { "ToStartProc", ToStartProc },
924 { "ToEndProc", ToEndProc },
925 { "RevertProc", RevertProc },
926 { "AnnotateProc", AnnotateProc },
927 { "TruncateGameProc", TruncateGameProc },
928 { "MoveNowProc", MoveNowProc },
929 { "RetractMoveProc", RetractMoveProc },
930 { "AlwaysQueenProc", AlwaysQueenProc },
931 { "AnimateDraggingProc", AnimateDraggingProc },
932 { "AnimateMovingProc", AnimateMovingProc },
933 { "AutoflagProc", AutoflagProc },
934 { "AutoflipProc", AutoflipProc },
935 { "AutobsProc", AutobsProc },
936 { "AutoraiseProc", AutoraiseProc },
937 { "AutosaveProc", AutosaveProc },
938 { "BlindfoldProc", BlindfoldProc },
939 { "FlashMovesProc", FlashMovesProc },
940 { "FlipViewProc", FlipViewProc },
941 { "GetMoveListProc", GetMoveListProc },
943 { "HighlightDraggingProc", HighlightDraggingProc },
945 { "HighlightLastMoveProc", HighlightLastMoveProc },
946 { "IcsAlarmProc", IcsAlarmProc },
947 { "MoveSoundProc", MoveSoundProc },
948 { "OldSaveStyleProc", OldSaveStyleProc },
949 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
950 { "PonderNextMoveProc", PonderNextMoveProc },
951 { "PopupExitMessageProc", PopupExitMessageProc },
952 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
953 { "PremoveProc", PremoveProc },
954 { "QuietPlayProc", QuietPlayProc },
955 { "ShowCoordsProc", ShowCoordsProc },
956 { "ShowThinkingProc", ShowThinkingProc },
957 { "HideThinkingProc", HideThinkingProc },
958 { "TestLegalityProc", TestLegalityProc },
959 { "SaveSettingsProc", SaveSettingsProc },
960 { "SaveOnExitProc", SaveOnExitProc },
961 { "InfoProc", InfoProc },
962 { "ManProc", ManProc },
963 { "HintProc", HintProc },
964 { "BookProc", BookProc },
965 { "AboutGameProc", AboutGameProc },
966 { "AboutProc", AboutProc },
967 { "DebugProc", DebugProc },
968 { "NothingProc", NothingProc },
969 { "CommentPopDown", (XtActionProc) CommentPopDown },
970 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
971 { "TagsPopDown", (XtActionProc) TagsPopDown },
972 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
973 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
974 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
975 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
976 { "GameListPopDown", (XtActionProc) GameListPopDown },
977 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
978 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
979 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
980 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
981 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
982 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
983 { "EnginePopDown", (XtActionProc) EnginePopDown },
984 { "UciPopDown", (XtActionProc) UciPopDown },
985 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
986 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
987 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
988 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
991 char globalTranslations[] =
992 ":<Key>R: ResignProc() \n \
993 :<Key>r: ResetProc() \n \
994 :<Key>g: LoadGameProc() \n \
995 :<Key>N: LoadNextGameProc() \n \
996 :<Key>P: LoadPrevGameProc() \n \
997 :<Key>Q: QuitProc() \n \
998 :<Key>F: ToEndProc() \n \
999 :<Key>f: ForwardProc() \n \
1000 :<Key>B: ToStartProc() \n \
1001 :<Key>b: BackwardProc() \n \
1002 :<Key>p: PauseProc() \n \
1003 :<Key>d: DrawProc() \n \
1004 :<Key>t: CallFlagProc() \n \
1005 :<Key>i: Iconify() \n \
1006 :<Key>c: Iconify() \n \
1007 :<Key>v: FlipViewProc() \n \
1008 <KeyDown>Control_L: BackwardProc() \n \
1009 <KeyUp>Control_L: ForwardProc() \n \
1010 <KeyDown>Control_R: BackwardProc() \n \
1011 <KeyUp>Control_R: ForwardProc() \n \
1012 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1013 \"Send to chess program:\",,1) \n \
1014 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1015 \"Send to second chess program:\",,2) \n";
1017 char boardTranslations[] =
1018 "<Btn1Down>: HandleUserMove() \n \
1019 <Btn1Up>: HandleUserMove() \n \
1020 <Btn1Motion>: AnimateUserMove() \n \
1021 <Btn3Motion>: HandlePV() \n \
1022 <Btn3Up>: PieceMenuPopup(menuB) \n \
1023 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1024 PieceMenuPopup(menuB) \n \
1025 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1026 PieceMenuPopup(menuW) \n \
1027 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1028 PieceMenuPopup(menuW) \n \
1029 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1030 PieceMenuPopup(menuB) \n";
1032 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1033 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1035 char ICSInputTranslations[] =
1036 "<Key>Up: UpKeyProc() \n "
1037 "<Key>Down: DownKeyProc() \n "
1038 "<Key>Return: EnterKeyProc() \n";
1040 String xboardResources[] = {
1041 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1042 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1043 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1048 /* Max possible square size */
1049 #define MAXSQSIZE 256
1051 static int xpm_avail[MAXSQSIZE];
1053 #ifdef HAVE_DIR_STRUCT
1055 /* Extract piece size from filename */
1057 xpm_getsize(name, len, ext)
1068 if ((p=strchr(name, '.')) == NULL ||
1069 StrCaseCmp(p+1, ext) != 0)
1075 while (*p && isdigit(*p))
1082 /* Setup xpm_avail */
1084 xpm_getavail(dirname, ext)
1092 for (i=0; i<MAXSQSIZE; ++i)
1095 if (appData.debugMode)
1096 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1098 dir = opendir(dirname);
1101 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1102 programName, dirname);
1106 while ((ent=readdir(dir)) != NULL) {
1107 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1108 if (i > 0 && i < MAXSQSIZE)
1118 xpm_print_avail(fp, ext)
1124 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1125 for (i=1; i<MAXSQSIZE; ++i) {
1131 /* Return XPM piecesize closest to size */
1133 xpm_closest_to(dirname, size, ext)
1139 int sm_diff = MAXSQSIZE;
1143 xpm_getavail(dirname, ext);
1145 if (appData.debugMode)
1146 xpm_print_avail(stderr, ext);
1148 for (i=1; i<MAXSQSIZE; ++i) {
1151 diff = (diff<0) ? -diff : diff;
1152 if (diff < sm_diff) {
1160 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1166 #else /* !HAVE_DIR_STRUCT */
1167 /* If we are on a system without a DIR struct, we can't
1168 read the directory, so we can't collect a list of
1169 filenames, etc., so we can't do any size-fitting. */
1171 xpm_closest_to(dirname, size, ext)
1176 fprintf(stderr, _("\
1177 Warning: No DIR structure found on this system --\n\
1178 Unable to autosize for XPM/XIM pieces.\n\
1179 Please report this error to frankm@hiwaay.net.\n\
1180 Include system type & operating system in message.\n"));
1183 #endif /* HAVE_DIR_STRUCT */
1185 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1186 "magenta", "cyan", "white" };
1190 TextColors textColors[(int)NColorClasses];
1192 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1194 parse_color(str, which)
1198 char *p, buf[100], *d;
1201 if (strlen(str) > 99) /* watch bounds on buf */
1206 for (i=0; i<which; ++i) {
1213 /* Could be looking at something like:
1215 .. in which case we want to stop on a comma also */
1216 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1220 return -1; /* Use default for empty field */
1223 if (which == 2 || isdigit(*p))
1226 while (*p && isalpha(*p))
1231 for (i=0; i<8; ++i) {
1232 if (!StrCaseCmp(buf, cnames[i]))
1233 return which? (i+40) : (i+30);
1235 if (!StrCaseCmp(buf, "default")) return -1;
1237 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1242 parse_cpair(cc, str)
1246 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1247 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1252 /* bg and attr are optional */
1253 textColors[(int)cc].bg = parse_color(str, 1);
1254 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1255 textColors[(int)cc].attr = 0;
1261 /* Arrange to catch delete-window events */
1262 Atom wm_delete_window;
1264 CatchDeleteWindow(Widget w, String procname)
1267 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1268 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1269 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1276 XtSetArg(args[0], XtNiconic, False);
1277 XtSetValues(shellWidget, args, 1);
1279 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1282 //---------------------------------------------------------------------------------------------------------
1283 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1286 #define CW_USEDEFAULT (1<<31)
1287 #define ICS_TEXT_MENU_SIZE 90
1288 #define DEBUG_FILE "xboard.debug"
1289 #define SetCurrentDirectory chdir
1290 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1294 // these two must some day move to frontend.h, when they are implemented
1295 Boolean GameListIsUp();
1297 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1300 // front-end part of option handling
1302 // [HGM] This platform-dependent table provides the location for storing the color info
1303 extern char *crWhite, * crBlack;
1307 &appData.whitePieceColor,
1308 &appData.blackPieceColor,
1309 &appData.lightSquareColor,
1310 &appData.darkSquareColor,
1311 &appData.highlightSquareColor,
1312 &appData.premoveHighlightColor,
1313 &appData.lowTimeWarningColor,
1324 // [HGM] font: keep a font for each square size, even non-stndard ones
1325 #define NUM_SIZES 18
1326 #define MAX_SIZE 130
1327 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1328 char *fontTable[NUM_FONTS][MAX_SIZE];
1331 ParseFont(char *name, int number)
1332 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1334 if(sscanf(name, "size%d:", &size)) {
1335 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1336 // defer processing it until we know if it matches our board size
1337 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1338 fontTable[number][size] = strdup(strchr(name, ':')+1);
1339 fontValid[number][size] = True;
1344 case 0: // CLOCK_FONT
1345 appData.clockFont = strdup(name);
1347 case 1: // MESSAGE_FONT
1348 appData.font = strdup(name);
1350 case 2: // COORD_FONT
1351 appData.coordFont = strdup(name);
1356 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1361 { // only 2 fonts currently
1362 appData.clockFont = CLOCK_FONT_NAME;
1363 appData.coordFont = COORD_FONT_NAME;
1364 appData.font = DEFAULT_FONT_NAME;
1369 { // no-op, until we identify the code for this already in XBoard and move it here
1373 ParseColor(int n, char *name)
1374 { // in XBoard, just copy the color-name string
1375 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1379 ParseTextAttribs(ColorClass cc, char *s)
1381 (&appData.colorShout)[cc] = strdup(s);
1385 ParseBoardSize(void *addr, char *name)
1387 appData.boardSize = strdup(name);
1392 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1396 SetCommPortDefaults()
1397 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1400 // [HGM] args: these three cases taken out to stay in front-end
1402 SaveFontArg(FILE *f, ArgDescriptor *ad)
1404 char *name, buf[MSG_SIZ];
1405 int i, n = (int)ad->argLoc;
1407 case 0: // CLOCK_FONT
1408 name = appData.clockFont;
1410 case 1: // MESSAGE_FONT
1411 name = appData.font;
1413 case 2: // COORD_FONT
1414 name = appData.coordFont;
1419 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1420 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1421 fontTable[n][squareSize] = strdup(name);
1422 fontValid[n][squareSize] = True;
1425 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1426 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1431 { // nothing to do, as the sounds are at all times represented by their text-string names already
1435 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1436 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1437 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1441 SaveColor(FILE *f, ArgDescriptor *ad)
1442 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1443 if(colorVariable[(int)ad->argLoc])
1444 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1448 SaveBoardSize(FILE *f, char *name, void *addr)
1449 { // wrapper to shield back-end from BoardSize & sizeInfo
1450 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1454 ParseCommPortSettings(char *s)
1455 { // no such option in XBoard (yet)
1458 extern Widget engineOutputShell;
1459 extern Widget tagsShell, editTagsShell;
1461 GetActualPlacement(Widget wg, WindowPlacement *wp)
1471 XtSetArg(args[i], XtNx, &x); i++;
1472 XtSetArg(args[i], XtNy, &y); i++;
1473 XtSetArg(args[i], XtNwidth, &w); i++;
1474 XtSetArg(args[i], XtNheight, &h); i++;
1475 XtGetValues(wg, args, i);
1484 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1485 // In XBoard this will have to wait until awareness of window parameters is implemented
1486 GetActualPlacement(shellWidget, &wpMain);
1487 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1488 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1489 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1490 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1491 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1492 else GetActualPlacement(editShell, &wpComment);
1493 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1494 else GetActualPlacement(editTagsShell, &wpTags);
1498 PrintCommPortSettings(FILE *f, char *name)
1499 { // This option does not exist in XBoard
1503 MySearchPath(char *installDir, char *name, char *fullname)
1504 { // just append installDir and name. Perhaps ExpandPath should be used here?
1505 name = ExpandPathName(name);
1506 if(name && name[0] == '/') strcpy(fullname, name); else {
1507 sprintf(fullname, "%s%c%s", installDir, '/', name);
1513 MyGetFullPathName(char *name, char *fullname)
1514 { // should use ExpandPath?
1515 name = ExpandPathName(name);
1516 strcpy(fullname, name);
1521 EnsureOnScreen(int *x, int *y, int minX, int minY)
1528 { // [HGM] args: allows testing if main window is realized from back-end
1529 return xBoardWindow != 0;
1533 PopUpStartupDialog()
1534 { // start menu not implemented in XBoard
1537 ConvertToLine(int argc, char **argv)
1539 static char line[128*1024], buf[1024];
1543 for(i=1; i<argc; i++) {
1544 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1545 && argv[i][0] != '{' )
1546 sprintf(buf, "{%s} ", argv[i]);
1547 else sprintf(buf, "%s ", argv[i]);
1550 line[strlen(line)-1] = NULLCHAR;
1554 //--------------------------------------------------------------------------------------------
1556 extern Boolean twoBoards, partnerUp;
1559 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1561 #define BoardSize int
1562 void InitDrawingSizes(BoardSize boardSize, int flags)
1563 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1564 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1566 XtGeometryResult gres;
1569 if(!formWidget) return;
1572 * Enable shell resizing.
1574 shellArgs[0].value = (XtArgVal) &w;
1575 shellArgs[1].value = (XtArgVal) &h;
1576 XtGetValues(shellWidget, shellArgs, 2);
1578 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1579 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1580 XtSetValues(shellWidget, &shellArgs[2], 4);
1582 XtSetArg(args[0], XtNdefaultDistance, &sep);
1583 XtGetValues(formWidget, args, 1);
1585 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1586 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1588 hOffset = boardWidth + 10;
1589 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1590 secondSegments[i] = gridSegments[i];
1591 secondSegments[i].x1 += hOffset;
1592 secondSegments[i].x2 += hOffset;
1595 XtSetArg(args[0], XtNwidth, boardWidth);
1596 XtSetArg(args[1], XtNheight, boardHeight);
1597 XtSetValues(boardWidget, args, 2);
1599 timerWidth = (boardWidth - sep) / 2;
1600 XtSetArg(args[0], XtNwidth, timerWidth);
1601 XtSetValues(whiteTimerWidget, args, 1);
1602 XtSetValues(blackTimerWidget, args, 1);
1604 XawFormDoLayout(formWidget, False);
1606 if (appData.titleInWindow) {
1608 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1609 XtSetArg(args[i], XtNheight, &h); i++;
1610 XtGetValues(titleWidget, args, i);
1612 w = boardWidth - 2*bor;
1614 XtSetArg(args[0], XtNwidth, &w);
1615 XtGetValues(menuBarWidget, args, 1);
1616 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1619 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1620 if (gres != XtGeometryYes && appData.debugMode) {
1622 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1623 programName, gres, w, h, wr, hr);
1627 XawFormDoLayout(formWidget, True);
1630 * Inhibit shell resizing.
1632 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1633 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1634 shellArgs[4].value = shellArgs[2].value = w;
1635 shellArgs[5].value = shellArgs[3].value = h;
1636 XtSetValues(shellWidget, &shellArgs[0], 6);
1638 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1641 for(i=0; i<4; i++) {
1643 for(p=0; p<=(int)WhiteKing; p++)
1644 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1645 if(gameInfo.variant == VariantShogi) {
1646 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1647 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1648 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1649 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1650 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1653 if(gameInfo.variant == VariantGothic) {
1654 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1658 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1659 for(p=0; p<=(int)WhiteKing; p++)
1660 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1661 if(gameInfo.variant == VariantShogi) {
1662 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1663 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1664 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1665 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1666 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1669 if(gameInfo.variant == VariantGothic) {
1670 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1676 for(i=0; i<2; i++) {
1678 for(p=0; p<=(int)WhiteKing; p++)
1679 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1680 if(gameInfo.variant == VariantShogi) {
1681 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1682 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1683 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1684 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1685 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1688 if(gameInfo.variant == VariantGothic) {
1689 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1700 void EscapeExpand(char *p, char *q)
1701 { // [HGM] initstring: routine to shape up string arguments
1702 while(*p++ = *q++) if(p[-1] == '\\')
1704 case 'n': p[-1] = '\n'; break;
1705 case 'r': p[-1] = '\r'; break;
1706 case 't': p[-1] = '\t'; break;
1707 case '\\': p[-1] = '\\'; break;
1708 case 0: *p = 0; return;
1709 default: p[-1] = q[-1]; break;
1718 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1719 XSetWindowAttributes window_attributes;
1721 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1722 XrmValue vFrom, vTo;
1723 XtGeometryResult gres;
1726 int forceMono = False;
1728 srandom(time(0)); // [HGM] book: make random truly random
1730 setbuf(stdout, NULL);
1731 setbuf(stderr, NULL);
1734 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1735 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1739 programName = strrchr(argv[0], '/');
1740 if (programName == NULL)
1741 programName = argv[0];
1746 XtSetLanguageProc(NULL, NULL, NULL);
1747 bindtextdomain(PACKAGE, LOCALEDIR);
1748 textdomain(PACKAGE);
1752 XtAppInitialize(&appContext, "XBoard", shellOptions,
1753 XtNumber(shellOptions),
1754 &argc, argv, xboardResources, NULL, 0);
1755 appData.boardSize = "";
1756 InitAppData(ConvertToLine(argc, argv));
1758 if (p == NULL) p = "/tmp";
1759 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1760 gameCopyFilename = (char*) malloc(i);
1761 gamePasteFilename = (char*) malloc(i);
1762 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1763 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1765 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1766 clientResources, XtNumber(clientResources),
1769 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1770 static char buf[MSG_SIZ];
1771 EscapeExpand(buf, appData.initString);
1772 appData.initString = strdup(buf);
1773 EscapeExpand(buf, appData.secondInitString);
1774 appData.secondInitString = strdup(buf);
1775 EscapeExpand(buf, appData.firstComputerString);
1776 appData.firstComputerString = strdup(buf);
1777 EscapeExpand(buf, appData.secondComputerString);
1778 appData.secondComputerString = strdup(buf);
1781 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1784 if (chdir(chessDir) != 0) {
1785 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1791 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1792 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1793 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1794 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1797 setbuf(debugFP, NULL);
1800 /* [HGM,HR] make sure board size is acceptable */
1801 if(appData.NrFiles > BOARD_FILES ||
1802 appData.NrRanks > BOARD_RANKS )
1803 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1806 /* This feature does not work; animation needs a rewrite */
1807 appData.highlightDragging = FALSE;
1811 xDisplay = XtDisplay(shellWidget);
1812 xScreen = DefaultScreen(xDisplay);
1813 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1815 gameInfo.variant = StringToVariant(appData.variant);
1816 InitPosition(FALSE);
1819 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1821 if (isdigit(appData.boardSize[0])) {
1822 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1823 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1824 &fontPxlSize, &smallLayout, &tinyLayout);
1826 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1827 programName, appData.boardSize);
1831 /* Find some defaults; use the nearest known size */
1832 SizeDefaults *szd, *nearest;
1833 int distance = 99999;
1834 nearest = szd = sizeDefaults;
1835 while (szd->name != NULL) {
1836 if (abs(szd->squareSize - squareSize) < distance) {
1838 distance = abs(szd->squareSize - squareSize);
1839 if (distance == 0) break;
1843 if (i < 2) lineGap = nearest->lineGap;
1844 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1845 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1846 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1847 if (i < 6) smallLayout = nearest->smallLayout;
1848 if (i < 7) tinyLayout = nearest->tinyLayout;
1851 SizeDefaults *szd = sizeDefaults;
1852 if (*appData.boardSize == NULLCHAR) {
1853 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1854 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1857 if (szd->name == NULL) szd--;
1858 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1860 while (szd->name != NULL &&
1861 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1862 if (szd->name == NULL) {
1863 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1864 programName, appData.boardSize);
1868 squareSize = szd->squareSize;
1869 lineGap = szd->lineGap;
1870 clockFontPxlSize = szd->clockFontPxlSize;
1871 coordFontPxlSize = szd->coordFontPxlSize;
1872 fontPxlSize = szd->fontPxlSize;
1873 smallLayout = szd->smallLayout;
1874 tinyLayout = szd->tinyLayout;
1875 // [HGM] font: use defaults from settings file if available and not overruled
1877 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
1878 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
1879 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
1880 appData.font = fontTable[MESSAGE_FONT][squareSize];
1881 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
1882 appData.coordFont = fontTable[COORD_FONT][squareSize];
1884 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1885 if (strlen(appData.pixmapDirectory) > 0) {
1886 p = ExpandPathName(appData.pixmapDirectory);
1888 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1889 appData.pixmapDirectory);
1892 if (appData.debugMode) {
1893 fprintf(stderr, _("\
1894 XBoard square size (hint): %d\n\
1895 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1897 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1898 if (appData.debugMode) {
1899 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1903 /* [HR] height treated separately (hacked) */
1904 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1905 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1906 if (appData.showJail == 1) {
1907 /* Jail on top and bottom */
1908 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1909 XtSetArg(boardArgs[2], XtNheight,
1910 boardHeight + 2*(lineGap + squareSize));
1911 } else if (appData.showJail == 2) {
1913 XtSetArg(boardArgs[1], XtNwidth,
1914 boardWidth + 2*(lineGap + squareSize));
1915 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1918 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1919 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1923 * Determine what fonts to use.
1925 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1926 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1927 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1928 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1929 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1930 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1931 appData.font = FindFont(appData.font, fontPxlSize);
1932 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1933 countFontStruct = XQueryFont(xDisplay, countFontID);
1934 // appData.font = FindFont(appData.font, fontPxlSize);
1936 xdb = XtDatabase(xDisplay);
1937 XrmPutStringResource(&xdb, "*font", appData.font);
1940 * Detect if there are not enough colors available and adapt.
1942 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1943 appData.monoMode = True;
1946 if (!appData.monoMode) {
1947 vFrom.addr = (caddr_t) appData.lightSquareColor;
1948 vFrom.size = strlen(appData.lightSquareColor);
1949 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1950 if (vTo.addr == NULL) {
1951 appData.monoMode = True;
1954 lightSquareColor = *(Pixel *) vTo.addr;
1957 if (!appData.monoMode) {
1958 vFrom.addr = (caddr_t) appData.darkSquareColor;
1959 vFrom.size = strlen(appData.darkSquareColor);
1960 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1961 if (vTo.addr == NULL) {
1962 appData.monoMode = True;
1965 darkSquareColor = *(Pixel *) vTo.addr;
1968 if (!appData.monoMode) {
1969 vFrom.addr = (caddr_t) appData.whitePieceColor;
1970 vFrom.size = strlen(appData.whitePieceColor);
1971 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1972 if (vTo.addr == NULL) {
1973 appData.monoMode = True;
1976 whitePieceColor = *(Pixel *) vTo.addr;
1979 if (!appData.monoMode) {
1980 vFrom.addr = (caddr_t) appData.blackPieceColor;
1981 vFrom.size = strlen(appData.blackPieceColor);
1982 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1983 if (vTo.addr == NULL) {
1984 appData.monoMode = True;
1987 blackPieceColor = *(Pixel *) vTo.addr;
1991 if (!appData.monoMode) {
1992 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1993 vFrom.size = strlen(appData.highlightSquareColor);
1994 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1995 if (vTo.addr == NULL) {
1996 appData.monoMode = True;
1999 highlightSquareColor = *(Pixel *) vTo.addr;
2003 if (!appData.monoMode) {
2004 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
2005 vFrom.size = strlen(appData.premoveHighlightColor);
2006 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2007 if (vTo.addr == NULL) {
2008 appData.monoMode = True;
2011 premoveHighlightColor = *(Pixel *) vTo.addr;
2016 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2019 if (appData.bitmapDirectory == NULL ||
2020 appData.bitmapDirectory[0] == NULLCHAR)
2021 appData.bitmapDirectory = DEF_BITMAP_DIR;
2024 if (appData.lowTimeWarning && !appData.monoMode) {
2025 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2026 vFrom.size = strlen(appData.lowTimeWarningColor);
2027 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2028 if (vTo.addr == NULL)
2029 appData.monoMode = True;
2031 lowTimeWarningColor = *(Pixel *) vTo.addr;
2034 if (appData.monoMode && appData.debugMode) {
2035 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2036 (unsigned long) XWhitePixel(xDisplay, xScreen),
2037 (unsigned long) XBlackPixel(xDisplay, xScreen));
2040 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2041 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2042 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2043 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2044 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2045 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2046 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2047 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2048 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2049 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2051 if (appData.colorize) {
2053 _("%s: can't parse color names; disabling colorization\n"),
2056 appData.colorize = FALSE;
2058 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2059 textColors[ColorNone].attr = 0;
2061 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2067 layoutName = "tinyLayout";
2068 } else if (smallLayout) {
2069 layoutName = "smallLayout";
2071 layoutName = "normalLayout";
2073 /* Outer layoutWidget is there only to provide a name for use in
2074 resources that depend on the layout style */
2076 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2077 layoutArgs, XtNumber(layoutArgs));
2079 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2080 formArgs, XtNumber(formArgs));
2081 XtSetArg(args[0], XtNdefaultDistance, &sep);
2082 XtGetValues(formWidget, args, 1);
2085 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2086 XtSetArg(args[0], XtNtop, XtChainTop);
2087 XtSetArg(args[1], XtNbottom, XtChainTop);
2088 XtSetArg(args[2], XtNright, XtChainLeft);
2089 XtSetValues(menuBarWidget, args, 3);
2091 widgetList[j++] = whiteTimerWidget =
2092 XtCreateWidget("whiteTime", labelWidgetClass,
2093 formWidget, timerArgs, XtNumber(timerArgs));
2094 XtSetArg(args[0], XtNfont, clockFontStruct);
2095 XtSetArg(args[1], XtNtop, XtChainTop);
2096 XtSetArg(args[2], XtNbottom, XtChainTop);
2097 XtSetValues(whiteTimerWidget, args, 3);
2099 widgetList[j++] = blackTimerWidget =
2100 XtCreateWidget("blackTime", labelWidgetClass,
2101 formWidget, timerArgs, XtNumber(timerArgs));
2102 XtSetArg(args[0], XtNfont, clockFontStruct);
2103 XtSetArg(args[1], XtNtop, XtChainTop);
2104 XtSetArg(args[2], XtNbottom, XtChainTop);
2105 XtSetValues(blackTimerWidget, args, 3);
2107 if (appData.titleInWindow) {
2108 widgetList[j++] = titleWidget =
2109 XtCreateWidget("title", labelWidgetClass, formWidget,
2110 titleArgs, XtNumber(titleArgs));
2111 XtSetArg(args[0], XtNtop, XtChainTop);
2112 XtSetArg(args[1], XtNbottom, XtChainTop);
2113 XtSetValues(titleWidget, args, 2);
2116 if (appData.showButtonBar) {
2117 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2118 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2119 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2120 XtSetArg(args[2], XtNtop, XtChainTop);
2121 XtSetArg(args[3], XtNbottom, XtChainTop);
2122 XtSetValues(buttonBarWidget, args, 4);
2125 widgetList[j++] = messageWidget =
2126 XtCreateWidget("message", labelWidgetClass, formWidget,
2127 messageArgs, XtNumber(messageArgs));
2128 XtSetArg(args[0], XtNtop, XtChainTop);
2129 XtSetArg(args[1], XtNbottom, XtChainTop);
2130 XtSetValues(messageWidget, args, 2);
2132 widgetList[j++] = boardWidget =
2133 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2134 XtNumber(boardArgs));
2136 XtManageChildren(widgetList, j);
2138 timerWidth = (boardWidth - sep) / 2;
2139 XtSetArg(args[0], XtNwidth, timerWidth);
2140 XtSetValues(whiteTimerWidget, args, 1);
2141 XtSetValues(blackTimerWidget, args, 1);
2143 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2144 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2145 XtGetValues(whiteTimerWidget, args, 2);
2147 if (appData.showButtonBar) {
2148 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2149 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2150 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2154 * formWidget uses these constraints but they are stored
2158 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2159 XtSetValues(menuBarWidget, args, i);
2160 if (appData.titleInWindow) {
2163 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2164 XtSetValues(whiteTimerWidget, args, i);
2166 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2167 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2168 XtSetValues(blackTimerWidget, args, i);
2170 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2171 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2172 XtSetValues(titleWidget, args, i);
2174 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2175 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2176 XtSetValues(messageWidget, args, i);
2177 if (appData.showButtonBar) {
2179 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2180 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2181 XtSetValues(buttonBarWidget, args, i);
2185 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2186 XtSetValues(whiteTimerWidget, args, i);
2188 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2189 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2190 XtSetValues(blackTimerWidget, args, i);
2192 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2193 XtSetValues(titleWidget, args, i);
2195 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2196 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2197 XtSetValues(messageWidget, args, i);
2198 if (appData.showButtonBar) {
2200 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2201 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2202 XtSetValues(buttonBarWidget, args, i);
2207 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2208 XtSetValues(whiteTimerWidget, args, i);
2210 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2211 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2212 XtSetValues(blackTimerWidget, args, i);
2214 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2215 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2216 XtSetValues(messageWidget, args, i);
2217 if (appData.showButtonBar) {
2219 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2220 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2221 XtSetValues(buttonBarWidget, args, i);
2225 XtSetArg(args[0], XtNfromVert, messageWidget);
2226 XtSetArg(args[1], XtNtop, XtChainTop);
2227 XtSetArg(args[2], XtNbottom, XtChainBottom);
2228 XtSetArg(args[3], XtNleft, XtChainLeft);
2229 XtSetArg(args[4], XtNright, XtChainRight);
2230 XtSetValues(boardWidget, args, 5);
2232 XtRealizeWidget(shellWidget);
2235 XtSetArg(args[0], XtNx, wpMain.x);
2236 XtSetArg(args[1], XtNy, wpMain.y);
2237 XtSetValues(shellWidget, args, 2);
2241 * Correct the width of the message and title widgets.
2242 * It is not known why some systems need the extra fudge term.
2243 * The value "2" is probably larger than needed.
2245 XawFormDoLayout(formWidget, False);
2247 #define WIDTH_FUDGE 2
2249 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2250 XtSetArg(args[i], XtNheight, &h); i++;
2251 XtGetValues(messageWidget, args, i);
2252 if (appData.showButtonBar) {
2254 XtSetArg(args[i], XtNwidth, &w); i++;
2255 XtGetValues(buttonBarWidget, args, i);
2256 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2258 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2261 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2262 if (gres != XtGeometryYes && appData.debugMode) {
2263 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2264 programName, gres, w, h, wr, hr);
2267 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2268 /* The size used for the child widget in layout lags one resize behind
2269 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2271 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2272 if (gres != XtGeometryYes && appData.debugMode) {
2273 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2274 programName, gres, w, h, wr, hr);
2277 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2278 XtSetArg(args[1], XtNright, XtChainRight);
2279 XtSetValues(messageWidget, args, 2);
2281 if (appData.titleInWindow) {
2283 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2284 XtSetArg(args[i], XtNheight, &h); i++;
2285 XtGetValues(titleWidget, args, i);
2287 w = boardWidth - 2*bor;
2289 XtSetArg(args[0], XtNwidth, &w);
2290 XtGetValues(menuBarWidget, args, 1);
2291 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2294 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2295 if (gres != XtGeometryYes && appData.debugMode) {
2297 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2298 programName, gres, w, h, wr, hr);
2301 XawFormDoLayout(formWidget, True);
2303 xBoardWindow = XtWindow(boardWidget);
2305 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2306 // not need to go into InitDrawingSizes().
2310 * Create X checkmark bitmap and initialize option menu checks.
2312 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2313 checkmark_bits, checkmark_width, checkmark_height);
2314 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2315 if (appData.alwaysPromoteToQueen) {
2316 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2319 if (appData.animateDragging) {
2320 XtSetValues(XtNameToWidget(menuBarWidget,
2321 "menuOptions.Animate Dragging"),
2324 if (appData.animate) {
2325 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2328 if (appData.autoComment) {
2329 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2332 if (appData.autoCallFlag) {
2333 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2336 if (appData.autoFlipView) {
2337 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2340 if (appData.autoObserve) {
2341 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2344 if (appData.autoRaiseBoard) {
2345 XtSetValues(XtNameToWidget(menuBarWidget,
2346 "menuOptions.Auto Raise Board"), args, 1);
2348 if (appData.autoSaveGames) {
2349 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2352 if (appData.saveGameFile[0] != NULLCHAR) {
2353 /* Can't turn this off from menu */
2354 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2356 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2360 if (appData.blindfold) {
2361 XtSetValues(XtNameToWidget(menuBarWidget,
2362 "menuOptions.Blindfold"), args, 1);
2364 if (appData.flashCount > 0) {
2365 XtSetValues(XtNameToWidget(menuBarWidget,
2366 "menuOptions.Flash Moves"),
2369 if (appData.getMoveList) {
2370 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2374 if (appData.highlightDragging) {
2375 XtSetValues(XtNameToWidget(menuBarWidget,
2376 "menuOptions.Highlight Dragging"),
2380 if (appData.highlightLastMove) {
2381 XtSetValues(XtNameToWidget(menuBarWidget,
2382 "menuOptions.Highlight Last Move"),
2385 if (appData.icsAlarm) {
2386 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2389 if (appData.ringBellAfterMoves) {
2390 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2393 if (appData.oldSaveStyle) {
2394 XtSetValues(XtNameToWidget(menuBarWidget,
2395 "menuOptions.Old Save Style"), args, 1);
2397 if (appData.periodicUpdates) {
2398 XtSetValues(XtNameToWidget(menuBarWidget,
2399 "menuOptions.Periodic Updates"), args, 1);
2401 if (appData.ponderNextMove) {
2402 XtSetValues(XtNameToWidget(menuBarWidget,
2403 "menuOptions.Ponder Next Move"), args, 1);
2405 if (appData.popupExitMessage) {
2406 XtSetValues(XtNameToWidget(menuBarWidget,
2407 "menuOptions.Popup Exit Message"), args, 1);
2409 if (appData.popupMoveErrors) {
2410 XtSetValues(XtNameToWidget(menuBarWidget,
2411 "menuOptions.Popup Move Errors"), args, 1);
2413 if (appData.premove) {
2414 XtSetValues(XtNameToWidget(menuBarWidget,
2415 "menuOptions.Premove"), args, 1);
2417 if (appData.quietPlay) {
2418 XtSetValues(XtNameToWidget(menuBarWidget,
2419 "menuOptions.Quiet Play"), args, 1);
2421 if (appData.showCoords) {
2422 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2425 if (appData.hideThinkingFromHuman) {
2426 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2429 if (appData.testLegality) {
2430 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2433 if (saveSettingsOnExit) {
2434 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2441 ReadBitmap(&wIconPixmap, "icon_white.bm",
2442 icon_white_bits, icon_white_width, icon_white_height);
2443 ReadBitmap(&bIconPixmap, "icon_black.bm",
2444 icon_black_bits, icon_black_width, icon_black_height);
2445 iconPixmap = wIconPixmap;
2447 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2448 XtSetValues(shellWidget, args, i);
2451 * Create a cursor for the board widget.
2453 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2454 XChangeWindowAttributes(xDisplay, xBoardWindow,
2455 CWCursor, &window_attributes);
2458 * Inhibit shell resizing.
2460 shellArgs[0].value = (XtArgVal) &w;
2461 shellArgs[1].value = (XtArgVal) &h;
2462 XtGetValues(shellWidget, shellArgs, 2);
2463 shellArgs[4].value = shellArgs[2].value = w;
2464 shellArgs[5].value = shellArgs[3].value = h;
2465 XtSetValues(shellWidget, &shellArgs[2], 4);
2466 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2467 marginH = h - boardHeight;
2469 CatchDeleteWindow(shellWidget, "QuitProc");
2474 if (appData.bitmapDirectory[0] != NULLCHAR) {
2481 /* Create regular pieces */
2482 if (!useImages) CreatePieces();
2487 if (appData.animate || appData.animateDragging)
2490 XtAugmentTranslations(formWidget,
2491 XtParseTranslationTable(globalTranslations));
2492 XtAugmentTranslations(boardWidget,
2493 XtParseTranslationTable(boardTranslations));
2494 XtAugmentTranslations(whiteTimerWidget,
2495 XtParseTranslationTable(whiteTranslations));
2496 XtAugmentTranslations(blackTimerWidget,
2497 XtParseTranslationTable(blackTranslations));
2499 /* Why is the following needed on some versions of X instead
2500 * of a translation? */
2501 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2502 (XtEventHandler) EventProc, NULL);
2505 /* [AS] Restore layout */
2506 if( wpMoveHistory.visible ) {
2510 if( wpEvalGraph.visible )
2515 if( wpEngineOutput.visible ) {
2516 EngineOutputPopUp();
2521 if (errorExitStatus == -1) {
2522 if (appData.icsActive) {
2523 /* We now wait until we see "login:" from the ICS before
2524 sending the logon script (problems with timestamp otherwise) */
2525 /*ICSInitScript();*/
2526 if (appData.icsInputBox) ICSInputBoxPopUp();
2530 signal(SIGWINCH, TermSizeSigHandler);
2532 signal(SIGINT, IntSigHandler);
2533 signal(SIGTERM, IntSigHandler);
2534 if (*appData.cmailGameName != NULLCHAR) {
2535 signal(SIGUSR1, CmailSigHandler);
2538 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2540 XtSetKeyboardFocus(shellWidget, formWidget);
2542 XtAppMainLoop(appContext);
2543 if (appData.debugMode) fclose(debugFP); // [DM] debug
2550 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2551 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2553 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2554 unlink(gameCopyFilename);
2555 unlink(gamePasteFilename);
2558 RETSIGTYPE TermSizeSigHandler(int sig)
2571 CmailSigHandler(sig)
2577 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2579 /* Activate call-back function CmailSigHandlerCallBack() */
2580 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2582 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2586 CmailSigHandlerCallBack(isr, closure, message, count, error)
2594 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2596 /**** end signal code ****/
2606 f = fopen(appData.icsLogon, "r");
2612 strcat(buf, appData.icsLogon);
2613 f = fopen(buf, "r");
2617 ProcessICSInitScript(f);
2624 EditCommentPopDown();
2639 if (!menuBarWidget) return;
2640 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2642 DisplayError("menuStep.Revert", 0);
2644 XtSetSensitive(w, !grey);
2646 w = XtNameToWidget(menuBarWidget, "menuStep.Annotate");
2648 DisplayError("menuStep.Annotate", 0);
2650 XtSetSensitive(w, !grey);
2655 SetMenuEnables(enab)
2659 if (!menuBarWidget) return;
2660 while (enab->name != NULL) {
2661 w = XtNameToWidget(menuBarWidget, enab->name);
2663 DisplayError(enab->name, 0);
2665 XtSetSensitive(w, enab->value);
2671 Enables icsEnables[] = {
2672 { "menuFile.Mail Move", False },
2673 { "menuFile.Reload CMail Message", False },
2674 { "menuMode.Machine Black", False },
2675 { "menuMode.Machine White", False },
2676 { "menuMode.Analysis Mode", False },
2677 { "menuMode.Analyze File", False },
2678 { "menuMode.Two Machines", False },
2680 { "menuHelp.Hint", False },
2681 { "menuHelp.Book", False },
2682 { "menuStep.Move Now", False },
2683 { "menuOptions.Periodic Updates", False },
2684 { "menuOptions.Hide Thinking", False },
2685 { "menuOptions.Ponder Next Move", False },
2687 { "menuStep.Annotate", False },
2691 Enables ncpEnables[] = {
2692 { "menuFile.Mail Move", False },
2693 { "menuFile.Reload CMail Message", False },
2694 { "menuMode.Machine White", False },
2695 { "menuMode.Machine Black", False },
2696 { "menuMode.Analysis Mode", False },
2697 { "menuMode.Analyze File", False },
2698 { "menuMode.Two Machines", False },
2699 { "menuMode.ICS Client", False },
2700 { "menuMode.ICS Input Box", False },
2701 { "Action", False },
2702 { "menuStep.Revert", False },
2703 { "menuStep.Annotate", False },
2704 { "menuStep.Move Now", False },
2705 { "menuStep.Retract Move", False },
2706 { "menuOptions.Auto Comment", False },
2707 { "menuOptions.Auto Flag", False },
2708 { "menuOptions.Auto Flip View", False },
2709 { "menuOptions.Auto Observe", False },
2710 { "menuOptions.Auto Raise Board", False },
2711 { "menuOptions.Get Move List", False },
2712 { "menuOptions.ICS Alarm", False },
2713 { "menuOptions.Move Sound", False },
2714 { "menuOptions.Quiet Play", False },
2715 { "menuOptions.Hide Thinking", False },
2716 { "menuOptions.Periodic Updates", False },
2717 { "menuOptions.Ponder Next Move", False },
2718 { "menuHelp.Hint", False },
2719 { "menuHelp.Book", False },
2723 Enables gnuEnables[] = {
2724 { "menuMode.ICS Client", False },
2725 { "menuMode.ICS Input Box", False },
2726 { "menuAction.Accept", False },
2727 { "menuAction.Decline", False },
2728 { "menuAction.Rematch", False },
2729 { "menuAction.Adjourn", False },
2730 { "menuAction.Stop Examining", False },
2731 { "menuAction.Stop Observing", False },
2732 { "menuAction.Upload to Examine", False },
2733 { "menuStep.Revert", False },
2734 { "menuStep.Annotate", False },
2735 { "menuOptions.Auto Comment", False },
2736 { "menuOptions.Auto Observe", False },
2737 { "menuOptions.Auto Raise Board", False },
2738 { "menuOptions.Get Move List", False },
2739 { "menuOptions.Premove", False },
2740 { "menuOptions.Quiet Play", False },
2742 /* The next two options rely on SetCmailMode being called *after* */
2743 /* SetGNUMode so that when GNU is being used to give hints these */
2744 /* menu options are still available */
2746 { "menuFile.Mail Move", False },
2747 { "menuFile.Reload CMail Message", False },
2751 Enables cmailEnables[] = {
2753 { "menuAction.Call Flag", False },
2754 { "menuAction.Draw", True },
2755 { "menuAction.Adjourn", False },
2756 { "menuAction.Abort", False },
2757 { "menuAction.Stop Observing", False },
2758 { "menuAction.Stop Examining", False },
2759 { "menuFile.Mail Move", True },
2760 { "menuFile.Reload CMail Message", True },
2764 Enables trainingOnEnables[] = {
2765 { "menuMode.Edit Comment", False },
2766 { "menuMode.Pause", False },
2767 { "menuStep.Forward", False },
2768 { "menuStep.Backward", False },
2769 { "menuStep.Forward to End", False },
2770 { "menuStep.Back to Start", False },
2771 { "menuStep.Move Now", False },
2772 { "menuStep.Truncate Game", False },
2776 Enables trainingOffEnables[] = {
2777 { "menuMode.Edit Comment", True },
2778 { "menuMode.Pause", True },
2779 { "menuStep.Forward", True },
2780 { "menuStep.Backward", True },
2781 { "menuStep.Forward to End", True },
2782 { "menuStep.Back to Start", True },
2783 { "menuStep.Move Now", True },
2784 { "menuStep.Truncate Game", True },
2788 Enables machineThinkingEnables[] = {
2789 { "menuFile.Load Game", False },
2790 { "menuFile.Load Next Game", False },
2791 { "menuFile.Load Previous Game", False },
2792 { "menuFile.Reload Same Game", False },
2793 { "menuFile.Paste Game", False },
2794 { "menuFile.Load Position", False },
2795 { "menuFile.Load Next Position", False },
2796 { "menuFile.Load Previous Position", False },
2797 { "menuFile.Reload Same Position", False },
2798 { "menuFile.Paste Position", False },
2799 { "menuMode.Machine White", False },
2800 { "menuMode.Machine Black", False },
2801 { "menuMode.Two Machines", False },
2802 { "menuStep.Retract Move", False },
2806 Enables userThinkingEnables[] = {
2807 { "menuFile.Load Game", True },
2808 { "menuFile.Load Next Game", True },
2809 { "menuFile.Load Previous Game", True },
2810 { "menuFile.Reload Same Game", True },
2811 { "menuFile.Paste Game", True },
2812 { "menuFile.Load Position", True },
2813 { "menuFile.Load Next Position", True },
2814 { "menuFile.Load Previous Position", True },
2815 { "menuFile.Reload Same Position", True },
2816 { "menuFile.Paste Position", True },
2817 { "menuMode.Machine White", True },
2818 { "menuMode.Machine Black", True },
2819 { "menuMode.Two Machines", True },
2820 { "menuStep.Retract Move", True },
2826 SetMenuEnables(icsEnables);
2829 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2830 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2837 SetMenuEnables(ncpEnables);
2843 SetMenuEnables(gnuEnables);
2849 SetMenuEnables(cmailEnables);
2855 SetMenuEnables(trainingOnEnables);
2856 if (appData.showButtonBar) {
2857 XtSetSensitive(buttonBarWidget, False);
2863 SetTrainingModeOff()
2865 SetMenuEnables(trainingOffEnables);
2866 if (appData.showButtonBar) {
2867 XtSetSensitive(buttonBarWidget, True);
2872 SetUserThinkingEnables()
2874 if (appData.noChessProgram) return;
2875 SetMenuEnables(userThinkingEnables);
2879 SetMachineThinkingEnables()
2881 if (appData.noChessProgram) return;
2882 SetMenuEnables(machineThinkingEnables);
2884 case MachinePlaysBlack:
2885 case MachinePlaysWhite:
2886 case TwoMachinesPlay:
2887 XtSetSensitive(XtNameToWidget(menuBarWidget,
2888 ModeToWidgetName(gameMode)), True);
2895 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2896 #define HISTORY_SIZE 64
\r
2897 static char *history[HISTORY_SIZE];
\r
2898 int histIn = 0, histP = 0;
\r
2901 SaveInHistory(char *cmd)
\r
2903 if (history[histIn] != NULL) {
\r
2904 free(history[histIn]);
\r
2905 history[histIn] = NULL;
\r
2907 if (*cmd == NULLCHAR) return;
\r
2908 history[histIn] = StrSave(cmd);
\r
2909 histIn = (histIn + 1) % HISTORY_SIZE;
\r
2910 if (history[histIn] != NULL) {
\r
2911 free(history[histIn]);
\r
2912 history[histIn] = NULL;
\r
2918 PrevInHistory(char *cmd)
\r
2921 if (histP == histIn) {
\r
2922 if (history[histIn] != NULL) free(history[histIn]);
\r
2923 history[histIn] = StrSave(cmd);
\r
2925 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
2926 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
2928 return history[histP];
\r
2934 if (histP == histIn) return NULL;
\r
2935 histP = (histP + 1) % HISTORY_SIZE;
\r
2936 return history[histP];
\r
2938 // end of borrowed code
\r
2940 #define Abs(n) ((n)<0 ? -(n) : (n))
2943 * Find a font that matches "pattern" that is as close as
2944 * possible to the targetPxlSize. Prefer fonts that are k
2945 * pixels smaller to fonts that are k pixels larger. The
2946 * pattern must be in the X Consortium standard format,
2947 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2948 * The return value should be freed with XtFree when no
2951 char *FindFont(pattern, targetPxlSize)
2955 char **fonts, *p, *best, *scalable, *scalableTail;
2956 int i, j, nfonts, minerr, err, pxlSize;
2959 char **missing_list;
2961 char *def_string, *base_fnt_lst, strInt[3];
2963 XFontStruct **fnt_list;
2965 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2966 sprintf(strInt, "%d", targetPxlSize);
2967 p = strstr(pattern, "--");
2968 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2969 strcat(base_fnt_lst, strInt);
2970 strcat(base_fnt_lst, strchr(p + 2, '-'));
2972 if ((fntSet = XCreateFontSet(xDisplay,
2976 &def_string)) == NULL) {
2978 fprintf(stderr, _("Unable to create font set.\n"));
2982 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2984 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2986 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2987 programName, pattern);
2995 for (i=0; i<nfonts; i++) {
2998 if (*p != '-') continue;
3000 if (*p == NULLCHAR) break;
3001 if (*p++ == '-') j++;
3003 if (j < 7) continue;
3006 scalable = fonts[i];
3009 err = pxlSize - targetPxlSize;
3010 if (Abs(err) < Abs(minerr) ||
3011 (minerr > 0 && err < 0 && -err == minerr)) {
3017 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3018 /* If the error is too big and there is a scalable font,
3019 use the scalable font. */
3020 int headlen = scalableTail - scalable;
3021 p = (char *) XtMalloc(strlen(scalable) + 10);
3022 while (isdigit(*scalableTail)) scalableTail++;
3023 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3025 p = (char *) XtMalloc(strlen(best) + 1);
3028 if (appData.debugMode) {
3029 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3030 pattern, targetPxlSize, p);
3033 if (missing_count > 0)
3034 XFreeStringList(missing_list);
3035 XFreeFontSet(xDisplay, fntSet);
3037 XFreeFontNames(fonts);
3044 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3045 | GCBackground | GCFunction | GCPlaneMask;
3046 XGCValues gc_values;
3049 gc_values.plane_mask = AllPlanes;
3050 gc_values.line_width = lineGap;
3051 gc_values.line_style = LineSolid;
3052 gc_values.function = GXcopy;
3054 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3055 gc_values.background = XBlackPixel(xDisplay, xScreen);
3056 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3058 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3059 gc_values.background = XWhitePixel(xDisplay, xScreen);
3060 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3061 XSetFont(xDisplay, coordGC, coordFontID);
3063 // [HGM] make font for holdings counts (white on black0
3064 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3065 gc_values.background = XBlackPixel(xDisplay, xScreen);
3066 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3067 XSetFont(xDisplay, countGC, countFontID);
3069 if (appData.monoMode) {
3070 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3071 gc_values.background = XWhitePixel(xDisplay, xScreen);
3072 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3074 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3075 gc_values.background = XBlackPixel(xDisplay, xScreen);
3076 lightSquareGC = wbPieceGC
3077 = XtGetGC(shellWidget, value_mask, &gc_values);
3079 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3080 gc_values.background = XWhitePixel(xDisplay, xScreen);
3081 darkSquareGC = bwPieceGC
3082 = XtGetGC(shellWidget, value_mask, &gc_values);
3084 if (DefaultDepth(xDisplay, xScreen) == 1) {
3085 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3086 gc_values.function = GXcopyInverted;
3087 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3088 gc_values.function = GXcopy;
3089 if (XBlackPixel(xDisplay, xScreen) == 1) {
3090 bwPieceGC = darkSquareGC;
3091 wbPieceGC = copyInvertedGC;
3093 bwPieceGC = copyInvertedGC;
3094 wbPieceGC = lightSquareGC;
3098 gc_values.foreground = highlightSquareColor;
3099 gc_values.background = highlightSquareColor;
3100 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3102 gc_values.foreground = premoveHighlightColor;
3103 gc_values.background = premoveHighlightColor;
3104 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3106 gc_values.foreground = lightSquareColor;
3107 gc_values.background = darkSquareColor;
3108 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3110 gc_values.foreground = darkSquareColor;
3111 gc_values.background = lightSquareColor;
3112 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3114 gc_values.foreground = jailSquareColor;
3115 gc_values.background = jailSquareColor;
3116 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3118 gc_values.foreground = whitePieceColor;
3119 gc_values.background = darkSquareColor;
3120 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3122 gc_values.foreground = whitePieceColor;
3123 gc_values.background = lightSquareColor;
3124 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3126 gc_values.foreground = whitePieceColor;
3127 gc_values.background = jailSquareColor;
3128 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3130 gc_values.foreground = blackPieceColor;
3131 gc_values.background = darkSquareColor;
3132 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3134 gc_values.foreground = blackPieceColor;
3135 gc_values.background = lightSquareColor;
3136 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3138 gc_values.foreground = blackPieceColor;
3139 gc_values.background = jailSquareColor;
3140 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3144 void loadXIM(xim, xmask, filename, dest, mask)
3157 fp = fopen(filename, "rb");
3159 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3166 for (y=0; y<h; ++y) {
3167 for (x=0; x<h; ++x) {
3172 XPutPixel(xim, x, y, blackPieceColor);
3174 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3177 XPutPixel(xim, x, y, darkSquareColor);
3179 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3182 XPutPixel(xim, x, y, whitePieceColor);
3184 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3187 XPutPixel(xim, x, y, lightSquareColor);
3189 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3195 /* create Pixmap of piece */
3196 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3198 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3201 /* create Pixmap of clipmask
3202 Note: We assume the white/black pieces have the same
3203 outline, so we make only 6 masks. This is okay
3204 since the XPM clipmask routines do the same. */
3206 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3208 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3211 /* now create the 1-bit version */
3212 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3215 values.foreground = 1;
3216 values.background = 0;
3218 /* Don't use XtGetGC, not read only */
3219 maskGC = XCreateGC(xDisplay, *mask,
3220 GCForeground | GCBackground, &values);
3221 XCopyPlane(xDisplay, temp, *mask, maskGC,
3222 0, 0, squareSize, squareSize, 0, 0, 1);
3223 XFreePixmap(xDisplay, temp);
3228 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3230 void CreateXIMPieces()
3235 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3240 /* The XSynchronize calls were copied from CreatePieces.
3241 Not sure if needed, but can't hurt */
3242 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3245 /* temp needed by loadXIM() */
3246 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3247 0, 0, ss, ss, AllPlanes, XYPixmap);
3249 if (strlen(appData.pixmapDirectory) == 0) {
3253 if (appData.monoMode) {
3254 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3258 fprintf(stderr, _("\nLoading XIMs...\n"));
3260 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3261 fprintf(stderr, "%d", piece+1);
3262 for (kind=0; kind<4; kind++) {
3263 fprintf(stderr, ".");
3264 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3265 ExpandPathName(appData.pixmapDirectory),
3266 piece <= (int) WhiteKing ? "" : "w",
3267 pieceBitmapNames[piece],
3269 ximPieceBitmap[kind][piece] =
3270 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3271 0, 0, ss, ss, AllPlanes, XYPixmap);
3272 if (appData.debugMode)
3273 fprintf(stderr, _("(File:%s:) "), buf);
3274 loadXIM(ximPieceBitmap[kind][piece],
3276 &(xpmPieceBitmap2[kind][piece]),
3277 &(ximMaskPm2[piece]));
3278 if(piece <= (int)WhiteKing)
3279 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3281 fprintf(stderr," ");
3283 /* Load light and dark squares */
3284 /* If the LSQ and DSQ pieces don't exist, we will
3285 draw them with solid squares. */
3286 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3287 if (access(buf, 0) != 0) {
3291 fprintf(stderr, _("light square "));
3293 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3294 0, 0, ss, ss, AllPlanes, XYPixmap);
3295 if (appData.debugMode)
3296 fprintf(stderr, _("(File:%s:) "), buf);
3298 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3299 fprintf(stderr, _("dark square "));
3300 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3301 ExpandPathName(appData.pixmapDirectory), ss);
3302 if (appData.debugMode)
3303 fprintf(stderr, _("(File:%s:) "), buf);
3305 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3306 0, 0, ss, ss, AllPlanes, XYPixmap);
3307 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3308 xpmJailSquare = xpmLightSquare;
3310 fprintf(stderr, _("Done.\n"));
3312 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3316 void CreateXPMPieces()
3320 u_int ss = squareSize;
3322 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3323 XpmColorSymbol symbols[4];
3325 /* The XSynchronize calls were copied from CreatePieces.
3326 Not sure if needed, but can't hurt */
3327 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3329 /* Setup translations so piece colors match square colors */
3330 symbols[0].name = "light_piece";
3331 symbols[0].value = appData.whitePieceColor;
3332 symbols[1].name = "dark_piece";
3333 symbols[1].value = appData.blackPieceColor;
3334 symbols[2].name = "light_square";
3335 symbols[2].value = appData.lightSquareColor;
3336 symbols[3].name = "dark_square";
3337 symbols[3].value = appData.darkSquareColor;
3339 attr.valuemask = XpmColorSymbols;
3340 attr.colorsymbols = symbols;
3341 attr.numsymbols = 4;
3343 if (appData.monoMode) {
3344 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3348 if (strlen(appData.pixmapDirectory) == 0) {
3349 XpmPieces* pieces = builtInXpms;
3352 while (pieces->size != squareSize && pieces->size) pieces++;
3353 if (!pieces->size) {
3354 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3357 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3358 for (kind=0; kind<4; kind++) {
3360 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3361 pieces->xpm[piece][kind],
3362 &(xpmPieceBitmap2[kind][piece]),
3363 NULL, &attr)) != 0) {
3364 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3368 if(piece <= (int) WhiteKing)
3369 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3373 xpmJailSquare = xpmLightSquare;
3377 fprintf(stderr, _("\nLoading XPMs...\n"));
3380 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3381 fprintf(stderr, "%d ", piece+1);
3382 for (kind=0; kind<4; kind++) {
3383 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3384 ExpandPathName(appData.pixmapDirectory),
3385 piece > (int) WhiteKing ? "w" : "",
3386 pieceBitmapNames[piece],
3388 if (appData.debugMode) {
3389 fprintf(stderr, _("(File:%s:) "), buf);
3391 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3392 &(xpmPieceBitmap2[kind][piece]),
3393 NULL, &attr)) != 0) {
3394 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3395 // [HGM] missing: read of unorthodox piece failed; substitute King.
3396 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3397 ExpandPathName(appData.pixmapDirectory),
3399 if (appData.debugMode) {
3400 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3402 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3403 &(xpmPieceBitmap2[kind][piece]),
3407 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3412 if(piece <= (int) WhiteKing)
3413 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3416 /* Load light and dark squares */
3417 /* If the LSQ and DSQ pieces don't exist, we will
3418 draw them with solid squares. */
3419 fprintf(stderr, _("light square "));
3420 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3421 if (access(buf, 0) != 0) {
3425 if (appData.debugMode)
3426 fprintf(stderr, _("(File:%s:) "), buf);
3428 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3429 &xpmLightSquare, NULL, &attr)) != 0) {
3430 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3433 fprintf(stderr, _("dark square "));
3434 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3435 ExpandPathName(appData.pixmapDirectory), ss);
3436 if (appData.debugMode) {
3437 fprintf(stderr, _("(File:%s:) "), buf);
3439 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3440 &xpmDarkSquare, NULL, &attr)) != 0) {
3441 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3445 xpmJailSquare = xpmLightSquare;
3446 fprintf(stderr, _("Done.\n"));
3448 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3451 #endif /* HAVE_LIBXPM */
3454 /* No built-in bitmaps */
3459 u_int ss = squareSize;
3461 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3464 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3465 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3466 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3467 pieceBitmapNames[piece],
3468 ss, kind == SOLID ? 's' : 'o');
3469 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3470 if(piece <= (int)WhiteKing)
3471 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3475 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3479 /* With built-in bitmaps */
3482 BuiltInBits* bib = builtInBits;
3485 u_int ss = squareSize;
3487 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3490 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3492 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3493 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3494 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3495 pieceBitmapNames[piece],
3496 ss, kind == SOLID ? 's' : 'o');
3497 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3498 bib->bits[kind][piece], ss, ss);
3499 if(piece <= (int)WhiteKing)
3500 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3504 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3509 void ReadBitmap(pm, name, bits, wreq, hreq)
3512 unsigned char bits[];
3518 char msg[MSG_SIZ], fullname[MSG_SIZ];
3520 if (*appData.bitmapDirectory != NULLCHAR) {
3521 strcpy(fullname, appData.bitmapDirectory);
3522 strcat(fullname, "/");
3523 strcat(fullname, name);
3524 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3525 &w, &h, pm, &x_hot, &y_hot);
3526 fprintf(stderr, "load %s\n", name);
3527 if (errcode != BitmapSuccess) {
3529 case BitmapOpenFailed:
3530 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3532 case BitmapFileInvalid:
3533 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3535 case BitmapNoMemory:
3536 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3540 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3544 fprintf(stderr, _("%s: %s...using built-in\n"),
3546 } else if (w != wreq || h != hreq) {
3548 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3549 programName, fullname, w, h, wreq, hreq);
3555 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3564 if (lineGap == 0) return;
3566 /* [HR] Split this into 2 loops for non-square boards. */
3568 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3569 gridSegments[i].x1 = 0;
3570 gridSegments[i].x2 =
3571 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3572 gridSegments[i].y1 = gridSegments[i].y2
3573 = lineGap / 2 + (i * (squareSize + lineGap));
3576 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3577 gridSegments[j + i].y1 = 0;
3578 gridSegments[j + i].y2 =
3579 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3580 gridSegments[j + i].x1 = gridSegments[j + i].x2
3581 = lineGap / 2 + (j * (squareSize + lineGap));
3585 static void MenuBarSelect(w, addr, index)
3590 XtActionProc proc = (XtActionProc) addr;
3592 (proc)(NULL, NULL, NULL, NULL);
3595 void CreateMenuBarPopup(parent, name, mb)
3605 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3608 XtSetArg(args[j], XtNleftMargin, 20); j++;
3609 XtSetArg(args[j], XtNrightMargin, 20); j++;
3611 while (mi->string != NULL) {
3612 if (strcmp(mi->string, "----") == 0) {
3613 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3616 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3617 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3619 XtAddCallback(entry, XtNcallback,
3620 (XtCallbackProc) MenuBarSelect,
3621 (caddr_t) mi->proc);
3627 Widget CreateMenuBar(mb)
3631 Widget anchor, menuBar;
3633 char menuName[MSG_SIZ];
3636 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3637 XtSetArg(args[j], XtNvSpace, 0); j++;
3638 XtSetArg(args[j], XtNborderWidth, 0); j++;
3639 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3640 formWidget, args, j);
3642 while (mb->name != NULL) {
3643 strcpy(menuName, "menu");
3644 strcat(menuName, mb->name);
3646 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3649 shortName[0] = _(mb->name)[0];
3650 shortName[1] = NULLCHAR;
3651 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3654 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3657 XtSetArg(args[j], XtNborderWidth, 0); j++;
3658 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3660 CreateMenuBarPopup(menuBar, menuName, mb);
3666 Widget CreateButtonBar(mi)
3670 Widget button, buttonBar;
3674 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3676 XtSetArg(args[j], XtNhSpace, 0); j++;
3678 XtSetArg(args[j], XtNborderWidth, 0); j++;
3679 XtSetArg(args[j], XtNvSpace, 0); j++;
3680 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3681 formWidget, args, j);
3683 while (mi->string != NULL) {
3686 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3687 XtSetArg(args[j], XtNborderWidth, 0); j++;
3689 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3690 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3691 buttonBar, args, j);
3692 XtAddCallback(button, XtNcallback,
3693 (XtCallbackProc) MenuBarSelect,
3694 (caddr_t) mi->proc);
3701 CreatePieceMenu(name, color)
3708 ChessSquare selection;
3710 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3711 boardWidget, args, 0);
3713 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3714 String item = pieceMenuStrings[color][i];
3716 if (strcmp(item, "----") == 0) {
3717 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3720 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3721 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3723 selection = pieceMenuTranslation[color][i];
3724 XtAddCallback(entry, XtNcallback,
3725 (XtCallbackProc) PieceMenuSelect,
3726 (caddr_t) selection);
3727 if (selection == WhitePawn || selection == BlackPawn) {
3728 XtSetArg(args[0], XtNpopupOnEntry, entry);
3729 XtSetValues(menu, args, 1);
3742 ChessSquare selection;
3744 whitePieceMenu = CreatePieceMenu("menuW", 0);
3745 blackPieceMenu = CreatePieceMenu("menuB", 1);
3747 XtRegisterGrabAction(PieceMenuPopup, True,
3748 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3749 GrabModeAsync, GrabModeAsync);
3751 XtSetArg(args[0], XtNlabel, _("Drop"));
3752 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3753 boardWidget, args, 1);
3754 for (i = 0; i < DROP_MENU_SIZE; i++) {
3755 String item = dropMenuStrings[i];
3757 if (strcmp(item, "----") == 0) {
3758 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3761 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3762 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3764 selection = dropMenuTranslation[i];
3765 XtAddCallback(entry, XtNcallback,
3766 (XtCallbackProc) DropMenuSelect,
3767 (caddr_t) selection);
3772 void SetupDropMenu()
3780 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3781 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3782 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3783 dmEnables[i].piece);
3784 XtSetSensitive(entry, p != NULL || !appData.testLegality
3785 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3786 && !appData.icsActive));
3788 while (p && *p++ == dmEnables[i].piece) count++;
3789 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3791 XtSetArg(args[j], XtNlabel, label); j++;
3792 XtSetValues(entry, args, j);
3796 void PieceMenuPopup(w, event, params, num_params)
3800 Cardinal *num_params;
3802 String whichMenu; int menuNr;
3803 if (event->type == ButtonRelease)
3804 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3805 else if (event->type == ButtonPress)
3806 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3808 case 0: whichMenu = params[0]; break;
3809 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3811 case -1: if (errorUp) ErrorPopDown();
3814 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3817 static void PieceMenuSelect(w, piece, junk)
3822 if (pmFromX < 0 || pmFromY < 0) return;
3823 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3826 static void DropMenuSelect(w, piece, junk)
3831 if (pmFromX < 0 || pmFromY < 0) return;
3832 DropMenuEvent(piece, pmFromX, pmFromY);
3835 void WhiteClock(w, event, prms, nprms)
3841 if (gameMode == EditPosition || gameMode == IcsExamining) {
3842 SetWhiteToPlayEvent();
3843 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3848 void BlackClock(w, event, prms, nprms)
3854 if (gameMode == EditPosition || gameMode == IcsExamining) {
3855 SetBlackToPlayEvent();
3856 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3863 * If the user selects on a border boundary, return -1; if off the board,
3864 * return -2. Otherwise map the event coordinate to the square.
3866 int EventToSquare(x, limit)
3874 if ((x % (squareSize + lineGap)) >= squareSize)
3876 x /= (squareSize + lineGap);
3882 static void do_flash_delay(msec)
3888 static void drawHighlight(file, rank, gc)
3894 if (lineGap == 0 || appData.blindfold) return;
3897 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3898 (squareSize + lineGap);
3899 y = lineGap/2 + rank * (squareSize + lineGap);
3901 x = lineGap/2 + file * (squareSize + lineGap);
3902 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3903 (squareSize + lineGap);
3906 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3907 squareSize+lineGap, squareSize+lineGap);
3910 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3911 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3914 SetHighlights(fromX, fromY, toX, toY)
3915 int fromX, fromY, toX, toY;
3917 if (hi1X != fromX || hi1Y != fromY) {
3918 if (hi1X >= 0 && hi1Y >= 0) {
3919 drawHighlight(hi1X, hi1Y, lineGC);
3921 } // [HGM] first erase both, then draw new!
3922 if (hi2X != toX || hi2Y != toY) {
3923 if (hi2X >= 0 && hi2Y >= 0) {
3924 drawHighlight(hi2X, hi2Y, lineGC);
3927 if (hi1X != fromX || hi1Y != fromY) {
3928 if (fromX >= 0 && fromY >= 0) {
3929 drawHighlight(fromX, fromY, highlineGC);
3932 if (hi2X != toX || hi2Y != toY) {
3933 if (toX >= 0 && toY >= 0) {
3934 drawHighlight(toX, toY, highlineGC);
3946 SetHighlights(-1, -1, -1, -1);
3951 SetPremoveHighlights(fromX, fromY, toX, toY)
3952 int fromX, fromY, toX, toY;
3954 if (pm1X != fromX || pm1Y != fromY) {
3955 if (pm1X >= 0 && pm1Y >= 0) {
3956 drawHighlight(pm1X, pm1Y, lineGC);
3958 if (fromX >= 0 && fromY >= 0) {
3959 drawHighlight(fromX, fromY, prelineGC);
3962 if (pm2X != toX || pm2Y != toY) {
3963 if (pm2X >= 0 && pm2Y >= 0) {
3964 drawHighlight(pm2X, pm2Y, lineGC);
3966 if (toX >= 0 && toY >= 0) {
3967 drawHighlight(toX, toY, prelineGC);
3977 ClearPremoveHighlights()
3979 SetPremoveHighlights(-1, -1, -1, -1);
3982 static void BlankSquare(x, y, color, piece, dest)
3987 if (useImages && useImageSqs) {
3991 pm = xpmLightSquare;
3996 case 2: /* neutral */
4001 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4002 squareSize, squareSize, x, y);
4012 case 2: /* neutral */
4017 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
4022 I split out the routines to draw a piece so that I could
4023 make a generic flash routine.
4025 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4027 int square_color, x, y;
4030 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4031 switch (square_color) {
4033 case 2: /* neutral */
4035 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4036 ? *pieceToOutline(piece)
4037 : *pieceToSolid(piece),
4038 dest, bwPieceGC, 0, 0,
4039 squareSize, squareSize, x, y);
4042 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4043 ? *pieceToSolid(piece)
4044 : *pieceToOutline(piece),
4045 dest, wbPieceGC, 0, 0,
4046 squareSize, squareSize, x, y);
4051 static void monoDrawPiece(piece, square_color, x, y, dest)
4053 int square_color, x, y;
4056 switch (square_color) {
4058 case 2: /* neutral */
4060 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4061 ? *pieceToOutline(piece)
4062 : *pieceToSolid(piece),
4063 dest, bwPieceGC, 0, 0,
4064 squareSize, squareSize, x, y, 1);
4067 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4068 ? *pieceToSolid(piece)
4069 : *pieceToOutline(piece),
4070 dest, wbPieceGC, 0, 0,
4071 squareSize, squareSize, x, y, 1);
4076 static void colorDrawPiece(piece, square_color, x, y, dest)
4078 int square_color, x, y;
4081 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4082 switch (square_color) {
4084 XCopyPlane(xDisplay, *pieceToSolid(piece),
4085 dest, (int) piece < (int) BlackPawn
4086 ? wlPieceGC : blPieceGC, 0, 0,
4087 squareSize, squareSize, x, y, 1);
4090 XCopyPlane(xDisplay, *pieceToSolid(piece),
4091 dest, (int) piece < (int) BlackPawn
4092 ? wdPieceGC : bdPieceGC, 0, 0,
4093 squareSize, squareSize, x, y, 1);
4095 case 2: /* neutral */
4097 XCopyPlane(xDisplay, *pieceToSolid(piece),
4098 dest, (int) piece < (int) BlackPawn
4099 ? wjPieceGC : bjPieceGC, 0, 0,
4100 squareSize, squareSize, x, y, 1);
4105 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4107 int square_color, x, y;
4112 switch (square_color) {
4114 case 2: /* neutral */
4116 if ((int)piece < (int) BlackPawn) {
4124 if ((int)piece < (int) BlackPawn) {
4132 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4133 dest, wlPieceGC, 0, 0,
4134 squareSize, squareSize, x, y);
4137 typedef void (*DrawFunc)();
4139 DrawFunc ChooseDrawFunc()
4141 if (appData.monoMode) {
4142 if (DefaultDepth(xDisplay, xScreen) == 1) {
4143 return monoDrawPiece_1bit;
4145 return monoDrawPiece;
4149 return colorDrawPieceImage;
4151 return colorDrawPiece;
4155 /* [HR] determine square color depending on chess variant. */
4156 static int SquareColor(row, column)
4161 if (gameInfo.variant == VariantXiangqi) {
4162 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4164 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4166 } else if (row <= 4) {
4172 square_color = ((column + row) % 2) == 1;
4175 /* [hgm] holdings: next line makes all holdings squares light */
4176 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4178 return square_color;
4181 void DrawSquare(row, column, piece, do_flash)
4182 int row, column, do_flash;
4185 int square_color, x, y, direction, font_ascent, font_descent;
4188 XCharStruct overall;
4192 /* Calculate delay in milliseconds (2-delays per complete flash) */
4193 flash_delay = 500 / appData.flashRate;
4196 x = lineGap + ((BOARD_WIDTH-1)-column) *
4197 (squareSize + lineGap);
4198 y = lineGap + row * (squareSize + lineGap);
4200 x = lineGap + column * (squareSize + lineGap);
4201 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4202 (squareSize + lineGap);
4205 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4207 square_color = SquareColor(row, column);
4209 if ( // [HGM] holdings: blank out area between board and holdings
4210 column == BOARD_LEFT-1 || column == BOARD_RGHT
4211 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4212 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4213 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4215 // [HGM] print piece counts next to holdings
4216 string[1] = NULLCHAR;
4217 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4218 string[0] = '0' + piece;
4219 XTextExtents(countFontStruct, string, 1, &direction,
4220 &font_ascent, &font_descent, &overall);
4221 if (appData.monoMode) {
4222 XDrawImageString(xDisplay, xBoardWindow, countGC,
4223 x + squareSize - overall.width - 2,
4224 y + font_ascent + 1, string, 1);
4226 XDrawString(xDisplay, xBoardWindow, countGC,
4227 x + squareSize - overall.width - 2,
4228 y + font_ascent + 1, string, 1);
4231 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4232 string[0] = '0' + piece;
4233 XTextExtents(countFontStruct, string, 1, &direction,
4234 &font_ascent, &font_descent, &overall);
4235 if (appData.monoMode) {
4236 XDrawImageString(xDisplay, xBoardWindow, countGC,
4237 x + 2, y + font_ascent + 1, string, 1);
4239 XDrawString(xDisplay, xBoardWindow, countGC,
4240 x + 2, y + font_ascent + 1, string, 1);
4244 if (piece == EmptySquare || appData.blindfold) {
4245 BlankSquare(x, y, square_color, piece, xBoardWindow);
4247 drawfunc = ChooseDrawFunc();
4248 if (do_flash && appData.flashCount > 0) {
4249 for (i=0; i<appData.flashCount; ++i) {
4251 drawfunc(piece, square_color, x, y, xBoardWindow);
4252 XSync(xDisplay, False);
4253 do_flash_delay(flash_delay);
4255 BlankSquare(x, y, square_color, piece, xBoardWindow);
4256 XSync(xDisplay, False);
4257 do_flash_delay(flash_delay);
4260 drawfunc(piece, square_color, x, y, xBoardWindow);
4264 string[1] = NULLCHAR;
4265 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4266 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4267 string[0] = 'a' + column - BOARD_LEFT;
4268 XTextExtents(coordFontStruct, string, 1, &direction,
4269 &font_ascent, &font_descent, &overall);
4270 if (appData.monoMode) {
4271 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4272 x + squareSize - overall.width - 2,
4273 y + squareSize - font_descent - 1, string, 1);
4275 XDrawString(xDisplay, xBoardWindow, coordGC,
4276 x + squareSize - overall.width - 2,
4277 y + squareSize - font_descent - 1, string, 1);
4280 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4281 string[0] = ONE + row;
4282 XTextExtents(coordFontStruct, string, 1, &direction,
4283 &font_ascent, &font_descent, &overall);
4284 if (appData.monoMode) {
4285 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4286 x + 2, y + font_ascent + 1, string, 1);
4288 XDrawString(xDisplay, xBoardWindow, coordGC,
4289 x + 2, y + font_ascent + 1, string, 1);
4292 if(!partnerUp && marker[row][column]) {
4293 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4294 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4299 /* Why is this needed on some versions of X? */
4300 void EventProc(widget, unused, event)
4305 if (!XtIsRealized(widget))
4308 switch (event->type) {
4310 if (event->xexpose.count > 0) return; /* no clipping is done */
4311 XDrawPosition(widget, True, NULL);
4312 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4313 flipView = !flipView; partnerUp = !partnerUp;
4314 XDrawPosition(widget, True, NULL);
4315 flipView = !flipView; partnerUp = !partnerUp;
4319 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
\r
4326 void DrawPosition(fullRedraw, board)
4327 /*Boolean*/int fullRedraw;
4330 XDrawPosition(boardWidget, fullRedraw, board);
4333 /* Returns 1 if there are "too many" differences between b1 and b2
4334 (i.e. more than 1 move was made) */
4335 static int too_many_diffs(b1, b2)
4341 for (i=0; i<BOARD_HEIGHT; ++i) {
4342 for (j=0; j<BOARD_WIDTH; ++j) {
4343 if (b1[i][j] != b2[i][j]) {
4344 if (++c > 4) /* Castling causes 4 diffs */
4353 /* Matrix describing castling maneuvers */
4354 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4355 static int castling_matrix[4][5] = {
4356 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4357 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4358 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4359 { 7, 7, 4, 5, 6 } /* 0-0, black */
4362 /* Checks whether castling occurred. If it did, *rrow and *rcol
4363 are set to the destination (row,col) of the rook that moved.
4365 Returns 1 if castling occurred, 0 if not.
4367 Note: Only handles a max of 1 castling move, so be sure
4368 to call too_many_diffs() first.
4370 static int check_castle_draw(newb, oldb, rrow, rcol)
4377 /* For each type of castling... */
4378 for (i=0; i<4; ++i) {
4379 r = castling_matrix[i];
4381 /* Check the 4 squares involved in the castling move */
4383 for (j=1; j<=4; ++j) {
4384 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4391 /* All 4 changed, so it must be a castling move */
4400 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4401 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4403 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4406 void DrawSeekBackground( int left, int top, int right, int bottom )
4408 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4411 void DrawSeekText(char *buf, int x, int y)
4413 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4416 void DrawSeekDot(int x, int y, int colorNr)
4418 int square = colorNr & 0x80;
4421 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4423 XFillRectangle(xDisplay, xBoardWindow, color,
4424 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4426 XFillArc(xDisplay, xBoardWindow, color,
4427 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4430 static int damage[2][BOARD_RANKS][BOARD_FILES];
4433 * event handler for redrawing the board
4435 void XDrawPosition(w, repaint, board)
4437 /*Boolean*/int repaint;
4441 static int lastFlipView = 0;
4442 static int lastBoardValid[2] = {0, 0};
4443 static Board lastBoard[2];
4446 int nr = twoBoards*partnerUp;
4448 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4450 if (board == NULL) {
4451 if (!lastBoardValid) return;
4452 board = lastBoard[nr];
4454 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4455 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4456 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4461 * It would be simpler to clear the window with XClearWindow()
4462 * but this causes a very distracting flicker.
4465 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4467 /* If too much changes (begin observing new game, etc.), don't
4469 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4471 /* Special check for castling so we don't flash both the king
4472 and the rook (just flash the king). */
4474 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4475 /* Draw rook with NO flashing. King will be drawn flashing later */
4476 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4477 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4481 /* First pass -- Draw (newly) empty squares and repair damage.
4482 This prevents you from having a piece show up twice while it
4483 is flashing on its new square */
4484 for (i = 0; i < BOARD_HEIGHT; i++)
4485 for (j = 0; j < BOARD_WIDTH; j++)
4486 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4487 || damage[nr][i][j]) {
4488 DrawSquare(i, j, board[i][j], 0);
4489 damage[nr][i][j] = False;
4492 /* Second pass -- Draw piece(s) in new position and flash them */
4493 for (i = 0; i < BOARD_HEIGHT; i++)
4494 for (j = 0; j < BOARD_WIDTH; j++)
4495 if (board[i][j] != lastBoard[nr][i][j]) {
4496 DrawSquare(i, j, board[i][j], do_flash);
4500 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4501 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4502 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4504 for (i = 0; i < BOARD_HEIGHT; i++)
4505 for (j = 0; j < BOARD_WIDTH; j++) {
4506 DrawSquare(i, j, board[i][j], 0);
4507 damage[nr][i][j] = False;
4511 CopyBoard(lastBoard[nr], board);
4512 lastBoardValid[nr] = 1;
4513 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4514 lastFlipView = flipView;
4516 /* Draw highlights */
4517 if (pm1X >= 0 && pm1Y >= 0) {
4518 drawHighlight(pm1X, pm1Y, prelineGC);
4520 if (pm2X >= 0 && pm2Y >= 0) {
4521 drawHighlight(pm2X, pm2Y, prelineGC);
4523 if (hi1X >= 0 && hi1Y >= 0) {
4524 drawHighlight(hi1X, hi1Y, highlineGC);
4526 if (hi2X >= 0 && hi2Y >= 0) {
4527 drawHighlight(hi2X, hi2Y, highlineGC);
4530 /* If piece being dragged around board, must redraw that too */
4533 XSync(xDisplay, False);
4538 * event handler for redrawing the board
4540 void DrawPositionProc(w, event, prms, nprms)
4546 XDrawPosition(w, True, NULL);
4551 * event handler for parsing user moves
4553 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4554 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4555 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4556 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4557 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4558 // and at the end FinishMove() to perform the move after optional promotion popups.
4559 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4560 void HandleUserMove(w, event, prms, nprms)
4566 if (w != boardWidget || errorExitStatus != -1) return;
4569 if (event->type == ButtonPress) {
4570 XtPopdown(promotionShell);
4571 XtDestroyWidget(promotionShell);
4572 promotionUp = False;
4580 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4581 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4582 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4585 void AnimateUserMove (Widget w, XEvent * event,
4586 String * params, Cardinal * nParams)
4588 DragPieceMove(event->xmotion.x, event->xmotion.y);
4591 void HandlePV (Widget w, XEvent * event,
4592 String * params, Cardinal * nParams)
4593 { // [HGM] pv: walk PV
4594 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4597 Widget CommentCreate(name, text, mutable, callback, lines)
4599 int /*Boolean*/ mutable;
4600 XtCallbackProc callback;
4604 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4609 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4610 XtGetValues(boardWidget, args, j);
4613 XtSetArg(args[j], XtNresizable, True); j++;
4616 XtCreatePopupShell(name, topLevelShellWidgetClass,
4617 shellWidget, args, j);
4620 XtCreatePopupShell(name, transientShellWidgetClass,
4621 shellWidget, args, j);
4624 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4625 layoutArgs, XtNumber(layoutArgs));
4627 XtCreateManagedWidget("form", formWidgetClass, layout,
4628 formArgs, XtNumber(formArgs));
4632 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4633 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4635 XtSetArg(args[j], XtNstring, text); j++;
4636 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4637 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4638 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4639 XtSetArg(args[j], XtNright, XtChainRight); j++;
4640 XtSetArg(args[j], XtNresizable, True); j++;
4641 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4642 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4643 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4644 XtSetArg(args[j], XtNautoFill, True); j++;
4645 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4647 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4651 XtSetArg(args[j], XtNfromVert, edit); j++;
4652 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4653 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4654 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4655 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4657 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4658 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4661 XtSetArg(args[j], XtNfromVert, edit); j++;
4662 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4663 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4664 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4665 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4666 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4668 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4669 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4672 XtSetArg(args[j], XtNfromVert, edit); j++;
4673 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4674 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4675 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4676 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4677 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4679 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4680 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4683 XtSetArg(args[j], XtNfromVert, edit); j++;
4684 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4685 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4686 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4687 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4689 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4690 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4693 XtSetArg(args[j], XtNfromVert, edit); j++;
4694 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4695 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4696 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4697 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4698 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4700 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4701 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4704 XtRealizeWidget(shell);
4706 if (commentX == -1) {
4709 Dimension pw_height;
4710 Dimension ew_height;
4713 XtSetArg(args[j], XtNheight, &ew_height); j++;
4714 XtGetValues(edit, args, j);
4717 XtSetArg(args[j], XtNheight, &pw_height); j++;
4718 XtGetValues(shell, args, j);
4719 commentH = pw_height + (lines - 1) * ew_height;
4720 commentW = bw_width - 16;
4722 XSync(xDisplay, False);
4724 /* This code seems to tickle an X bug if it is executed too soon
4725 after xboard starts up. The coordinates get transformed as if
4726 the main window was positioned at (0, 0).
4728 XtTranslateCoords(shellWidget,
4729 (bw_width - commentW) / 2, 0 - commentH / 2,
4730 &commentX, &commentY);
4732 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4733 RootWindowOfScreen(XtScreen(shellWidget)),
4734 (bw_width - commentW) / 2, 0 - commentH / 2,
4739 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4742 if(wpComment.width > 0) {
4743 commentX = wpComment.x;
4744 commentY = wpComment.y;
4745 commentW = wpComment.width;
4746 commentH = wpComment.height;
4750 XtSetArg(args[j], XtNheight, commentH); j++;
4751 XtSetArg(args[j], XtNwidth, commentW); j++;
4752 XtSetArg(args[j], XtNx, commentX); j++;
4753 XtSetArg(args[j], XtNy, commentY); j++;
4754 XtSetValues(shell, args, j);
4755 XtSetKeyboardFocus(shell, edit);
4760 /* Used for analysis window and ICS input window */
4761 Widget MiscCreate(name, text, mutable, callback, lines)
4763 int /*Boolean*/ mutable;
4764 XtCallbackProc callback;
4768 Widget shell, layout, form, edit;
4770 Dimension bw_width, pw_height, ew_height, w, h;
4776 XtSetArg(args[j], XtNresizable, True); j++;
4779 XtCreatePopupShell(name, topLevelShellWidgetClass,
4780 shellWidget, args, j);
4783 XtCreatePopupShell(name, transientShellWidgetClass,
4784 shellWidget, args, j);
4787 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4788 layoutArgs, XtNumber(layoutArgs));
4790 XtCreateManagedWidget("form", formWidgetClass, layout,
4791 formArgs, XtNumber(formArgs));
4795 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4796 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4798 XtSetArg(args[j], XtNstring, text); j++;
4799 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4800 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4801 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4802 XtSetArg(args[j], XtNright, XtChainRight); j++;
4803 XtSetArg(args[j], XtNresizable, True); j++;
4804 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4805 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4806 XtSetArg(args[j], XtNautoFill, True); j++;
4807 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4809 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4811 XtRealizeWidget(shell);
4814 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4815 XtGetValues(boardWidget, args, j);
4818 XtSetArg(args[j], XtNheight, &ew_height); j++;
4819 XtGetValues(edit, args, j);
4822 XtSetArg(args[j], XtNheight, &pw_height); j++;
4823 XtGetValues(shell, args, j);
4824 h = pw_height + (lines - 1) * ew_height;
4827 XSync(xDisplay, False);
4829 /* This code seems to tickle an X bug if it is executed too soon
4830 after xboard starts up. The coordinates get transformed as if
4831 the main window was positioned at (0, 0).
4833 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4835 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4836 RootWindowOfScreen(XtScreen(shellWidget)),
4837 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4841 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4844 XtSetArg(args[j], XtNheight, h); j++;
4845 XtSetArg(args[j], XtNwidth, w); j++;
4846 XtSetArg(args[j], XtNx, x); j++;
4847 XtSetArg(args[j], XtNy, y); j++;
4848 XtSetValues(shell, args, j);
4854 static int savedIndex; /* gross that this is global */
4856 void EditCommentPopUp(index, title, text)
4865 if (text == NULL) text = "";
4867 if (editShell == NULL) {
4869 CommentCreate(title, text, True, EditCommentCallback, 4);
4870 XtRealizeWidget(editShell);
4871 CatchDeleteWindow(editShell, "EditCommentPopDown");
4873 edit = XtNameToWidget(editShell, "*form.text");
4875 XtSetArg(args[j], XtNstring, text); j++;
4876 XtSetValues(edit, args, j);
4878 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4879 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4880 XtSetValues(editShell, args, j);
4883 XtPopup(editShell, XtGrabNone);
4887 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4888 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4892 void EditCommentCallback(w, client_data, call_data)
4894 XtPointer client_data, call_data;
4902 XtSetArg(args[j], XtNlabel, &name); j++;
4903 XtGetValues(w, args, j);
4905 if (strcmp(name, _("ok")) == 0) {
4906 edit = XtNameToWidget(editShell, "*form.text");
4908 XtSetArg(args[j], XtNstring, &val); j++;
4909 XtGetValues(edit, args, j);
4910 ReplaceComment(savedIndex, val);
4911 EditCommentPopDown();
4912 } else if (strcmp(name, _("cancel")) == 0) {
4913 EditCommentPopDown();
4914 } else if (strcmp(name, _("clear")) == 0) {
4915 edit = XtNameToWidget(editShell, "*form.text");
4916 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4917 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4921 void EditCommentPopDown()
4926 if (!editUp) return;
4928 XtSetArg(args[j], XtNx, &commentX); j++;
4929 XtSetArg(args[j], XtNy, &commentY); j++;
4930 XtSetArg(args[j], XtNheight, &commentH); j++;
4931 XtSetArg(args[j], XtNwidth, &commentW); j++;
4932 XtGetValues(editShell, args, j);
4933 XtPopdown(editShell);
4936 XtSetArg(args[j], XtNleftBitmap, None); j++;
4937 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4941 void ICSInputBoxPopUp()
4946 char *title = _("ICS Input");
4949 if (ICSInputShell == NULL) {
4950 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
4951 tr = XtParseTranslationTable(ICSInputTranslations);
4952 edit = XtNameToWidget(ICSInputShell, "*form.text");
4953 XtOverrideTranslations(edit, tr);
4954 XtRealizeWidget(ICSInputShell);
4955 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
4958 edit = XtNameToWidget(ICSInputShell, "*form.text");
4960 XtSetArg(args[j], XtNstring, ""); j++;
4961 XtSetValues(edit, args, j);
4963 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4964 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4965 XtSetValues(ICSInputShell, args, j);
4968 XtPopup(ICSInputShell, XtGrabNone);
4969 XtSetKeyboardFocus(ICSInputShell, edit);
4971 ICSInputBoxUp = True;
4973 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4974 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4978 void ICSInputSendText()
4985 edit = XtNameToWidget(ICSInputShell, "*form.text");
4987 XtSetArg(args[j], XtNstring, &val); j++;
4988 XtGetValues(edit, args, j);
4990 SendMultiLineToICS(val);
4991 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4992 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4995 void ICSInputBoxPopDown()
5000 if (!ICSInputBoxUp) return;
5002 XtPopdown(ICSInputShell);
5003 ICSInputBoxUp = False;
5005 XtSetArg(args[j], XtNleftBitmap, None); j++;
5006 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
5010 void CommentPopUp(title, text)
5017 if (commentShell == NULL) {
5019 CommentCreate(title, text, False, CommentCallback, 4);
5020 XtRealizeWidget(commentShell);
5021 CatchDeleteWindow(commentShell, "CommentPopDown");
5023 edit = XtNameToWidget(commentShell, "*form.text");
5025 XtSetArg(args[j], XtNstring, text); j++;
5026 XtSetValues(edit, args, j);
5028 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5029 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5030 XtSetValues(commentShell, args, j);
5033 XtPopup(commentShell, XtGrabNone);
5034 XSync(xDisplay, False);
5039 void CommentCallback(w, client_data, call_data)
5041 XtPointer client_data, call_data;
5048 XtSetArg(args[j], XtNlabel, &name); j++;
5049 XtGetValues(w, args, j);
5051 if (strcmp(name, _("close")) == 0) {
5053 } else if (strcmp(name, _("edit")) == 0) {
5060 void CommentPopDown()
5065 if (!commentUp) return;
5067 XtSetArg(args[j], XtNx, &commentX); j++;
5068 XtSetArg(args[j], XtNy, &commentY); j++;
5069 XtSetArg(args[j], XtNwidth, &commentW); j++;
5070 XtSetArg(args[j], XtNheight, &commentH); j++;
5071 XtGetValues(commentShell, args, j);
5072 XtPopdown(commentShell);
5073 XSync(xDisplay, False);
5077 void FileNamePopUp(label, def, proc, openMode)
5084 Widget popup, layout, dialog, edit;
5090 fileProc = proc; /* I can't see a way not */
5091 fileOpenMode = openMode; /* to use globals here */
5092 { // [HGM] use file-selector dialog stolen from Ghostview
5094 int index; // this is not supported yet
5096 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5097 NULL, openMode, NULL, &name))
5098 (void) (*fileProc)(f, index=0, name);
5102 void FileNamePopDown()
5104 if (!filenameUp) return;
5105 XtPopdown(fileNameShell);
5106 XtDestroyWidget(fileNameShell);
5111 void FileNameCallback(w, client_data, call_data)
5113 XtPointer client_data, call_data;
5118 XtSetArg(args[0], XtNlabel, &name);
5119 XtGetValues(w, args, 1);
5121 if (strcmp(name, _("cancel")) == 0) {
5126 FileNameAction(w, NULL, NULL, NULL);
5129 void FileNameAction(w, event, prms, nprms)
5141 name = XawDialogGetValueString(w = XtParent(w));
5143 if ((name != NULL) && (*name != NULLCHAR)) {
5145 XtPopdown(w = XtParent(XtParent(w)));
5149 p = strrchr(buf, ' ');
5156 fullname = ExpandPathName(buf);
5158 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5161 f = fopen(fullname, fileOpenMode);
5163 DisplayError(_("Failed to open file"), errno);
5165 (void) (*fileProc)(f, index, buf);
5172 XtPopdown(w = XtParent(XtParent(w)));
5178 void PromotionPopUp()
5181 Widget dialog, layout;
5183 Dimension bw_width, pw_width;
5187 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5188 XtGetValues(boardWidget, args, j);
5191 XtSetArg(args[j], XtNresizable, True); j++;
5192 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5194 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5195 shellWidget, args, j);
5197 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5198 layoutArgs, XtNumber(layoutArgs));
5201 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5202 XtSetArg(args[j], XtNborderWidth, 0); j++;
5203 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5206 if(gameInfo.variant != VariantShogi) {
5207 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5208 (XtPointer) dialog);
5209 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5210 (XtPointer) dialog);
5211 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5212 (XtPointer) dialog);
5213 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5214 (XtPointer) dialog);
5215 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5216 gameInfo.variant == VariantGiveaway) {
5217 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5218 (XtPointer) dialog);
5220 if(gameInfo.variant == VariantCapablanca ||
5221 gameInfo.variant == VariantGothic ||
5222 gameInfo.variant == VariantCapaRandom) {
5223 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5224 (XtPointer) dialog);
5225 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5226 (XtPointer) dialog);
5228 } else // [HGM] shogi
5230 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5231 (XtPointer) dialog);
5232 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5233 (XtPointer) dialog);
5235 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5236 (XtPointer) dialog);
5238 XtRealizeWidget(promotionShell);
5239 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5242 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5243 XtGetValues(promotionShell, args, j);
5245 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5246 lineGap + squareSize/3 +
5247 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5248 0 : 6*(squareSize + lineGap)), &x, &y);
5251 XtSetArg(args[j], XtNx, x); j++;
5252 XtSetArg(args[j], XtNy, y); j++;
5253 XtSetValues(promotionShell, args, j);
5255 XtPopup(promotionShell, XtGrabNone);
5260 void PromotionPopDown()
5262 if (!promotionUp) return;
5263 XtPopdown(promotionShell);
5264 XtDestroyWidget(promotionShell);
5265 promotionUp = False;
5268 void PromotionCallback(w, client_data, call_data)
5270 XtPointer client_data, call_data;
5276 XtSetArg(args[0], XtNlabel, &name);
5277 XtGetValues(w, args, 1);
5281 if (fromX == -1) return;
5283 if (strcmp(name, _("cancel")) == 0) {
5287 } else if (strcmp(name, _("Knight")) == 0) {
5289 } else if (strcmp(name, _("Promote")) == 0) {
5291 } else if (strcmp(name, _("Defer")) == 0) {
5294 promoChar = ToLower(name[0]);
5297 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5299 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5300 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5305 void ErrorCallback(w, client_data, call_data)
5307 XtPointer client_data, call_data;
5310 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5312 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5318 if (!errorUp) return;
5320 XtPopdown(errorShell);
5321 XtDestroyWidget(errorShell);
5322 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5325 void ErrorPopUp(title, label, modal)
5326 char *title, *label;
5330 Widget dialog, layout;
5334 Dimension bw_width, pw_width;
5335 Dimension pw_height;
5339 XtSetArg(args[i], XtNresizable, True); i++;
5340 XtSetArg(args[i], XtNtitle, title); i++;
5342 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5343 shellWidget, args, i);
5345 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5346 layoutArgs, XtNumber(layoutArgs));
5349 XtSetArg(args[i], XtNlabel, label); i++;
5350 XtSetArg(args[i], XtNborderWidth, 0); i++;
5351 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5354 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5356 XtRealizeWidget(errorShell);
5357 CatchDeleteWindow(errorShell, "ErrorPopDown");
5360 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5361 XtGetValues(boardWidget, args, i);
5363 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5364 XtSetArg(args[i], XtNheight, &pw_height); i++;
5365 XtGetValues(errorShell, args, i);
5368 /* This code seems to tickle an X bug if it is executed too soon
5369 after xboard starts up. The coordinates get transformed as if
5370 the main window was positioned at (0, 0).
5372 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5373 0 - pw_height + squareSize / 3, &x, &y);
5375 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5376 RootWindowOfScreen(XtScreen(boardWidget)),
5377 (bw_width - pw_width) / 2,
5378 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5382 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5385 XtSetArg(args[i], XtNx, x); i++;
5386 XtSetArg(args[i], XtNy, y); i++;
5387 XtSetValues(errorShell, args, i);
5390 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5393 /* Disable all user input other than deleting the window */
5394 static int frozen = 0;
5398 /* Grab by a widget that doesn't accept input */
5399 XtAddGrab(messageWidget, TRUE, FALSE);
5403 /* Undo a FreezeUI */
5406 if (!frozen) return;
5407 XtRemoveGrab(messageWidget);
5411 char *ModeToWidgetName(mode)
5415 case BeginningOfGame:
5416 if (appData.icsActive)
5417 return "menuMode.ICS Client";
5418 else if (appData.noChessProgram ||
5419 *appData.cmailGameName != NULLCHAR)
5420 return "menuMode.Edit Game";
5422 return "menuMode.Machine Black";
5423 case MachinePlaysBlack:
5424 return "menuMode.Machine Black";
5425 case MachinePlaysWhite:
5426 return "menuMode.Machine White";
5428 return "menuMode.Analysis Mode";
5430 return "menuMode.Analyze File";
5431 case TwoMachinesPlay:
5432 return "menuMode.Two Machines";
5434 return "menuMode.Edit Game";
5435 case PlayFromGameFile:
5436 return "menuFile.Load Game";
5438 return "menuMode.Edit Position";
5440 return "menuMode.Training";
5441 case IcsPlayingWhite:
5442 case IcsPlayingBlack:
5446 return "menuMode.ICS Client";
5453 void ModeHighlight()
5456 static int oldPausing = FALSE;
5457 static GameMode oldmode = (GameMode) -1;
5460 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5462 if (pausing != oldPausing) {
5463 oldPausing = pausing;
5465 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5467 XtSetArg(args[0], XtNleftBitmap, None);
5469 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5472 if (appData.showButtonBar) {
5473 /* Always toggle, don't set. Previous code messes up when
5474 invoked while the button is pressed, as releasing it
5475 toggles the state again. */
5478 XtSetArg(args[0], XtNbackground, &oldbg);
5479 XtSetArg(args[1], XtNforeground, &oldfg);
5480 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5482 XtSetArg(args[0], XtNbackground, oldfg);
5483 XtSetArg(args[1], XtNforeground, oldbg);
5485 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5489 wname = ModeToWidgetName(oldmode);
5490 if (wname != NULL) {
5491 XtSetArg(args[0], XtNleftBitmap, None);
5492 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5494 wname = ModeToWidgetName(gameMode);
5495 if (wname != NULL) {
5496 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5497 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5501 /* Maybe all the enables should be handled here, not just this one */
5502 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5503 gameMode == Training || gameMode == PlayFromGameFile);
5508 * Button/menu procedures
5510 void ResetProc(w, event, prms, nprms)
5519 int LoadGamePopUp(f, gameNumber, title)
5524 cmailMsgLoaded = FALSE;
5525 if (gameNumber == 0) {
5526 int error = GameListBuild(f);
5528 DisplayError(_("Cannot build game list"), error);
5529 } else if (!ListEmpty(&gameList) &&
5530 ((ListGame *) gameList.tailPred)->number > 1) {
5531 GameListPopUp(f, title);
5537 return LoadGame(f, gameNumber, title, FALSE);
5540 void LoadGameProc(w, event, prms, nprms)
5546 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5549 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5552 void LoadNextGameProc(w, event, prms, nprms)
5561 void LoadPrevGameProc(w, event, prms, nprms)
5570 void ReloadGameProc(w, event, prms, nprms)
5579 void LoadNextPositionProc(w, event, prms, nprms)
5588 void LoadPrevPositionProc(w, event, prms, nprms)
5597 void ReloadPositionProc(w, event, prms, nprms)
5606 void LoadPositionProc(w, event, prms, nprms)
5612 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5615 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5618 void SaveGameProc(w, event, prms, nprms)
5624 FileNamePopUp(_("Save game file name?"),
5625 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5629 void SavePositionProc(w, event, prms, nprms)
5635 FileNamePopUp(_("Save position file name?"),
5636 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5640 void ReloadCmailMsgProc(w, event, prms, nprms)
5646 ReloadCmailMsgEvent(FALSE);
5649 void MailMoveProc(w, event, prms, nprms)
5658 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5659 char *selected_fen_position=NULL;
5662 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5663 Atom *type_return, XtPointer *value_return,
5664 unsigned long *length_return, int *format_return)
5666 char *selection_tmp;
5668 if (!selected_fen_position) return False; /* should never happen */
5669 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5670 /* note: since no XtSelectionDoneProc was registered, Xt will
5671 * automatically call XtFree on the value returned. So have to
5672 * make a copy of it allocated with XtMalloc */
5673 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5674 strcpy(selection_tmp, selected_fen_position);
5676 *value_return=selection_tmp;
5677 *length_return=strlen(selection_tmp);
5678 *type_return=*target;
5679 *format_return = 8; /* bits per byte */
5681 } else if (*target == XA_TARGETS(xDisplay)) {
5682 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5683 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5684 targets_tmp[1] = XA_STRING;
5685 *value_return = targets_tmp;
5686 *type_return = XA_ATOM;
5688 *format_return = 8 * sizeof(Atom);
5689 if (*format_return > 32) {
5690 *length_return *= *format_return / 32;
5691 *format_return = 32;
5699 /* note: when called from menu all parameters are NULL, so no clue what the
5700 * Widget which was clicked on was, or what the click event was
5702 void CopyPositionProc(w, event, prms, nprms)
5709 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5710 * have a notion of a position that is selected but not copied.
5711 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5713 if(gameMode == EditPosition) EditPositionDone(TRUE);
5714 if (selected_fen_position) free(selected_fen_position);
5715 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5716 if (!selected_fen_position) return;
5717 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5719 SendPositionSelection,
5720 NULL/* lose_ownership_proc */ ,
5721 NULL/* transfer_done_proc */);
5722 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5724 SendPositionSelection,
5725 NULL/* lose_ownership_proc */ ,
5726 NULL/* transfer_done_proc */);
5729 /* function called when the data to Paste is ready */
5731 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5732 Atom *type, XtPointer value, unsigned long *len, int *format)
5735 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5736 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5737 EditPositionPasteFEN(fenstr);
5741 /* called when Paste Position button is pressed,
5742 * all parameters will be NULL */
5743 void PastePositionProc(w, event, prms, nprms)
5749 XtGetSelectionValue(menuBarWidget,
5750 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5751 /* (XtSelectionCallbackProc) */ PastePositionCB,
5752 NULL, /* client_data passed to PastePositionCB */
5754 /* better to use the time field from the event that triggered the
5755 * call to this function, but that isn't trivial to get
5763 SendGameSelection(Widget w, Atom *selection, Atom *target,
5764 Atom *type_return, XtPointer *value_return,
5765 unsigned long *length_return, int *format_return)
5767 char *selection_tmp;
5769 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5770 FILE* f = fopen(gameCopyFilename, "r");
5773 if (f == NULL) return False;
5777 selection_tmp = XtMalloc(len + 1);
5778 count = fread(selection_tmp, 1, len, f);
5780 XtFree(selection_tmp);
5783 selection_tmp[len] = NULLCHAR;
5784 *value_return = selection_tmp;
5785 *length_return = len;
5786 *type_return = *target;
5787 *format_return = 8; /* bits per byte */
5789 } else if (*target == XA_TARGETS(xDisplay)) {
5790 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5791 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5792 targets_tmp[1] = XA_STRING;
5793 *value_return = targets_tmp;
5794 *type_return = XA_ATOM;
5796 *format_return = 8 * sizeof(Atom);
5797 if (*format_return > 32) {
5798 *length_return *= *format_return / 32;
5799 *format_return = 32;
5807 /* note: when called from menu all parameters are NULL, so no clue what the
5808 * Widget which was clicked on was, or what the click event was
5810 void CopyGameProc(w, event, prms, nprms)
5818 ret = SaveGameToFile(gameCopyFilename, FALSE);
5822 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5823 * have a notion of a game that is selected but not copied.
5824 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5826 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5829 NULL/* lose_ownership_proc */ ,
5830 NULL/* transfer_done_proc */);
5831 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5834 NULL/* lose_ownership_proc */ ,
5835 NULL/* transfer_done_proc */);
5838 /* function called when the data to Paste is ready */
5840 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5841 Atom *type, XtPointer value, unsigned long *len, int *format)
5844 if (value == NULL || *len == 0) {
5845 return; /* nothing had been selected to copy */
5847 f = fopen(gamePasteFilename, "w");
5849 DisplayError(_("Can't open temp file"), errno);
5852 fwrite(value, 1, *len, f);
5855 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5858 /* called when Paste Game button is pressed,
5859 * all parameters will be NULL */
5860 void PasteGameProc(w, event, prms, nprms)
5866 XtGetSelectionValue(menuBarWidget,
5867 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5868 /* (XtSelectionCallbackProc) */ PasteGameCB,
5869 NULL, /* client_data passed to PasteGameCB */
5871 /* better to use the time field from the event that triggered the
5872 * call to this function, but that isn't trivial to get
5882 SaveGameProc(NULL, NULL, NULL, NULL);
5886 void QuitProc(w, event, prms, nprms)
5895 void PauseProc(w, event, prms, nprms)
5905 void MachineBlackProc(w, event, prms, nprms)
5911 MachineBlackEvent();
5914 void MachineWhiteProc(w, event, prms, nprms)
5920 MachineWhiteEvent();
5923 void AnalyzeModeProc(w, event, prms, nprms)
5931 if (!first.analysisSupport) {
5932 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5933 DisplayError(buf, 0);
5936 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5937 if (appData.icsActive) {
5938 if (gameMode != IcsObserving) {
5939 sprintf(buf,_("You are not observing a game"));
5940 DisplayError(buf, 0);
5942 if (appData.icsEngineAnalyze) {
5943 if (appData.debugMode)
5944 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5950 /* if enable, use want disable icsEngineAnalyze */
5951 if (appData.icsEngineAnalyze) {
5956 appData.icsEngineAnalyze = TRUE;
5957 if (appData.debugMode)
5958 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5960 if (!appData.showThinking)
5961 ShowThinkingProc(w,event,prms,nprms);
5966 void AnalyzeFileProc(w, event, prms, nprms)
5972 if (!first.analysisSupport) {
5974 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5975 DisplayError(buf, 0);
5980 if (!appData.showThinking)
5981 ShowThinkingProc(w,event,prms,nprms);
5984 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
5985 AnalysisPeriodicEvent(1);
5988 void TwoMachinesProc(w, event, prms, nprms)
5997 void IcsClientProc(w, event, prms, nprms)
6006 void EditGameProc(w, event, prms, nprms)
6015 void EditPositionProc(w, event, prms, nprms)
6021 EditPositionEvent();
6024 void TrainingProc(w, event, prms, nprms)
6033 void EditCommentProc(w, event, prms, nprms)
6040 EditCommentPopDown();
6046 void IcsInputBoxProc(w, event, prms, nprms)
6052 if (ICSInputBoxUp) {
6053 ICSInputBoxPopDown();
6059 void AcceptProc(w, event, prms, nprms)
6068 void DeclineProc(w, event, prms, nprms)
6077 void RematchProc(w, event, prms, nprms)
6086 void CallFlagProc(w, event, prms, nprms)
6095 void DrawProc(w, event, prms, nprms)
6104 void AbortProc(w, event, prms, nprms)
6113 void AdjournProc(w, event, prms, nprms)
6122 void ResignProc(w, event, prms, nprms)
6131 void AdjuWhiteProc(w, event, prms, nprms)
6137 UserAdjudicationEvent(+1);
6140 void AdjuBlackProc(w, event, prms, nprms)
6146 UserAdjudicationEvent(-1);
6149 void AdjuDrawProc(w, event, prms, nprms)
6155 UserAdjudicationEvent(0);
6158 void EnterKeyProc(w, event, prms, nprms)
6164 if (ICSInputBoxUp == True)
6168 void UpKeyProc(w, event, prms, nprms)
6173 { // [HGM] input: let up-arrow recall previous line from history
6180 if (!ICSInputBoxUp) return;
6181 edit = XtNameToWidget(ICSInputShell, "*form.text");
6183 XtSetArg(args[j], XtNstring, &val); j++;
6184 XtGetValues(edit, args, j);
6185 val = PrevInHistory(val);
6186 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6187 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6189 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6190 XawTextReplace(edit, 0, 0, &t);
6191 XawTextSetInsertionPoint(edit, 9999);
6195 void DownKeyProc(w, event, prms, nprms)
6200 { // [HGM] input: let down-arrow recall next line from history
6205 if (!ICSInputBoxUp) return;
6206 edit = XtNameToWidget(ICSInputShell, "*form.text");
6207 val = NextInHistory();
6208 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6209 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6211 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6212 XawTextReplace(edit, 0, 0, &t);
6213 XawTextSetInsertionPoint(edit, 9999);
6217 void StopObservingProc(w, event, prms, nprms)
6223 StopObservingEvent();
6226 void StopExaminingProc(w, event, prms, nprms)
6232 StopExaminingEvent();
6235 void UploadProc(w, event, prms, nprms)
6245 void ForwardProc(w, event, prms, nprms)
6255 void BackwardProc(w, event, prms, nprms)
6264 void ToStartProc(w, event, prms, nprms)
6273 void ToEndProc(w, event, prms, nprms)
6282 void RevertProc(w, event, prms, nprms)
6291 void AnnotateProc(w, event, prms, nprms)
6300 void TruncateGameProc(w, event, prms, nprms)
6306 TruncateGameEvent();
6308 void RetractMoveProc(w, event, prms, nprms)
6317 void MoveNowProc(w, event, prms, nprms)
6327 void AlwaysQueenProc(w, event, prms, nprms)
6335 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6337 if (appData.alwaysPromoteToQueen) {
6338 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6340 XtSetArg(args[0], XtNleftBitmap, None);
6342 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6346 void AnimateDraggingProc(w, event, prms, nprms)
6354 appData.animateDragging = !appData.animateDragging;
6356 if (appData.animateDragging) {
6357 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6360 XtSetArg(args[0], XtNleftBitmap, None);
6362 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6366 void AnimateMovingProc(w, event, prms, nprms)
6374 appData.animate = !appData.animate;
6376 if (appData.animate) {
6377 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6380 XtSetArg(args[0], XtNleftBitmap, None);
6382 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6386 void AutocommProc(w, event, prms, nprms)
6394 appData.autoComment = !appData.autoComment;
6396 if (appData.autoComment) {
6397 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6399 XtSetArg(args[0], XtNleftBitmap, None);
6401 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6406 void AutoflagProc(w, event, prms, nprms)
6414 appData.autoCallFlag = !appData.autoCallFlag;
6416 if (appData.autoCallFlag) {
6417 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6419 XtSetArg(args[0], XtNleftBitmap, None);
6421 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6425 void AutoflipProc(w, event, prms, nprms)
6433 appData.autoFlipView = !appData.autoFlipView;
6435 if (appData.autoFlipView) {
6436 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6438 XtSetArg(args[0], XtNleftBitmap, None);
6440 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6444 void AutobsProc(w, event, prms, nprms)
6452 appData.autoObserve = !appData.autoObserve;
6454 if (appData.autoObserve) {
6455 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6457 XtSetArg(args[0], XtNleftBitmap, None);
6459 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6463 void AutoraiseProc(w, event, prms, nprms)
6471 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6473 if (appData.autoRaiseBoard) {
6474 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6476 XtSetArg(args[0], XtNleftBitmap, None);
6478 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6482 void AutosaveProc(w, event, prms, nprms)
6490 appData.autoSaveGames = !appData.autoSaveGames;
6492 if (appData.autoSaveGames) {
6493 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6495 XtSetArg(args[0], XtNleftBitmap, None);
6497 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6501 void BlindfoldProc(w, event, prms, nprms)
6509 appData.blindfold = !appData.blindfold;
6511 if (appData.blindfold) {
6512 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6514 XtSetArg(args[0], XtNleftBitmap, None);
6516 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6519 DrawPosition(True, NULL);
6522 void TestLegalityProc(w, event, prms, nprms)
6530 appData.testLegality = !appData.testLegality;
6532 if (appData.testLegality) {
6533 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6535 XtSetArg(args[0], XtNleftBitmap, None);
6537 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6542 void FlashMovesProc(w, event, prms, nprms)
6550 if (appData.flashCount == 0) {
6551 appData.flashCount = 3;
6553 appData.flashCount = -appData.flashCount;
6556 if (appData.flashCount > 0) {
6557 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6559 XtSetArg(args[0], XtNleftBitmap, None);
6561 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6565 void FlipViewProc(w, event, prms, nprms)
6571 flipView = !flipView;
6572 DrawPosition(True, NULL);
6575 void GetMoveListProc(w, event, prms, nprms)
6583 appData.getMoveList = !appData.getMoveList;
6585 if (appData.getMoveList) {
6586 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6589 XtSetArg(args[0], XtNleftBitmap, None);
6591 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6596 void HighlightDraggingProc(w, event, prms, nprms)
6604 appData.highlightDragging = !appData.highlightDragging;
6606 if (appData.highlightDragging) {
6607 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6609 XtSetArg(args[0], XtNleftBitmap, None);
6611 XtSetValues(XtNameToWidget(menuBarWidget,
6612 "menuOptions.Highlight Dragging"), args, 1);
6616 void HighlightLastMoveProc(w, event, prms, nprms)
6624 appData.highlightLastMove = !appData.highlightLastMove;
6626 if (appData.highlightLastMove) {
6627 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6629 XtSetArg(args[0], XtNleftBitmap, None);
6631 XtSetValues(XtNameToWidget(menuBarWidget,
6632 "menuOptions.Highlight Last Move"), args, 1);
6635 void IcsAlarmProc(w, event, prms, nprms)
6643 appData.icsAlarm = !appData.icsAlarm;
6645 if (appData.icsAlarm) {
6646 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6648 XtSetArg(args[0], XtNleftBitmap, None);
6650 XtSetValues(XtNameToWidget(menuBarWidget,
6651 "menuOptions.ICS Alarm"), args, 1);
6654 void MoveSoundProc(w, event, prms, nprms)
6662 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6664 if (appData.ringBellAfterMoves) {
6665 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6667 XtSetArg(args[0], XtNleftBitmap, None);
6669 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6674 void OldSaveStyleProc(w, event, prms, nprms)
6682 appData.oldSaveStyle = !appData.oldSaveStyle;
6684 if (appData.oldSaveStyle) {
6685 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6687 XtSetArg(args[0], XtNleftBitmap, None);
6689 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6693 void PeriodicUpdatesProc(w, event, prms, nprms)
6701 PeriodicUpdatesEvent(!appData.periodicUpdates);
6703 if (appData.periodicUpdates) {
6704 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6706 XtSetArg(args[0], XtNleftBitmap, None);
6708 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6712 void PonderNextMoveProc(w, event, prms, nprms)
6720 PonderNextMoveEvent(!appData.ponderNextMove);
6722 if (appData.ponderNextMove) {
6723 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6725 XtSetArg(args[0], XtNleftBitmap, None);
6727 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6731 void PopupExitMessageProc(w, event, prms, nprms)
6739 appData.popupExitMessage = !appData.popupExitMessage;
6741 if (appData.popupExitMessage) {
6742 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6744 XtSetArg(args[0], XtNleftBitmap, None);
6746 XtSetValues(XtNameToWidget(menuBarWidget,
6747 "menuOptions.Popup Exit Message"), args, 1);
6750 void PopupMoveErrorsProc(w, event, prms, nprms)
6758 appData.popupMoveErrors = !appData.popupMoveErrors;
6760 if (appData.popupMoveErrors) {
6761 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6763 XtSetArg(args[0], XtNleftBitmap, None);
6765 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6769 void PremoveProc(w, event, prms, nprms)
6777 appData.premove = !appData.premove;
6779 if (appData.premove) {
6780 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6782 XtSetArg(args[0], XtNleftBitmap, None);
6784 XtSetValues(XtNameToWidget(menuBarWidget,
6785 "menuOptions.Premove"), args, 1);
6788 void QuietPlayProc(w, event, prms, nprms)
6796 appData.quietPlay = !appData.quietPlay;
6798 if (appData.quietPlay) {
6799 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6801 XtSetArg(args[0], XtNleftBitmap, None);
6803 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6807 void ShowCoordsProc(w, event, prms, nprms)
6815 appData.showCoords = !appData.showCoords;
6817 if (appData.showCoords) {
6818 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6820 XtSetArg(args[0], XtNleftBitmap, None);
6822 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6825 DrawPosition(True, NULL);
6828 void ShowThinkingProc(w, event, prms, nprms)
6834 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6835 ShowThinkingEvent();
6838 void HideThinkingProc(w, event, prms, nprms)
6846 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6847 ShowThinkingEvent();
6849 if (appData.hideThinkingFromHuman) {
6850 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6852 XtSetArg(args[0], XtNleftBitmap, None);
6854 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6858 void SaveOnExitProc(w, event, prms, nprms)
6866 saveSettingsOnExit = !saveSettingsOnExit;
6868 if (saveSettingsOnExit) {
6869 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6871 XtSetArg(args[0], XtNleftBitmap, None);
6873 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6877 void SaveSettingsProc(w, event, prms, nprms)
6883 SaveSettings(settingsFileName);
6886 void InfoProc(w, event, prms, nprms)
6893 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6898 void ManProc(w, event, prms, nprms)
6906 if (nprms && *nprms > 0)
6910 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6914 void HintProc(w, event, prms, nprms)
6923 void BookProc(w, event, prms, nprms)
6932 void AboutProc(w, event, prms, nprms)
6940 char *zippy = " (with Zippy code)";
6944 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6945 programVersion, zippy,
6946 "Copyright 1991 Digital Equipment Corporation",
6947 "Enhancements Copyright 1992-2009 Free Software Foundation",
6948 "Enhancements Copyright 2005 Alessandro Scotti",
6949 PACKAGE, " is free software and carries NO WARRANTY;",
6950 "see the file COPYING for more information.");
6951 ErrorPopUp(_("About XBoard"), buf, FALSE);
6954 void DebugProc(w, event, prms, nprms)
6960 appData.debugMode = !appData.debugMode;
6963 void AboutGameProc(w, event, prms, nprms)
6972 void NothingProc(w, event, prms, nprms)
6981 void Iconify(w, event, prms, nprms)
6990 XtSetArg(args[0], XtNiconic, True);
6991 XtSetValues(shellWidget, args, 1);
6994 void DisplayMessage(message, extMessage)
6995 char *message, *extMessage;
6997 /* display a message in the message widget */
7006 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
7011 message = extMessage;
7015 /* need to test if messageWidget already exists, since this function
7016 can also be called during the startup, if for example a Xresource
7017 is not set up correctly */
7020 XtSetArg(arg, XtNlabel, message);
7021 XtSetValues(messageWidget, &arg, 1);
7027 void DisplayTitle(text)
7032 char title[MSG_SIZ];
7035 if (text == NULL) text = "";
7037 if (appData.titleInWindow) {
7039 XtSetArg(args[i], XtNlabel, text); i++;
7040 XtSetValues(titleWidget, args, i);
7043 if (*text != NULLCHAR) {
7045 strcpy(title, text);
7046 } else if (appData.icsActive) {
7047 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7048 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7049 } else if (appData.cmailGameName[0] != NULLCHAR) {
7050 snprintf(icon, sizeof(icon), "%s", "CMail");
7051 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7053 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7054 } else if (gameInfo.variant == VariantGothic) {
7055 strcpy(icon, programName);
7056 strcpy(title, GOTHIC);
7059 } else if (gameInfo.variant == VariantFalcon) {
7060 strcpy(icon, programName);
7061 strcpy(title, FALCON);
7063 } else if (appData.noChessProgram) {
7064 strcpy(icon, programName);
7065 strcpy(title, programName);
7067 strcpy(icon, first.tidy);
7068 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7071 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7072 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7073 XtSetValues(shellWidget, args, i);
7077 void DisplayError(message, error)
7084 if (appData.debugMode || appData.matchMode) {
7085 fprintf(stderr, "%s: %s\n", programName, message);
7088 if (appData.debugMode || appData.matchMode) {
7089 fprintf(stderr, "%s: %s: %s\n",
7090 programName, message, strerror(error));
7092 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7095 ErrorPopUp(_("Error"), message, FALSE);
7099 void DisplayMoveError(message)
7104 DrawPosition(FALSE, NULL);
7105 if (appData.debugMode || appData.matchMode) {
7106 fprintf(stderr, "%s: %s\n", programName, message);
7108 if (appData.popupMoveErrors) {
7109 ErrorPopUp(_("Error"), message, FALSE);
7111 DisplayMessage(message, "");
7116 void DisplayFatalError(message, error, status)
7122 errorExitStatus = status;
7124 fprintf(stderr, "%s: %s\n", programName, message);
7126 fprintf(stderr, "%s: %s: %s\n",
7127 programName, message, strerror(error));
7128 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7131 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7132 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7138 void DisplayInformation(message)
7142 ErrorPopUp(_("Information"), message, TRUE);
7145 void DisplayNote(message)
7149 ErrorPopUp(_("Note"), message, FALSE);
7153 NullXErrorCheck(dpy, error_event)
7155 XErrorEvent *error_event;
7160 void DisplayIcsInteractionTitle(message)
7163 if (oldICSInteractionTitle == NULL) {
7164 /* Magic to find the old window title, adapted from vim */
7165 char *wina = getenv("WINDOWID");
7167 Window win = (Window) atoi(wina);
7168 Window root, parent, *children;
7169 unsigned int nchildren;
7170 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7172 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7173 if (!XQueryTree(xDisplay, win, &root, &parent,
7174 &children, &nchildren)) break;
7175 if (children) XFree((void *)children);
7176 if (parent == root || parent == 0) break;
7179 XSetErrorHandler(oldHandler);
7181 if (oldICSInteractionTitle == NULL) {
7182 oldICSInteractionTitle = "xterm";
7185 printf("\033]0;%s\007", message);
7189 char pendingReplyPrefix[MSG_SIZ];
7190 ProcRef pendingReplyPR;
7192 void AskQuestionProc(w, event, prms, nprms)
7199 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7203 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7206 void AskQuestionPopDown()
7208 if (!askQuestionUp) return;
7209 XtPopdown(askQuestionShell);
7210 XtDestroyWidget(askQuestionShell);
7211 askQuestionUp = False;
7214 void AskQuestionReplyAction(w, event, prms, nprms)
7224 reply = XawDialogGetValueString(w = XtParent(w));
7225 strcpy(buf, pendingReplyPrefix);
7226 if (*buf) strcat(buf, " ");
7229 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7230 AskQuestionPopDown();
7232 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7235 void AskQuestionCallback(w, client_data, call_data)
7237 XtPointer client_data, call_data;
7242 XtSetArg(args[0], XtNlabel, &name);
7243 XtGetValues(w, args, 1);
7245 if (strcmp(name, _("cancel")) == 0) {
7246 AskQuestionPopDown();
7248 AskQuestionReplyAction(w, NULL, NULL, NULL);
7252 void AskQuestion(title, question, replyPrefix, pr)
7253 char *title, *question, *replyPrefix;
7257 Widget popup, layout, dialog, edit;
7263 strcpy(pendingReplyPrefix, replyPrefix);
7264 pendingReplyPR = pr;
7267 XtSetArg(args[i], XtNresizable, True); i++;
7268 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7269 askQuestionShell = popup =
7270 XtCreatePopupShell(title, transientShellWidgetClass,
7271 shellWidget, args, i);
7274 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7275 layoutArgs, XtNumber(layoutArgs));
7278 XtSetArg(args[i], XtNlabel, question); i++;
7279 XtSetArg(args[i], XtNvalue, ""); i++;
7280 XtSetArg(args[i], XtNborderWidth, 0); i++;
7281 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7284 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7285 (XtPointer) dialog);
7286 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7287 (XtPointer) dialog);
7289 XtRealizeWidget(popup);
7290 CatchDeleteWindow(popup, "AskQuestionPopDown");
7292 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7293 &x, &y, &win_x, &win_y, &mask);
7295 XtSetArg(args[0], XtNx, x - 10);
7296 XtSetArg(args[1], XtNy, y - 30);
7297 XtSetValues(popup, args, 2);
7299 XtPopup(popup, XtGrabExclusive);
7300 askQuestionUp = True;
7302 edit = XtNameToWidget(dialog, "*value");
7303 XtSetKeyboardFocus(popup, edit);
7311 if (*name == NULLCHAR) {
7313 } else if (strcmp(name, "$") == 0) {
7314 putc(BELLCHAR, stderr);
7317 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7325 PlaySound(appData.soundMove);
7331 PlaySound(appData.soundIcsWin);
7337 PlaySound(appData.soundIcsLoss);
7343 PlaySound(appData.soundIcsDraw);
7347 PlayIcsUnfinishedSound()
7349 PlaySound(appData.soundIcsUnfinished);
7355 PlaySound(appData.soundIcsAlarm);
7361 system("stty echo");
7367 system("stty -echo");
7371 Colorize(cc, continuation)
7376 int count, outCount, error;
7378 if (textColors[(int)cc].bg > 0) {
7379 if (textColors[(int)cc].fg > 0) {
7380 sprintf(buf, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7381 textColors[(int)cc].fg, textColors[(int)cc].bg);
7383 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7384 textColors[(int)cc].bg);
7387 if (textColors[(int)cc].fg > 0) {
7388 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7389 textColors[(int)cc].fg);
7391 sprintf(buf, "\033[0;%dm", textColors[(int)cc].attr);
7394 count = strlen(buf);
7395 outCount = OutputToProcess(NoProc, buf, count, &error);
7396 if (outCount < count) {
7397 DisplayFatalError(_("Error writing to display"), error, 1);
7400 if (continuation) return;
7403 PlaySound(appData.soundShout);
7406 PlaySound(appData.soundSShout);
7409 PlaySound(appData.soundChannel1);
7412 PlaySound(appData.soundChannel);
7415 PlaySound(appData.soundKibitz);
7418 PlaySound(appData.soundTell);
7420 case ColorChallenge:
7421 PlaySound(appData.soundChallenge);
7424 PlaySound(appData.soundRequest);
7427 PlaySound(appData.soundSeek);
7438 return getpwuid(getuid())->pw_name;
7441 static char *ExpandPathName(path)
7444 static char static_buf[2000];
7445 char *d, *s, buf[2000];
7451 while (*s && isspace(*s))
7460 if (*(s+1) == '/') {
7461 strcpy(d, getpwuid(getuid())->pw_dir);
7466 *strchr(buf, '/') = 0;
7467 pwd = getpwnam(buf);
7470 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7474 strcpy(d, pwd->pw_dir);
7475 strcat(d, strchr(s+1, '/'));
7486 static char host_name[MSG_SIZ];
7488 #if HAVE_GETHOSTNAME
7489 gethostname(host_name, MSG_SIZ);
7491 #else /* not HAVE_GETHOSTNAME */
7492 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7493 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7495 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7497 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7498 #endif /* not HAVE_GETHOSTNAME */
7501 XtIntervalId delayedEventTimerXID = 0;
7502 DelayedEventCallback delayedEventCallback = 0;
7507 delayedEventTimerXID = 0;
7508 delayedEventCallback();
7512 ScheduleDelayedEvent(cb, millisec)
7513 DelayedEventCallback cb; long millisec;
7515 if(delayedEventTimerXID && delayedEventCallback == cb)
7516 // [HGM] alive: replace, rather than add or flush identical event
7517 XtRemoveTimeOut(delayedEventTimerXID);
7518 delayedEventCallback = cb;
7519 delayedEventTimerXID =
7520 XtAppAddTimeOut(appContext, millisec,
7521 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7524 DelayedEventCallback
7527 if (delayedEventTimerXID) {
7528 return delayedEventCallback;
7535 CancelDelayedEvent()
7537 if (delayedEventTimerXID) {
7538 XtRemoveTimeOut(delayedEventTimerXID);
7539 delayedEventTimerXID = 0;
7543 XtIntervalId loadGameTimerXID = 0;
7545 int LoadGameTimerRunning()
7547 return loadGameTimerXID != 0;
7550 int StopLoadGameTimer()
7552 if (loadGameTimerXID != 0) {
7553 XtRemoveTimeOut(loadGameTimerXID);
7554 loadGameTimerXID = 0;
7562 LoadGameTimerCallback(arg, id)
7566 loadGameTimerXID = 0;
7571 StartLoadGameTimer(millisec)
7575 XtAppAddTimeOut(appContext, millisec,
7576 (XtTimerCallbackProc) LoadGameTimerCallback,
7580 XtIntervalId analysisClockXID = 0;
7583 AnalysisClockCallback(arg, id)
7587 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7588 || appData.icsEngineAnalyze) { // [DM]
7589 AnalysisPeriodicEvent(0);
7590 StartAnalysisClock();
7595 StartAnalysisClock()
7598 XtAppAddTimeOut(appContext, 2000,
7599 (XtTimerCallbackProc) AnalysisClockCallback,
7603 XtIntervalId clockTimerXID = 0;
7605 int ClockTimerRunning()
7607 return clockTimerXID != 0;
7610 int StopClockTimer()
7612 if (clockTimerXID != 0) {
7613 XtRemoveTimeOut(clockTimerXID);
7622 ClockTimerCallback(arg, id)
7631 StartClockTimer(millisec)
7635 XtAppAddTimeOut(appContext, millisec,
7636 (XtTimerCallbackProc) ClockTimerCallback,
7641 DisplayTimerLabel(w, color, timer, highlight)
7650 /* check for low time warning */
7651 Pixel foregroundOrWarningColor = timerForegroundPixel;
7654 appData.lowTimeWarning &&
7655 (timer / 1000) < appData.icsAlarmTime)
7656 foregroundOrWarningColor = lowTimeWarningColor;
7658 if (appData.clockMode) {
7659 sprintf(buf, "%s: %s", color, TimeString(timer));
7660 XtSetArg(args[0], XtNlabel, buf);
7662 sprintf(buf, "%s ", color);
7663 XtSetArg(args[0], XtNlabel, buf);
7668 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7669 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7671 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7672 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7675 XtSetValues(w, args, 3);
7679 DisplayWhiteClock(timeRemaining, highlight)
7685 if(appData.noGUI) return;
7686 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7687 if (highlight && iconPixmap == bIconPixmap) {
7688 iconPixmap = wIconPixmap;
7689 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7690 XtSetValues(shellWidget, args, 1);
7695 DisplayBlackClock(timeRemaining, highlight)
7701 if(appData.noGUI) return;
7702 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7703 if (highlight && iconPixmap == wIconPixmap) {
7704 iconPixmap = bIconPixmap;
7705 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7706 XtSetValues(shellWidget, args, 1);
7724 int StartChildProcess(cmdLine, dir, pr)
7731 int to_prog[2], from_prog[2];
7735 if (appData.debugMode) {
7736 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7739 /* We do NOT feed the cmdLine to the shell; we just
7740 parse it into blank-separated arguments in the
7741 most simple-minded way possible.
7744 strcpy(buf, cmdLine);
7747 while(*p == ' ') p++;
7749 if(*p == '"' || *p == '\'')
7750 p = strchr(++argv[i-1], *p);
7751 else p = strchr(p, ' ');
7752 if (p == NULL) break;
7757 SetUpChildIO(to_prog, from_prog);
7759 if ((pid = fork()) == 0) {
7761 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7762 close(to_prog[1]); // first close the unused pipe ends
7763 close(from_prog[0]);
7764 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7765 dup2(from_prog[1], 1);
7766 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7767 close(from_prog[1]); // and closing again loses one of the pipes!
7768 if(fileno(stderr) >= 2) // better safe than sorry...
7769 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7771 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7776 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7778 execvp(argv[0], argv);
7780 /* If we get here, exec failed */
7785 /* Parent process */
7787 close(from_prog[1]);
7789 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7792 cp->fdFrom = from_prog[0];
7793 cp->fdTo = to_prog[1];
7798 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7799 static RETSIGTYPE AlarmCallBack(int n)
7805 DestroyChildProcess(pr, signalType)
7809 ChildProc *cp = (ChildProc *) pr;
7811 if (cp->kind != CPReal) return;
7813 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7814 signal(SIGALRM, AlarmCallBack);
7816 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7817 kill(cp->pid, SIGKILL); // kill it forcefully
7818 wait((int *) 0); // and wait again
7822 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7824 /* Process is exiting either because of the kill or because of
7825 a quit command sent by the backend; either way, wait for it to die.
7834 InterruptChildProcess(pr)
7837 ChildProc *cp = (ChildProc *) pr;
7839 if (cp->kind != CPReal) return;
7840 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7843 int OpenTelnet(host, port, pr)
7848 char cmdLine[MSG_SIZ];
7850 if (port[0] == NULLCHAR) {
7851 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7853 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7855 return StartChildProcess(cmdLine, "", pr);
7858 int OpenTCP(host, port, pr)
7864 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7865 #else /* !OMIT_SOCKETS */
7867 struct sockaddr_in sa;
7869 unsigned short uport;
7872 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7876 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7877 sa.sin_family = AF_INET;
7878 sa.sin_addr.s_addr = INADDR_ANY;
7879 uport = (unsigned short) 0;
7880 sa.sin_port = htons(uport);
7881 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7885 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7886 if (!(hp = gethostbyname(host))) {
7888 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7889 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7890 hp->h_addrtype = AF_INET;
7892 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7893 hp->h_addr_list[0] = (char *) malloc(4);
7894 hp->h_addr_list[0][0] = b0;
7895 hp->h_addr_list[0][1] = b1;
7896 hp->h_addr_list[0][2] = b2;
7897 hp->h_addr_list[0][3] = b3;
7902 sa.sin_family = hp->h_addrtype;
7903 uport = (unsigned short) atoi(port);
7904 sa.sin_port = htons(uport);
7905 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7907 if (connect(s, (struct sockaddr *) &sa,
7908 sizeof(struct sockaddr_in)) < 0) {
7912 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7919 #endif /* !OMIT_SOCKETS */
7924 int OpenCommPort(name, pr)
7931 fd = open(name, 2, 0);
7932 if (fd < 0) return errno;
7934 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7944 int OpenLoopback(pr)
7950 SetUpChildIO(to, from);
7952 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7955 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7962 int OpenRcmd(host, user, cmd, pr)
7963 char *host, *user, *cmd;
7966 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7970 #define INPUT_SOURCE_BUF_SIZE 8192
7979 char buf[INPUT_SOURCE_BUF_SIZE];
7984 DoInputCallback(closure, source, xid)
7989 InputSource *is = (InputSource *) closure;
7994 if (is->lineByLine) {
7995 count = read(is->fd, is->unused,
7996 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7998 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
8001 is->unused += count;
8003 while (p < is->unused) {
8004 q = memchr(p, '\n', is->unused - p);
8005 if (q == NULL) break;
8007 (is->func)(is, is->closure, p, q - p, 0);
8011 while (p < is->unused) {
8016 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8021 (is->func)(is, is->closure, is->buf, count, error);
8025 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8032 ChildProc *cp = (ChildProc *) pr;
8034 is = (InputSource *) calloc(1, sizeof(InputSource));
8035 is->lineByLine = lineByLine;
8039 is->fd = fileno(stdin);
8041 is->kind = cp->kind;
8042 is->fd = cp->fdFrom;
8045 is->unused = is->buf;
8048 is->xid = XtAppAddInput(appContext, is->fd,
8049 (XtPointer) (XtInputReadMask),
8050 (XtInputCallbackProc) DoInputCallback,
8052 is->closure = closure;
8053 return (InputSourceRef) is;
8057 RemoveInputSource(isr)
8060 InputSource *is = (InputSource *) isr;
8062 if (is->xid == 0) return;
8063 XtRemoveInput(is->xid);
8067 int OutputToProcess(pr, message, count, outError)
8073 static int line = 0;
8074 ChildProc *cp = (ChildProc *) pr;
8079 if (appData.noJoin || !appData.useInternalWrap)
8080 outCount = fwrite(message, 1, count, stdout);
8083 int width = get_term_width();
8084 int len = wrap(NULL, message, count, width, &line);
8085 char *msg = malloc(len);
8089 outCount = fwrite(message, 1, count, stdout);
8092 dbgchk = wrap(msg, message, count, width, &line);
8093 if (dbgchk != len && appData.debugMode)
8094 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8095 outCount = fwrite(msg, 1, dbgchk, stdout);
8101 outCount = write(cp->fdTo, message, count);
8111 /* Output message to process, with "ms" milliseconds of delay
8112 between each character. This is needed when sending the logon
8113 script to ICC, which for some reason doesn't like the
8114 instantaneous send. */
8115 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8122 ChildProc *cp = (ChildProc *) pr;
8127 r = write(cp->fdTo, message++, 1);
8140 /**** Animation code by Hugh Fisher, DCS, ANU.
8142 Known problem: if a window overlapping the board is
8143 moved away while a piece is being animated underneath,
8144 the newly exposed area won't be updated properly.
8145 I can live with this.
8147 Known problem: if you look carefully at the animation
8148 of pieces in mono mode, they are being drawn as solid
8149 shapes without interior detail while moving. Fixing
8150 this would be a major complication for minimal return.
8153 /* Masks for XPM pieces. Black and white pieces can have
8154 different shapes, but in the interest of retaining my
8155 sanity pieces must have the same outline on both light
8156 and dark squares, and all pieces must use the same
8157 background square colors/images. */
8159 static int xpmDone = 0;
8162 CreateAnimMasks (pieceDepth)
8169 unsigned long plane;
8172 /* Need a bitmap just to get a GC with right depth */
8173 buf = XCreatePixmap(xDisplay, xBoardWindow,
8175 values.foreground = 1;
8176 values.background = 0;
8177 /* Don't use XtGetGC, not read only */
8178 maskGC = XCreateGC(xDisplay, buf,
8179 GCForeground | GCBackground, &values);
8180 XFreePixmap(xDisplay, buf);
8182 buf = XCreatePixmap(xDisplay, xBoardWindow,
8183 squareSize, squareSize, pieceDepth);
8184 values.foreground = XBlackPixel(xDisplay, xScreen);
8185 values.background = XWhitePixel(xDisplay, xScreen);
8186 bufGC = XCreateGC(xDisplay, buf,
8187 GCForeground | GCBackground, &values);
8189 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8190 /* Begin with empty mask */
8191 if(!xpmDone) // [HGM] pieces: keep using existing
8192 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8193 squareSize, squareSize, 1);
8194 XSetFunction(xDisplay, maskGC, GXclear);
8195 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8196 0, 0, squareSize, squareSize);
8198 /* Take a copy of the piece */
8203 XSetFunction(xDisplay, bufGC, GXcopy);
8204 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8206 0, 0, squareSize, squareSize, 0, 0);
8208 /* XOR the background (light) over the piece */
8209 XSetFunction(xDisplay, bufGC, GXxor);
8211 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8212 0, 0, squareSize, squareSize, 0, 0);
8214 XSetForeground(xDisplay, bufGC, lightSquareColor);
8215 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8218 /* We now have an inverted piece image with the background
8219 erased. Construct mask by just selecting all the non-zero
8220 pixels - no need to reconstruct the original image. */
8221 XSetFunction(xDisplay, maskGC, GXor);
8223 /* Might be quicker to download an XImage and create bitmap
8224 data from it rather than this N copies per piece, but it
8225 only takes a fraction of a second and there is a much
8226 longer delay for loading the pieces. */
8227 for (n = 0; n < pieceDepth; n ++) {
8228 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8229 0, 0, squareSize, squareSize,
8235 XFreePixmap(xDisplay, buf);
8236 XFreeGC(xDisplay, bufGC);
8237 XFreeGC(xDisplay, maskGC);
8241 InitAnimState (anim, info)
8243 XWindowAttributes * info;
8248 /* Each buffer is square size, same depth as window */
8249 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8250 squareSize, squareSize, info->depth);
8251 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8252 squareSize, squareSize, info->depth);
8254 /* Create a plain GC for blitting */
8255 mask = GCForeground | GCBackground | GCFunction |
8256 GCPlaneMask | GCGraphicsExposures;
8257 values.foreground = XBlackPixel(xDisplay, xScreen);
8258 values.background = XWhitePixel(xDisplay, xScreen);
8259 values.function = GXcopy;
8260 values.plane_mask = AllPlanes;
8261 values.graphics_exposures = False;
8262 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8264 /* Piece will be copied from an existing context at
8265 the start of each new animation/drag. */
8266 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8268 /* Outline will be a read-only copy of an existing */
8269 anim->outlineGC = None;
8275 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8276 XWindowAttributes info;
8278 if (xpmDone && gameInfo.variant == old) return;
8279 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8280 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8282 InitAnimState(&game, &info);
8283 InitAnimState(&player, &info);
8285 /* For XPM pieces, we need bitmaps to use as masks. */
8287 CreateAnimMasks(info.depth);
8293 static Boolean frameWaiting;
8295 static RETSIGTYPE FrameAlarm (sig)
8298 frameWaiting = False;
8299 /* In case System-V style signals. Needed?? */
8300 signal(SIGALRM, FrameAlarm);
8307 struct itimerval delay;
8309 XSync(xDisplay, False);
8312 frameWaiting = True;
8313 signal(SIGALRM, FrameAlarm);
8314 delay.it_interval.tv_sec =
8315 delay.it_value.tv_sec = time / 1000;
8316 delay.it_interval.tv_usec =
8317 delay.it_value.tv_usec = (time % 1000) * 1000;
8318 setitimer(ITIMER_REAL, &delay, NULL);
8319 while (frameWaiting) pause();
8320 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8321 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8322 setitimer(ITIMER_REAL, &delay, NULL);
8332 XSync(xDisplay, False);
8334 usleep(time * 1000);
8339 /* Convert board position to corner of screen rect and color */
8342 ScreenSquare(column, row, pt, color)
8343 int column; int row; XPoint * pt; int * color;
8346 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8347 pt->y = lineGap + row * (squareSize + lineGap);
8349 pt->x = lineGap + column * (squareSize + lineGap);
8350 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8352 *color = SquareColor(row, column);
8355 /* Convert window coords to square */
8358 BoardSquare(x, y, column, row)
8359 int x; int y; int * column; int * row;
8361 *column = EventToSquare(x, BOARD_WIDTH);
8362 if (flipView && *column >= 0)
8363 *column = BOARD_WIDTH - 1 - *column;
8364 *row = EventToSquare(y, BOARD_HEIGHT);
8365 if (!flipView && *row >= 0)
8366 *row = BOARD_HEIGHT - 1 - *row;
8371 #undef Max /* just in case */
8373 #define Max(a, b) ((a) > (b) ? (a) : (b))
8374 #define Min(a, b) ((a) < (b) ? (a) : (b))
8377 SetRect(rect, x, y, width, height)
8378 XRectangle * rect; int x; int y; int width; int height;
8382 rect->width = width;
8383 rect->height = height;
8386 /* Test if two frames overlap. If they do, return
8387 intersection rect within old and location of
8388 that rect within new. */
8391 Intersect(old, new, size, area, pt)
8392 XPoint * old; XPoint * new;
8393 int size; XRectangle * area; XPoint * pt;
8395 if (old->x > new->x + size || new->x > old->x + size ||
8396 old->y > new->y + size || new->y > old->y + size) {
8399 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8400 size - abs(old->x - new->x), size - abs(old->y - new->y));
8401 pt->x = Max(old->x - new->x, 0);
8402 pt->y = Max(old->y - new->y, 0);
8407 /* For two overlapping frames, return the rect(s)
8408 in the old that do not intersect with the new. */
8411 CalcUpdateRects(old, new, size, update, nUpdates)
8412 XPoint * old; XPoint * new; int size;
8413 XRectangle update[]; int * nUpdates;
8417 /* If old = new (shouldn't happen) then nothing to draw */
8418 if (old->x == new->x && old->y == new->y) {
8422 /* Work out what bits overlap. Since we know the rects
8423 are the same size we don't need a full intersect calc. */
8425 /* Top or bottom edge? */
8426 if (new->y > old->y) {
8427 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8429 } else if (old->y > new->y) {
8430 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8431 size, old->y - new->y);
8434 /* Left or right edge - don't overlap any update calculated above. */
8435 if (new->x > old->x) {
8436 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8437 new->x - old->x, size - abs(new->y - old->y));
8439 } else if (old->x > new->x) {
8440 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8441 old->x - new->x, size - abs(new->y - old->y));
8448 /* Generate a series of frame coords from start->mid->finish.
8449 The movement rate doubles until the half way point is
8450 reached, then halves back down to the final destination,
8451 which gives a nice slow in/out effect. The algorithmn
8452 may seem to generate too many intermediates for short
8453 moves, but remember that the purpose is to attract the
8454 viewers attention to the piece about to be moved and
8455 then to where it ends up. Too few frames would be less
8459 Tween(start, mid, finish, factor, frames, nFrames)
8460 XPoint * start; XPoint * mid;
8461 XPoint * finish; int factor;
8462 XPoint frames[]; int * nFrames;
8464 int fraction, n, count;
8468 /* Slow in, stepping 1/16th, then 1/8th, ... */
8470 for (n = 0; n < factor; n++)
8472 for (n = 0; n < factor; n++) {
8473 frames[count].x = start->x + (mid->x - start->x) / fraction;
8474 frames[count].y = start->y + (mid->y - start->y) / fraction;
8476 fraction = fraction / 2;
8480 frames[count] = *mid;
8483 /* Slow out, stepping 1/2, then 1/4, ... */
8485 for (n = 0; n < factor; n++) {
8486 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8487 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8489 fraction = fraction * 2;
8494 /* Draw a piece on the screen without disturbing what's there */
8497 SelectGCMask(piece, clip, outline, mask)
8498 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8502 /* Bitmap for piece being moved. */
8503 if (appData.monoMode) {
8504 *mask = *pieceToSolid(piece);
8505 } else if (useImages) {
8507 *mask = xpmMask[piece];
8509 *mask = ximMaskPm[piece];
8512 *mask = *pieceToSolid(piece);
8515 /* GC for piece being moved. Square color doesn't matter, but
8516 since it gets modified we make a copy of the original. */
8518 if (appData.monoMode)
8523 if (appData.monoMode)
8528 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8530 /* Outline only used in mono mode and is not modified */
8532 *outline = bwPieceGC;
8534 *outline = wbPieceGC;
8538 OverlayPiece(piece, clip, outline, dest)
8539 ChessSquare piece; GC clip; GC outline; Drawable dest;
8544 /* Draw solid rectangle which will be clipped to shape of piece */
8545 XFillRectangle(xDisplay, dest, clip,
8546 0, 0, squareSize, squareSize);
8547 if (appData.monoMode)
8548 /* Also draw outline in contrasting color for black
8549 on black / white on white cases */
8550 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8551 0, 0, squareSize, squareSize, 0, 0, 1);
8553 /* Copy the piece */
8558 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8560 0, 0, squareSize, squareSize,
8565 /* Animate the movement of a single piece */
8568 BeginAnimation(anim, piece, startColor, start)
8576 /* The old buffer is initialised with the start square (empty) */
8577 BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8578 anim->prevFrame = *start;
8580 /* The piece will be drawn using its own bitmap as a matte */
8581 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8582 XSetClipMask(xDisplay, anim->pieceGC, mask);
8586 AnimationFrame(anim, frame, piece)
8591 XRectangle updates[4];
8596 /* Save what we are about to draw into the new buffer */
8597 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8598 frame->x, frame->y, squareSize, squareSize,
8601 /* Erase bits of the previous frame */
8602 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8603 /* Where the new frame overlapped the previous,
8604 the contents in newBuf are wrong. */
8605 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8606 overlap.x, overlap.y,
8607 overlap.width, overlap.height,
8609 /* Repaint the areas in the old that don't overlap new */
8610 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8611 for (i = 0; i < count; i++)
8612 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8613 updates[i].x - anim->prevFrame.x,
8614 updates[i].y - anim->prevFrame.y,
8615 updates[i].width, updates[i].height,
8616 updates[i].x, updates[i].y);
8618 /* Easy when no overlap */
8619 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8620 0, 0, squareSize, squareSize,
8621 anim->prevFrame.x, anim->prevFrame.y);
8624 /* Save this frame for next time round */
8625 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8626 0, 0, squareSize, squareSize,
8628 anim->prevFrame = *frame;
8630 /* Draw piece over original screen contents, not current,
8631 and copy entire rect. Wipes out overlapping piece images. */
8632 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8633 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8634 0, 0, squareSize, squareSize,
8635 frame->x, frame->y);
8639 EndAnimation (anim, finish)
8643 XRectangle updates[4];
8648 /* The main code will redraw the final square, so we
8649 only need to erase the bits that don't overlap. */
8650 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8651 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8652 for (i = 0; i < count; i++)
8653 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8654 updates[i].x - anim->prevFrame.x,
8655 updates[i].y - anim->prevFrame.y,
8656 updates[i].width, updates[i].height,
8657 updates[i].x, updates[i].y);
8659 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8660 0, 0, squareSize, squareSize,
8661 anim->prevFrame.x, anim->prevFrame.y);
8666 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8668 ChessSquare piece; int startColor;
8669 XPoint * start; XPoint * finish;
8670 XPoint frames[]; int nFrames;
8674 BeginAnimation(anim, piece, startColor, start);
8675 for (n = 0; n < nFrames; n++) {
8676 AnimationFrame(anim, &(frames[n]), piece);
8677 FrameDelay(appData.animSpeed);
8679 EndAnimation(anim, finish);
8682 /* Main control logic for deciding what to animate and how */
8685 AnimateMove(board, fromX, fromY, toX, toY)
8694 XPoint start, finish, mid;
8695 XPoint frames[kFactor * 2 + 1];
8696 int nFrames, startColor, endColor;
8698 /* Are we animating? */
8699 if (!appData.animate || appData.blindfold)
8702 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8703 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8704 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8706 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8707 piece = board[fromY][fromX];
8708 if (piece >= EmptySquare) return;
8713 hop = (piece == WhiteKnight || piece == BlackKnight);
8716 if (appData.debugMode) {
8717 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8718 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8719 piece, fromX, fromY, toX, toY); }
8721 ScreenSquare(fromX, fromY, &start, &startColor);
8722 ScreenSquare(toX, toY, &finish, &endColor);
8725 /* Knight: make diagonal movement then straight */
8726 if (abs(toY - fromY) < abs(toX - fromX)) {
8727 mid.x = start.x + (finish.x - start.x) / 2;
8731 mid.y = start.y + (finish.y - start.y) / 2;
8734 mid.x = start.x + (finish.x - start.x) / 2;
8735 mid.y = start.y + (finish.y - start.y) / 2;
8738 /* Don't use as many frames for very short moves */
8739 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8740 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8742 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8743 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8745 /* Be sure end square is redrawn */
8746 damage[0][toY][toX] = True;
8750 DragPieceBegin(x, y)
8753 int boardX, boardY, color;
8756 /* Are we animating? */
8757 if (!appData.animateDragging || appData.blindfold)
8760 /* Figure out which square we start in and the
8761 mouse position relative to top left corner. */
8762 BoardSquare(x, y, &boardX, &boardY);
8763 player.startBoardX = boardX;
8764 player.startBoardY = boardY;
8765 ScreenSquare(boardX, boardY, &corner, &color);
8766 player.startSquare = corner;
8767 player.startColor = color;
8768 /* As soon as we start dragging, the piece will jump slightly to
8769 be centered over the mouse pointer. */
8770 player.mouseDelta.x = squareSize/2;
8771 player.mouseDelta.y = squareSize/2;
8772 /* Initialise animation */
8773 player.dragPiece = PieceForSquare(boardX, boardY);
8775 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8776 player.dragActive = True;
8777 BeginAnimation(&player, player.dragPiece, color, &corner);
8778 /* Mark this square as needing to be redrawn. Note that
8779 we don't remove the piece though, since logically (ie
8780 as seen by opponent) the move hasn't been made yet. */
8781 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8782 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8783 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8784 corner.x, corner.y, squareSize, squareSize,
8785 0, 0); // [HGM] zh: unstack in stead of grab
8786 damage[0][boardY][boardX] = True;
8788 player.dragActive = False;
8798 /* Are we animating? */
8799 if (!appData.animateDragging || appData.blindfold)
8803 if (! player.dragActive)
8805 /* Move piece, maintaining same relative position
8806 of mouse within square */
8807 corner.x = x - player.mouseDelta.x;
8808 corner.y = y - player.mouseDelta.y;
8809 AnimationFrame(&player, &corner, player.dragPiece);
8811 if (appData.highlightDragging) {
8813 BoardSquare(x, y, &boardX, &boardY);
8814 SetHighlights(fromX, fromY, boardX, boardY);
8823 int boardX, boardY, color;
8826 /* Are we animating? */
8827 if (!appData.animateDragging || appData.blindfold)
8831 if (! player.dragActive)
8833 /* Last frame in sequence is square piece is
8834 placed on, which may not match mouse exactly. */
8835 BoardSquare(x, y, &boardX, &boardY);
8836 ScreenSquare(boardX, boardY, &corner, &color);
8837 EndAnimation(&player, &corner);
8839 /* Be sure end square is redrawn */
8840 damage[0][boardY][boardX] = True;
8842 /* This prevents weird things happening with fast successive
8843 clicks which on my Sun at least can cause motion events
8844 without corresponding press/release. */
8845 player.dragActive = False;
8848 /* Handle expose event while piece being dragged */
8853 if (!player.dragActive || appData.blindfold)
8856 /* What we're doing: logically, the move hasn't been made yet,
8857 so the piece is still in it's original square. But visually
8858 it's being dragged around the board. So we erase the square
8859 that the piece is on and draw it at the last known drag point. */
8860 BlankSquare(player.startSquare.x, player.startSquare.y,
8861 player.startColor, EmptySquare, xBoardWindow);
8862 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8863 damage[0][player.startBoardY][player.startBoardX] = TRUE;
8866 #include <sys/ioctl.h>
8867 int get_term_width()
8869 int fd, default_width;
8872 default_width = 79; // this is FICS default anyway...
8874 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8876 if (!ioctl(fd, TIOCGSIZE, &win))
8877 default_width = win.ts_cols;
8878 #elif defined(TIOCGWINSZ)
8880 if (!ioctl(fd, TIOCGWINSZ, &win))
8881 default_width = win.ws_col;
8883 return default_width;
8886 void update_ics_width()
8888 static int old_width = 0;
8889 int new_width = get_term_width();
8891 if (old_width != new_width)
8892 ics_printf("set width %d\n", new_width);
8893 old_width = new_width;
8896 void NotifyFrontendLogin()