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);