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 CommentClick P((Widget w, XEvent * event,
278 String * params, Cardinal * nParams));
279 void CommentPopUp P((char *title, char *label));
280 void CommentPopDown P((void));
281 void CommentCallback P((Widget w, XtPointer client_data,
282 XtPointer call_data));
283 void ICSInputBoxPopUp P((void));
284 void ICSInputBoxPopDown P((void));
285 void FileNamePopUp P((char *label, char *def,
286 FileProc proc, char *openMode));
287 void FileNamePopDown P((void));
288 void FileNameCallback P((Widget w, XtPointer client_data,
289 XtPointer call_data));
290 void FileNameAction P((Widget w, XEvent *event,
291 String *prms, Cardinal *nprms));
292 void AskQuestionReplyAction P((Widget w, XEvent *event,
293 String *prms, Cardinal *nprms));
294 void AskQuestionProc P((Widget w, XEvent *event,
295 String *prms, Cardinal *nprms));
296 void AskQuestionPopDown P((void));
297 void PromotionPopDown P((void));
298 void PromotionCallback P((Widget w, XtPointer client_data,
299 XtPointer call_data));
300 void EditCommentPopDown P((void));
301 void EditCommentCallback P((Widget w, XtPointer client_data,
302 XtPointer call_data));
303 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
304 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
305 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
306 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
308 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
310 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
312 void LoadPositionProc P((Widget w, XEvent *event,
313 String *prms, Cardinal *nprms));
314 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
316 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
318 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
320 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
322 void PastePositionProc P((Widget w, XEvent *event, String *prms,
324 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
325 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
326 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
327 void SavePositionProc P((Widget w, XEvent *event,
328 String *prms, Cardinal *nprms));
329 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
330 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
332 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
333 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
334 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
336 void MachineWhiteProc P((Widget w, XEvent *event,
337 String *prms, Cardinal *nprms));
338 void AnalyzeModeProc P((Widget w, XEvent *event,
339 String *prms, Cardinal *nprms));
340 void AnalyzeFileProc P((Widget w, XEvent *event,
341 String *prms, Cardinal *nprms));
342 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
344 void IcsClientProc P((Widget w, XEvent *event, String *prms,
346 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
347 void EditPositionProc P((Widget w, XEvent *event,
348 String *prms, Cardinal *nprms));
349 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
350 void EditCommentProc P((Widget w, XEvent *event,
351 String *prms, Cardinal *nprms));
352 void IcsInputBoxProc P((Widget w, XEvent *event,
353 String *prms, Cardinal *nprms));
354 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
355 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
356 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
357 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
358 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
365 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void StopObservingProc P((Widget w, XEvent *event, String *prms,
370 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
372 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
373 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
374 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
375 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
376 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
377 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
379 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
381 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
383 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
384 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
386 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
388 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
390 void AutocommProc P((Widget w, XEvent *event, String *prms,
392 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
393 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
394 void AutobsProc P((Widget w, XEvent *event, String *prms,
396 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
397 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
398 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
399 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
401 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
402 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
404 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
406 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
408 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
409 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
410 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
412 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
414 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
416 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
418 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
420 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
421 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
422 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
424 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
426 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
428 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
430 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
431 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
432 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
433 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
434 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
435 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
436 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void DisplayMove P((int moveNumber));
442 void DisplayTitle P((char *title));
443 void ICSInitScript P((void));
444 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
445 void ErrorPopUp P((char *title, char *text, int modal));
446 void ErrorPopDown P((void));
447 static char *ExpandPathName P((char *path));
448 static void CreateAnimVars P((void));
449 static void DragPieceMove P((int x, int y));
450 static void DrawDragPiece P((void));
451 char *ModeToWidgetName P((GameMode mode));
452 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
453 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
454 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
455 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
456 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
457 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
458 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
459 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
460 void GameListOptionsPopDown P(());
461 void ShufflePopDown P(());
462 void EnginePopDown P(());
463 void UciPopDown P(());
464 void TimeControlPopDown P(());
465 void NewVariantPopDown P(());
466 void SettingsPopDown P(());
467 void update_ics_width P(());
468 int get_term_width P(());
469 int CopyMemoProc P(());
471 * XBoard depends on Xt R4 or higher
473 int xtVersion = XtSpecificationRelease;
478 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
479 jailSquareColor, highlightSquareColor, premoveHighlightColor;
480 Pixel lowTimeWarningColor;
481 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
482 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
483 wjPieceGC, bjPieceGC, prelineGC, countGC;
484 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
485 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
486 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
487 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
488 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
489 ICSInputShell, fileNameShell, askQuestionShell;
490 Widget historyShell, evalGraphShell, gameListShell;
491 int hOffset; // [HGM] dual
492 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
493 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
494 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
495 Font clockFontID, coordFontID, countFontID;
496 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
497 XtAppContext appContext;
499 char *oldICSInteractionTitle;
503 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
505 Position commentX = -1, commentY = -1;
506 Dimension commentW, commentH;
507 typedef unsigned int BoardSize;
509 Boolean chessProgram;
511 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
512 int squareSize, smallLayout = 0, tinyLayout = 0,
513 marginW, marginH, // [HGM] for run-time resizing
514 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
515 ICSInputBoxUp = False, askQuestionUp = False,
516 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
517 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
518 Pixel timerForegroundPixel, timerBackgroundPixel;
519 Pixel buttonForegroundPixel, buttonBackgroundPixel;
520 char *chessDir, *programName, *programVersion,
521 *gameCopyFilename, *gamePasteFilename;
522 Boolean alwaysOnTop = False;
523 Boolean saveSettingsOnExit;
524 char *settingsFileName;
525 char *icsTextMenuString;
527 char *firstChessProgramNames;
528 char *secondChessProgramNames;
530 WindowPlacement wpMain;
531 WindowPlacement wpConsole;
532 WindowPlacement wpComment;
533 WindowPlacement wpMoveHistory;
534 WindowPlacement wpEvalGraph;
535 WindowPlacement wpEngineOutput;
536 WindowPlacement wpGameList;
537 WindowPlacement wpTags;
541 Pixmap pieceBitmap[2][(int)BlackPawn];
542 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
543 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
544 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
545 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
546 int useImages, useImageSqs;
547 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
548 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
549 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
550 XImage *ximLightSquare, *ximDarkSquare;
553 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
554 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
556 #define White(piece) ((int)(piece) < (int)BlackPawn)
558 /* Variables for doing smooth animation. This whole thing
559 would be much easier if the board was double-buffered,
560 but that would require a fairly major rewrite. */
565 GC blitGC, pieceGC, outlineGC;
566 XPoint startSquare, prevFrame, mouseDelta;
570 int startBoardX, startBoardY;
573 /* There can be two pieces being animated at once: a player
574 can begin dragging a piece before the remote opponent has moved. */
576 static AnimState game, player;
578 /* Bitmaps for use as masks when drawing XPM pieces.
579 Need one for each black and white piece. */
580 static Pixmap xpmMask[BlackKing + 1];
582 /* This magic number is the number of intermediate frames used
583 in each half of the animation. For short moves it's reduced
584 by 1. The total number of frames will be factor * 2 + 1. */
587 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
589 MenuItem fileMenu[] = {
590 {N_("New Game"), ResetProc},
591 {N_("New Shuffle Game ..."), ShuffleMenuProc},
592 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
593 {"----", NothingProc},
594 {N_("Load Game"), LoadGameProc},
595 {N_("Load Next Game"), LoadNextGameProc},
596 {N_("Load Previous Game"), LoadPrevGameProc},
597 {N_("Reload Same Game"), ReloadGameProc},
598 {N_("Save Game"), SaveGameProc},
599 {"----", NothingProc},
600 {N_("Copy Game"), CopyGameProc},
601 {N_("Paste Game"), PasteGameProc},
602 {"----", NothingProc},
603 {N_("Load Position"), LoadPositionProc},
604 {N_("Load Next Position"), LoadNextPositionProc},
605 {N_("Load Previous Position"), LoadPrevPositionProc},
606 {N_("Reload Same Position"), ReloadPositionProc},
607 {N_("Save Position"), SavePositionProc},
608 {"----", NothingProc},
609 {N_("Copy Position"), CopyPositionProc},
610 {N_("Paste Position"), PastePositionProc},
611 {"----", NothingProc},
612 {N_("Mail Move"), MailMoveProc},
613 {N_("Reload CMail Message"), ReloadCmailMsgProc},
614 {"----", NothingProc},
615 {N_("Exit"), QuitProc},
619 MenuItem modeMenu[] = {
620 {N_("Machine White"), MachineWhiteProc},
621 {N_("Machine Black"), MachineBlackProc},
622 {N_("Two Machines"), TwoMachinesProc},
623 {N_("Analysis Mode"), AnalyzeModeProc},
624 {N_("Analyze File"), AnalyzeFileProc },
625 {N_("ICS Client"), IcsClientProc},
626 {N_("Edit Game"), EditGameProc},
627 {N_("Edit Position"), EditPositionProc},
628 {N_("Training"), TrainingProc},
629 {"----", NothingProc},
630 {N_("Show Engine Output"), EngineOutputProc},
631 {N_("Show Evaluation Graph"), EvalGraphProc},
632 {N_("Show Game List"), ShowGameListProc},
633 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
634 {"----", NothingProc},
635 {N_("Edit Tags"), EditTagsProc},
636 {N_("Edit Comment"), EditCommentProc},
637 {N_("ICS Input Box"), IcsInputBoxProc},
638 {N_("Pause"), PauseProc},
642 MenuItem actionMenu[] = {
643 {N_("Accept"), AcceptProc},
644 {N_("Decline"), DeclineProc},
645 {N_("Rematch"), RematchProc},
646 {"----", NothingProc},
647 {N_("Call Flag"), CallFlagProc},
648 {N_("Draw"), DrawProc},
649 {N_("Adjourn"), AdjournProc},
650 {N_("Abort"), AbortProc},
651 {N_("Resign"), ResignProc},
652 {"----", NothingProc},
653 {N_("Stop Observing"), StopObservingProc},
654 {N_("Stop Examining"), StopExaminingProc},
655 {N_("Upload to Examine"), UploadProc},
656 {"----", NothingProc},
657 {N_("Adjudicate to White"), AdjuWhiteProc},
658 {N_("Adjudicate to Black"), AdjuBlackProc},
659 {N_("Adjudicate Draw"), AdjuDrawProc},
663 MenuItem stepMenu[] = {
664 {N_("Backward"), BackwardProc},
665 {N_("Forward"), ForwardProc},
666 {N_("Back to Start"), ToStartProc},
667 {N_("Forward to End"), ToEndProc},
668 {N_("Revert"), RevertProc},
669 {N_("Annotate"), AnnotateProc},
670 {N_("Truncate Game"), TruncateGameProc},
671 {"----", NothingProc},
672 {N_("Move Now"), MoveNowProc},
673 {N_("Retract Move"), RetractMoveProc},
677 MenuItem optionsMenu[] = {
678 {N_("Flip View"), FlipViewProc},
679 {"----", NothingProc},
680 {N_("Adjudications ..."), EngineMenuProc},
681 {N_("General Settings ..."), UciMenuProc},
682 {N_("Engine #1 Settings ..."), FirstSettingsProc},
683 {N_("Engine #2 Settings ..."), SecondSettingsProc},
684 {N_("Time Control ..."), TimeControlProc},
685 {N_("Game List ..."), GameListOptionsPopUp},
686 {"----", NothingProc},
687 {N_("Always Queen"), AlwaysQueenProc},
688 {N_("Animate Dragging"), AnimateDraggingProc},
689 {N_("Animate Moving"), AnimateMovingProc},
690 {N_("Auto Comment"), AutocommProc},
691 {N_("Auto Flag"), AutoflagProc},
692 {N_("Auto Flip View"), AutoflipProc},
693 {N_("Auto Observe"), AutobsProc},
694 {N_("Auto Raise Board"), AutoraiseProc},
695 {N_("Auto Save"), AutosaveProc},
696 {N_("Blindfold"), BlindfoldProc},
697 {N_("Flash Moves"), FlashMovesProc},
698 {N_("Get Move List"), GetMoveListProc},
700 {N_("Highlight Dragging"), HighlightDraggingProc},
702 {N_("Highlight Last Move"), HighlightLastMoveProc},
703 {N_("Move Sound"), MoveSoundProc},
704 {N_("ICS Alarm"), IcsAlarmProc},
705 {N_("Old Save Style"), OldSaveStyleProc},
706 {N_("Periodic Updates"), PeriodicUpdatesProc},
707 {N_("Ponder Next Move"), PonderNextMoveProc},
708 {N_("Popup Exit Message"), PopupExitMessageProc},
709 {N_("Popup Move Errors"), PopupMoveErrorsProc},
710 {N_("Premove"), PremoveProc},
711 {N_("Quiet Play"), QuietPlayProc},
712 {N_("Show Coords"), ShowCoordsProc},
713 {N_("Hide Thinking"), HideThinkingProc},
714 {N_("Test Legality"), TestLegalityProc},
715 {"----", NothingProc},
716 {N_("Save Settings Now"), SaveSettingsProc},
717 {N_("Save Settings on Exit"), SaveOnExitProc},
721 MenuItem helpMenu[] = {
722 {N_("Info XBoard"), InfoProc},
723 {N_("Man XBoard"), ManProc},
724 {"----", NothingProc},
725 {N_("Hint"), HintProc},
726 {N_("Book"), BookProc},
727 {"----", NothingProc},
728 {N_("About XBoard"), AboutProc},
733 {N_("File"), fileMenu},
734 {N_("Mode"), modeMenu},
735 {N_("Action"), actionMenu},
736 {N_("Step"), stepMenu},
737 {N_("Options"), optionsMenu},
738 {N_("Help"), helpMenu},
742 #define PAUSE_BUTTON N_("P")
743 MenuItem buttonBar[] = {
746 {PAUSE_BUTTON, PauseProc},
752 #define PIECE_MENU_SIZE 18
753 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
754 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
755 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
756 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
757 N_("Empty square"), N_("Clear board") },
758 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
759 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
760 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
761 N_("Empty square"), N_("Clear board") }
763 /* must be in same order as PieceMenuStrings! */
764 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
765 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
766 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
767 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
768 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
769 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
770 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
771 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
772 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
775 #define DROP_MENU_SIZE 6
776 String dropMenuStrings[DROP_MENU_SIZE] = {
777 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
779 /* must be in same order as PieceMenuStrings! */
780 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
781 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
782 WhiteRook, WhiteQueen
790 DropMenuEnables dmEnables[] = {
808 { XtNborderWidth, 0 },
809 { XtNdefaultDistance, 0 },
813 { XtNborderWidth, 0 },
814 { XtNresizable, (XtArgVal) True },
818 { XtNborderWidth, 0 },
824 { XtNjustify, (XtArgVal) XtJustifyRight },
825 { XtNlabel, (XtArgVal) "..." },
826 { XtNresizable, (XtArgVal) True },
827 { XtNresize, (XtArgVal) False }
830 Arg messageArgs[] = {
831 { XtNjustify, (XtArgVal) XtJustifyLeft },
832 { XtNlabel, (XtArgVal) "..." },
833 { XtNresizable, (XtArgVal) True },
834 { XtNresize, (XtArgVal) False }
838 { XtNborderWidth, 0 },
839 { XtNjustify, (XtArgVal) XtJustifyLeft }
842 XtResource clientResources[] = {
843 { "flashCount", "flashCount", XtRInt, sizeof(int),
844 XtOffset(AppDataPtr, flashCount), XtRImmediate,
845 (XtPointer) FLASH_COUNT },
848 XrmOptionDescRec shellOptions[] = {
849 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
850 { "-flash", "flashCount", XrmoptionNoArg, "3" },
851 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
854 XtActionsRec boardActions[] = {
855 { "DrawPosition", DrawPositionProc },
856 { "HandleUserMove", HandleUserMove },
857 { "AnimateUserMove", AnimateUserMove },
858 { "HandlePV", HandlePV },
859 { "SelectPV", SelectPV },
860 { "StopPV", StopPV },
861 { "FileNameAction", FileNameAction },
862 { "AskQuestionProc", AskQuestionProc },
863 { "AskQuestionReplyAction", AskQuestionReplyAction },
864 { "PieceMenuPopup", PieceMenuPopup },
865 { "WhiteClock", WhiteClock },
866 { "BlackClock", BlackClock },
867 { "Iconify", Iconify },
868 { "ResetProc", ResetProc },
869 { "LoadGameProc", LoadGameProc },
870 { "LoadNextGameProc", LoadNextGameProc },
871 { "LoadPrevGameProc", LoadPrevGameProc },
872 { "LoadSelectedProc", LoadSelectedProc },
873 { "SetFilterProc", SetFilterProc },
874 { "ReloadGameProc", ReloadGameProc },
875 { "LoadPositionProc", LoadPositionProc },
876 { "LoadNextPositionProc", LoadNextPositionProc },
877 { "LoadPrevPositionProc", LoadPrevPositionProc },
878 { "ReloadPositionProc", ReloadPositionProc },
879 { "CopyPositionProc", CopyPositionProc },
880 { "PastePositionProc", PastePositionProc },
881 { "CopyGameProc", CopyGameProc },
882 { "PasteGameProc", PasteGameProc },
883 { "SaveGameProc", SaveGameProc },
884 { "SavePositionProc", SavePositionProc },
885 { "MailMoveProc", MailMoveProc },
886 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
887 { "QuitProc", QuitProc },
888 { "MachineWhiteProc", MachineWhiteProc },
889 { "MachineBlackProc", MachineBlackProc },
890 { "AnalysisModeProc", AnalyzeModeProc },
891 { "AnalyzeFileProc", AnalyzeFileProc },
892 { "TwoMachinesProc", TwoMachinesProc },
893 { "IcsClientProc", IcsClientProc },
894 { "EditGameProc", EditGameProc },
895 { "EditPositionProc", EditPositionProc },
896 { "TrainingProc", EditPositionProc },
897 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
898 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
899 { "ShowGameListProc", ShowGameListProc },
900 { "ShowMoveListProc", HistoryShowProc},
901 { "EditTagsProc", EditCommentProc },
902 { "EditCommentProc", EditCommentProc },
903 { "IcsAlarmProc", IcsAlarmProc },
904 { "IcsInputBoxProc", IcsInputBoxProc },
905 { "PauseProc", PauseProc },
906 { "AcceptProc", AcceptProc },
907 { "DeclineProc", DeclineProc },
908 { "RematchProc", RematchProc },
909 { "CallFlagProc", CallFlagProc },
910 { "DrawProc", DrawProc },
911 { "AdjournProc", AdjournProc },
912 { "AbortProc", AbortProc },
913 { "ResignProc", ResignProc },
914 { "AdjuWhiteProc", AdjuWhiteProc },
915 { "AdjuBlackProc", AdjuBlackProc },
916 { "AdjuDrawProc", AdjuDrawProc },
917 { "EnterKeyProc", EnterKeyProc },
918 { "UpKeyProc", UpKeyProc },
919 { "DownKeyProc", DownKeyProc },
920 { "StopObservingProc", StopObservingProc },
921 { "StopExaminingProc", StopExaminingProc },
922 { "UploadProc", UploadProc },
923 { "BackwardProc", BackwardProc },
924 { "ForwardProc", ForwardProc },
925 { "ToStartProc", ToStartProc },
926 { "ToEndProc", ToEndProc },
927 { "RevertProc", RevertProc },
928 { "AnnotateProc", AnnotateProc },
929 { "TruncateGameProc", TruncateGameProc },
930 { "MoveNowProc", MoveNowProc },
931 { "RetractMoveProc", RetractMoveProc },
932 { "AlwaysQueenProc", AlwaysQueenProc },
933 { "AnimateDraggingProc", AnimateDraggingProc },
934 { "AnimateMovingProc", AnimateMovingProc },
935 { "AutoflagProc", AutoflagProc },
936 { "AutoflipProc", AutoflipProc },
937 { "AutobsProc", AutobsProc },
938 { "AutoraiseProc", AutoraiseProc },
939 { "AutosaveProc", AutosaveProc },
940 { "BlindfoldProc", BlindfoldProc },
941 { "FlashMovesProc", FlashMovesProc },
942 { "FlipViewProc", FlipViewProc },
943 { "GetMoveListProc", GetMoveListProc },
945 { "HighlightDraggingProc", HighlightDraggingProc },
947 { "HighlightLastMoveProc", HighlightLastMoveProc },
948 { "IcsAlarmProc", IcsAlarmProc },
949 { "MoveSoundProc", MoveSoundProc },
950 { "OldSaveStyleProc", OldSaveStyleProc },
951 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
952 { "PonderNextMoveProc", PonderNextMoveProc },
953 { "PopupExitMessageProc", PopupExitMessageProc },
954 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
955 { "PremoveProc", PremoveProc },
956 { "QuietPlayProc", QuietPlayProc },
957 { "ShowCoordsProc", ShowCoordsProc },
958 { "ShowThinkingProc", ShowThinkingProc },
959 { "HideThinkingProc", HideThinkingProc },
960 { "TestLegalityProc", TestLegalityProc },
961 { "SaveSettingsProc", SaveSettingsProc },
962 { "SaveOnExitProc", SaveOnExitProc },
963 { "InfoProc", InfoProc },
964 { "ManProc", ManProc },
965 { "HintProc", HintProc },
966 { "BookProc", BookProc },
967 { "AboutGameProc", AboutGameProc },
968 { "AboutProc", AboutProc },
969 { "DebugProc", DebugProc },
970 { "NothingProc", NothingProc },
971 { "CommentClick", (XtActionProc) CommentClick },
972 { "CommentPopDown", (XtActionProc) CommentPopDown },
973 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
974 { "TagsPopDown", (XtActionProc) TagsPopDown },
975 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
976 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
977 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
978 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
979 { "GameListPopDown", (XtActionProc) GameListPopDown },
980 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
981 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
982 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
983 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
984 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
985 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
986 { "EnginePopDown", (XtActionProc) EnginePopDown },
987 { "UciPopDown", (XtActionProc) UciPopDown },
988 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
989 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
990 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
991 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
994 char globalTranslations[] =
995 ":<Key>R: ResignProc() \n \
996 :<Key>r: ResetProc() \n \
997 :<Key>g: LoadGameProc() \n \
998 :<Key>N: LoadNextGameProc() \n \
999 :<Key>P: LoadPrevGameProc() \n \
1000 :<Key>Q: QuitProc() \n \
1001 :<Key>F: ToEndProc() \n \
1002 :<Key>f: ForwardProc() \n \
1003 :<Key>B: ToStartProc() \n \
1004 :<Key>b: BackwardProc() \n \
1005 :<Key>p: PauseProc() \n \
1006 :<Key>d: DrawProc() \n \
1007 :<Key>t: CallFlagProc() \n \
1008 :<Key>i: Iconify() \n \
1009 :<Key>c: Iconify() \n \
1010 :<Key>v: FlipViewProc() \n \
1011 <KeyDown>Control_L: BackwardProc() \n \
1012 <KeyUp>Control_L: ForwardProc() \n \
1013 <KeyDown>Control_R: BackwardProc() \n \
1014 <KeyUp>Control_R: ForwardProc() \n \
1015 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1016 \"Send to chess program:\",,1) \n \
1017 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1018 \"Send to second chess program:\",,2) \n";
1020 char boardTranslations[] =
1021 "<Btn1Down>: HandleUserMove() \n \
1022 <Btn1Up>: HandleUserMove() \n \
1023 <Btn1Motion>: AnimateUserMove() \n \
1024 <Btn3Motion>: HandlePV() \n \
1025 <Btn3Up>: PieceMenuPopup(menuB) \n \
1026 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1027 PieceMenuPopup(menuB) \n \
1028 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1029 PieceMenuPopup(menuW) \n \
1030 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1031 PieceMenuPopup(menuW) \n \
1032 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1033 PieceMenuPopup(menuB) \n";
1035 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1036 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1038 char ICSInputTranslations[] =
1039 "<Key>Up: UpKeyProc() \n "
1040 "<Key>Down: DownKeyProc() \n "
1041 "<Key>Return: EnterKeyProc() \n";
1043 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1044 // as the widget is destroyed before the up-click can call extend-end
1045 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1047 String xboardResources[] = {
1048 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1049 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1050 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1055 /* Max possible square size */
1056 #define MAXSQSIZE 256
1058 static int xpm_avail[MAXSQSIZE];
1060 #ifdef HAVE_DIR_STRUCT
1062 /* Extract piece size from filename */
1064 xpm_getsize(name, len, ext)
1075 if ((p=strchr(name, '.')) == NULL ||
1076 StrCaseCmp(p+1, ext) != 0)
1082 while (*p && isdigit(*p))
1089 /* Setup xpm_avail */
1091 xpm_getavail(dirname, ext)
1099 for (i=0; i<MAXSQSIZE; ++i)
1102 if (appData.debugMode)
1103 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1105 dir = opendir(dirname);
1108 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1109 programName, dirname);
1113 while ((ent=readdir(dir)) != NULL) {
1114 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1115 if (i > 0 && i < MAXSQSIZE)
1125 xpm_print_avail(fp, ext)
1131 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1132 for (i=1; i<MAXSQSIZE; ++i) {
1138 /* Return XPM piecesize closest to size */
1140 xpm_closest_to(dirname, size, ext)
1146 int sm_diff = MAXSQSIZE;
1150 xpm_getavail(dirname, ext);
1152 if (appData.debugMode)
1153 xpm_print_avail(stderr, ext);
1155 for (i=1; i<MAXSQSIZE; ++i) {
1158 diff = (diff<0) ? -diff : diff;
1159 if (diff < sm_diff) {
1167 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1173 #else /* !HAVE_DIR_STRUCT */
1174 /* If we are on a system without a DIR struct, we can't
1175 read the directory, so we can't collect a list of
1176 filenames, etc., so we can't do any size-fitting. */
1178 xpm_closest_to(dirname, size, ext)
1183 fprintf(stderr, _("\
1184 Warning: No DIR structure found on this system --\n\
1185 Unable to autosize for XPM/XIM pieces.\n\
1186 Please report this error to frankm@hiwaay.net.\n\
1187 Include system type & operating system in message.\n"));
1190 #endif /* HAVE_DIR_STRUCT */
1192 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1193 "magenta", "cyan", "white" };
1197 TextColors textColors[(int)NColorClasses];
1199 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1201 parse_color(str, which)
1205 char *p, buf[100], *d;
1208 if (strlen(str) > 99) /* watch bounds on buf */
1213 for (i=0; i<which; ++i) {
1220 /* Could be looking at something like:
1222 .. in which case we want to stop on a comma also */
1223 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1227 return -1; /* Use default for empty field */
1230 if (which == 2 || isdigit(*p))
1233 while (*p && isalpha(*p))
1238 for (i=0; i<8; ++i) {
1239 if (!StrCaseCmp(buf, cnames[i]))
1240 return which? (i+40) : (i+30);
1242 if (!StrCaseCmp(buf, "default")) return -1;
1244 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1249 parse_cpair(cc, str)
1253 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1254 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1259 /* bg and attr are optional */
1260 textColors[(int)cc].bg = parse_color(str, 1);
1261 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1262 textColors[(int)cc].attr = 0;
1268 /* Arrange to catch delete-window events */
1269 Atom wm_delete_window;
1271 CatchDeleteWindow(Widget w, String procname)
1274 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1275 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1276 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1283 XtSetArg(args[0], XtNiconic, False);
1284 XtSetValues(shellWidget, args, 1);
1286 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1289 //---------------------------------------------------------------------------------------------------------
1290 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1293 #define CW_USEDEFAULT (1<<31)
1294 #define ICS_TEXT_MENU_SIZE 90
1295 #define DEBUG_FILE "xboard.debug"
1296 #define SetCurrentDirectory chdir
1297 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1301 // these two must some day move to frontend.h, when they are implemented
1302 Boolean GameListIsUp();
1304 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1307 // front-end part of option handling
1309 // [HGM] This platform-dependent table provides the location for storing the color info
1310 extern char *crWhite, * crBlack;
1314 &appData.whitePieceColor,
1315 &appData.blackPieceColor,
1316 &appData.lightSquareColor,
1317 &appData.darkSquareColor,
1318 &appData.highlightSquareColor,
1319 &appData.premoveHighlightColor,
1320 &appData.lowTimeWarningColor,
1331 // [HGM] font: keep a font for each square size, even non-stndard ones
1332 #define NUM_SIZES 18
1333 #define MAX_SIZE 130
1334 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1335 char *fontTable[NUM_FONTS][MAX_SIZE];
1338 ParseFont(char *name, int number)
1339 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1341 if(sscanf(name, "size%d:", &size)) {
1342 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1343 // defer processing it until we know if it matches our board size
1344 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1345 fontTable[number][size] = strdup(strchr(name, ':')+1);
1346 fontValid[number][size] = True;
1351 case 0: // CLOCK_FONT
1352 appData.clockFont = strdup(name);
1354 case 1: // MESSAGE_FONT
1355 appData.font = strdup(name);
1357 case 2: // COORD_FONT
1358 appData.coordFont = strdup(name);
1363 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1368 { // only 2 fonts currently
1369 appData.clockFont = CLOCK_FONT_NAME;
1370 appData.coordFont = COORD_FONT_NAME;
1371 appData.font = DEFAULT_FONT_NAME;
1376 { // no-op, until we identify the code for this already in XBoard and move it here
1380 ParseColor(int n, char *name)
1381 { // in XBoard, just copy the color-name string
1382 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1386 ParseTextAttribs(ColorClass cc, char *s)
1388 (&appData.colorShout)[cc] = strdup(s);
1392 ParseBoardSize(void *addr, char *name)
1394 appData.boardSize = strdup(name);
1399 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1403 SetCommPortDefaults()
1404 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1407 // [HGM] args: these three cases taken out to stay in front-end
1409 SaveFontArg(FILE *f, ArgDescriptor *ad)
1411 char *name, buf[MSG_SIZ];
1412 int i, n = (int)ad->argLoc;
1414 case 0: // CLOCK_FONT
1415 name = appData.clockFont;
1417 case 1: // MESSAGE_FONT
1418 name = appData.font;
1420 case 2: // COORD_FONT
1421 name = appData.coordFont;
1426 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1427 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1428 fontTable[n][squareSize] = strdup(name);
1429 fontValid[n][squareSize] = True;
1432 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1433 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1438 { // nothing to do, as the sounds are at all times represented by their text-string names already
1442 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1443 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1444 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1448 SaveColor(FILE *f, ArgDescriptor *ad)
1449 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1450 if(colorVariable[(int)ad->argLoc])
1451 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1455 SaveBoardSize(FILE *f, char *name, void *addr)
1456 { // wrapper to shield back-end from BoardSize & sizeInfo
1457 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1461 ParseCommPortSettings(char *s)
1462 { // no such option in XBoard (yet)
1465 extern Widget engineOutputShell;
1466 extern Widget tagsShell, editTagsShell;
1468 GetActualPlacement(Widget wg, WindowPlacement *wp)
1478 XtSetArg(args[i], XtNx, &x); i++;
1479 XtSetArg(args[i], XtNy, &y); i++;
1480 XtSetArg(args[i], XtNwidth, &w); i++;
1481 XtSetArg(args[i], XtNheight, &h); i++;
1482 XtGetValues(wg, args, i);
1491 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1492 // In XBoard this will have to wait until awareness of window parameters is implemented
1493 GetActualPlacement(shellWidget, &wpMain);
1494 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1495 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1496 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1497 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1498 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1499 else GetActualPlacement(editShell, &wpComment);
1500 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1501 else GetActualPlacement(editTagsShell, &wpTags);
1505 PrintCommPortSettings(FILE *f, char *name)
1506 { // This option does not exist in XBoard
1510 MySearchPath(char *installDir, char *name, char *fullname)
1511 { // just append installDir and name. Perhaps ExpandPath should be used here?
1512 name = ExpandPathName(name);
1513 if(name && name[0] == '/') strcpy(fullname, name); else {
1514 sprintf(fullname, "%s%c%s", installDir, '/', name);
1520 MyGetFullPathName(char *name, char *fullname)
1521 { // should use ExpandPath?
1522 name = ExpandPathName(name);
1523 strcpy(fullname, name);
1528 EnsureOnScreen(int *x, int *y, int minX, int minY)
1535 { // [HGM] args: allows testing if main window is realized from back-end
1536 return xBoardWindow != 0;
1540 PopUpStartupDialog()
1541 { // start menu not implemented in XBoard
1544 ConvertToLine(int argc, char **argv)
1546 static char line[128*1024], buf[1024];
1550 for(i=1; i<argc; i++) {
1551 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1552 && argv[i][0] != '{' )
1553 sprintf(buf, "{%s} ", argv[i]);
1554 else sprintf(buf, "%s ", argv[i]);
1557 line[strlen(line)-1] = NULLCHAR;
1561 //--------------------------------------------------------------------------------------------
1563 extern Boolean twoBoards, partnerUp;
1566 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1568 #define BoardSize int
1569 void InitDrawingSizes(BoardSize boardSize, int flags)
1570 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1571 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1573 XtGeometryResult gres;
1576 if(!formWidget) return;
1579 * Enable shell resizing.
1581 shellArgs[0].value = (XtArgVal) &w;
1582 shellArgs[1].value = (XtArgVal) &h;
1583 XtGetValues(shellWidget, shellArgs, 2);
1585 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1586 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1587 XtSetValues(shellWidget, &shellArgs[2], 4);
1589 XtSetArg(args[0], XtNdefaultDistance, &sep);
1590 XtGetValues(formWidget, args, 1);
1592 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1593 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1595 hOffset = boardWidth + 10;
1596 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1597 secondSegments[i] = gridSegments[i];
1598 secondSegments[i].x1 += hOffset;
1599 secondSegments[i].x2 += hOffset;
1602 XtSetArg(args[0], XtNwidth, boardWidth);
1603 XtSetArg(args[1], XtNheight, boardHeight);
1604 XtSetValues(boardWidget, args, 2);
1606 timerWidth = (boardWidth - sep) / 2;
1607 XtSetArg(args[0], XtNwidth, timerWidth);
1608 XtSetValues(whiteTimerWidget, args, 1);
1609 XtSetValues(blackTimerWidget, args, 1);
1611 XawFormDoLayout(formWidget, False);
1613 if (appData.titleInWindow) {
1615 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1616 XtSetArg(args[i], XtNheight, &h); i++;
1617 XtGetValues(titleWidget, args, i);
1619 w = boardWidth - 2*bor;
1621 XtSetArg(args[0], XtNwidth, &w);
1622 XtGetValues(menuBarWidget, args, 1);
1623 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1626 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1627 if (gres != XtGeometryYes && appData.debugMode) {
1629 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1630 programName, gres, w, h, wr, hr);
1634 XawFormDoLayout(formWidget, True);
1637 * Inhibit shell resizing.
1639 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1640 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1641 shellArgs[4].value = shellArgs[2].value = w;
1642 shellArgs[5].value = shellArgs[3].value = h;
1643 XtSetValues(shellWidget, &shellArgs[0], 6);
1645 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1648 for(i=0; i<4; i++) {
1650 for(p=0; p<=(int)WhiteKing; p++)
1651 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1652 if(gameInfo.variant == VariantShogi) {
1653 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1654 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1655 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1656 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1657 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1660 if(gameInfo.variant == VariantGothic) {
1661 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1665 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1666 for(p=0; p<=(int)WhiteKing; p++)
1667 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1668 if(gameInfo.variant == VariantShogi) {
1669 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1670 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1671 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1672 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1673 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1676 if(gameInfo.variant == VariantGothic) {
1677 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1683 for(i=0; i<2; i++) {
1685 for(p=0; p<=(int)WhiteKing; p++)
1686 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1687 if(gameInfo.variant == VariantShogi) {
1688 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1689 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1690 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1691 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1692 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1695 if(gameInfo.variant == VariantGothic) {
1696 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1712 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1713 XSetWindowAttributes window_attributes;
1715 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1716 XrmValue vFrom, vTo;
1717 XtGeometryResult gres;
1720 int forceMono = False;
1722 srandom(time(0)); // [HGM] book: make random truly random
1724 setbuf(stdout, NULL);
1725 setbuf(stderr, NULL);
1728 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1729 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1733 programName = strrchr(argv[0], '/');
1734 if (programName == NULL)
1735 programName = argv[0];
1740 XtSetLanguageProc(NULL, NULL, NULL);
1741 bindtextdomain(PACKAGE, LOCALEDIR);
1742 textdomain(PACKAGE);
1746 XtAppInitialize(&appContext, "XBoard", shellOptions,
1747 XtNumber(shellOptions),
1748 &argc, argv, xboardResources, NULL, 0);
1749 appData.boardSize = "";
1750 InitAppData(ConvertToLine(argc, argv));
1752 if (p == NULL) p = "/tmp";
1753 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1754 gameCopyFilename = (char*) malloc(i);
1755 gamePasteFilename = (char*) malloc(i);
1756 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1757 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1759 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1760 clientResources, XtNumber(clientResources),
1763 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1764 static char buf[MSG_SIZ];
1765 EscapeExpand(buf, appData.initString);
1766 appData.initString = strdup(buf);
1767 EscapeExpand(buf, appData.secondInitString);
1768 appData.secondInitString = strdup(buf);
1769 EscapeExpand(buf, appData.firstComputerString);
1770 appData.firstComputerString = strdup(buf);
1771 EscapeExpand(buf, appData.secondComputerString);
1772 appData.secondComputerString = strdup(buf);
1775 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1778 if (chdir(chessDir) != 0) {
1779 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1785 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1786 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1787 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1788 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1791 setbuf(debugFP, NULL);
1794 /* [HGM,HR] make sure board size is acceptable */
1795 if(appData.NrFiles > BOARD_FILES ||
1796 appData.NrRanks > BOARD_RANKS )
1797 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1800 /* This feature does not work; animation needs a rewrite */
1801 appData.highlightDragging = FALSE;
1805 xDisplay = XtDisplay(shellWidget);
1806 xScreen = DefaultScreen(xDisplay);
1807 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1809 gameInfo.variant = StringToVariant(appData.variant);
1810 InitPosition(FALSE);
1813 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1815 if (isdigit(appData.boardSize[0])) {
1816 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1817 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1818 &fontPxlSize, &smallLayout, &tinyLayout);
1820 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1821 programName, appData.boardSize);
1825 /* Find some defaults; use the nearest known size */
1826 SizeDefaults *szd, *nearest;
1827 int distance = 99999;
1828 nearest = szd = sizeDefaults;
1829 while (szd->name != NULL) {
1830 if (abs(szd->squareSize - squareSize) < distance) {
1832 distance = abs(szd->squareSize - squareSize);
1833 if (distance == 0) break;
1837 if (i < 2) lineGap = nearest->lineGap;
1838 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1839 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1840 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1841 if (i < 6) smallLayout = nearest->smallLayout;
1842 if (i < 7) tinyLayout = nearest->tinyLayout;
1845 SizeDefaults *szd = sizeDefaults;
1846 if (*appData.boardSize == NULLCHAR) {
1847 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1848 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1851 if (szd->name == NULL) szd--;
1852 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1854 while (szd->name != NULL &&
1855 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1856 if (szd->name == NULL) {
1857 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1858 programName, appData.boardSize);
1862 squareSize = szd->squareSize;
1863 lineGap = szd->lineGap;
1864 clockFontPxlSize = szd->clockFontPxlSize;
1865 coordFontPxlSize = szd->coordFontPxlSize;
1866 fontPxlSize = szd->fontPxlSize;
1867 smallLayout = szd->smallLayout;
1868 tinyLayout = szd->tinyLayout;
1869 // [HGM] font: use defaults from settings file if available and not overruled
1871 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
1872 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
1873 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
1874 appData.font = fontTable[MESSAGE_FONT][squareSize];
1875 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
1876 appData.coordFont = fontTable[COORD_FONT][squareSize];
1878 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1879 if (strlen(appData.pixmapDirectory) > 0) {
1880 p = ExpandPathName(appData.pixmapDirectory);
1882 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1883 appData.pixmapDirectory);
1886 if (appData.debugMode) {
1887 fprintf(stderr, _("\
1888 XBoard square size (hint): %d\n\
1889 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1891 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1892 if (appData.debugMode) {
1893 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1897 /* [HR] height treated separately (hacked) */
1898 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1899 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1900 if (appData.showJail == 1) {
1901 /* Jail on top and bottom */
1902 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1903 XtSetArg(boardArgs[2], XtNheight,
1904 boardHeight + 2*(lineGap + squareSize));
1905 } else if (appData.showJail == 2) {
1907 XtSetArg(boardArgs[1], XtNwidth,
1908 boardWidth + 2*(lineGap + squareSize));
1909 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1912 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1913 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1917 * Determine what fonts to use.
1919 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1920 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1921 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1922 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1923 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1924 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1925 appData.font = FindFont(appData.font, fontPxlSize);
1926 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1927 countFontStruct = XQueryFont(xDisplay, countFontID);
1928 // appData.font = FindFont(appData.font, fontPxlSize);
1930 xdb = XtDatabase(xDisplay);
1931 XrmPutStringResource(&xdb, "*font", appData.font);
1934 * Detect if there are not enough colors available and adapt.
1936 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1937 appData.monoMode = True;
1940 if (!appData.monoMode) {
1941 vFrom.addr = (caddr_t) appData.lightSquareColor;
1942 vFrom.size = strlen(appData.lightSquareColor);
1943 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1944 if (vTo.addr == NULL) {
1945 appData.monoMode = True;
1948 lightSquareColor = *(Pixel *) vTo.addr;
1951 if (!appData.monoMode) {
1952 vFrom.addr = (caddr_t) appData.darkSquareColor;
1953 vFrom.size = strlen(appData.darkSquareColor);
1954 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1955 if (vTo.addr == NULL) {
1956 appData.monoMode = True;
1959 darkSquareColor = *(Pixel *) vTo.addr;
1962 if (!appData.monoMode) {
1963 vFrom.addr = (caddr_t) appData.whitePieceColor;
1964 vFrom.size = strlen(appData.whitePieceColor);
1965 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1966 if (vTo.addr == NULL) {
1967 appData.monoMode = True;
1970 whitePieceColor = *(Pixel *) vTo.addr;
1973 if (!appData.monoMode) {
1974 vFrom.addr = (caddr_t) appData.blackPieceColor;
1975 vFrom.size = strlen(appData.blackPieceColor);
1976 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1977 if (vTo.addr == NULL) {
1978 appData.monoMode = True;
1981 blackPieceColor = *(Pixel *) vTo.addr;
1985 if (!appData.monoMode) {
1986 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1987 vFrom.size = strlen(appData.highlightSquareColor);
1988 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1989 if (vTo.addr == NULL) {
1990 appData.monoMode = True;
1993 highlightSquareColor = *(Pixel *) vTo.addr;
1997 if (!appData.monoMode) {
1998 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1999 vFrom.size = strlen(appData.premoveHighlightColor);
2000 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2001 if (vTo.addr == NULL) {
2002 appData.monoMode = True;
2005 premoveHighlightColor = *(Pixel *) vTo.addr;
2010 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2013 if (appData.bitmapDirectory == NULL ||
2014 appData.bitmapDirectory[0] == NULLCHAR)
2015 appData.bitmapDirectory = DEF_BITMAP_DIR;
2018 if (appData.lowTimeWarning && !appData.monoMode) {
2019 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2020 vFrom.size = strlen(appData.lowTimeWarningColor);
2021 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2022 if (vTo.addr == NULL)
2023 appData.monoMode = True;
2025 lowTimeWarningColor = *(Pixel *) vTo.addr;
2028 if (appData.monoMode && appData.debugMode) {
2029 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2030 (unsigned long) XWhitePixel(xDisplay, xScreen),
2031 (unsigned long) XBlackPixel(xDisplay, xScreen));
2034 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2035 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2036 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2037 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2038 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2039 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2040 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2041 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2042 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2043 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2045 if (appData.colorize) {
2047 _("%s: can't parse color names; disabling colorization\n"),
2050 appData.colorize = FALSE;
2052 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2053 textColors[ColorNone].attr = 0;
2055 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2061 layoutName = "tinyLayout";
2062 } else if (smallLayout) {
2063 layoutName = "smallLayout";
2065 layoutName = "normalLayout";
2067 /* Outer layoutWidget is there only to provide a name for use in
2068 resources that depend on the layout style */
2070 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2071 layoutArgs, XtNumber(layoutArgs));
2073 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2074 formArgs, XtNumber(formArgs));
2075 XtSetArg(args[0], XtNdefaultDistance, &sep);
2076 XtGetValues(formWidget, args, 1);
2079 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2080 XtSetArg(args[0], XtNtop, XtChainTop);
2081 XtSetArg(args[1], XtNbottom, XtChainTop);
2082 XtSetArg(args[2], XtNright, XtChainLeft);
2083 XtSetValues(menuBarWidget, args, 3);
2085 widgetList[j++] = whiteTimerWidget =
2086 XtCreateWidget("whiteTime", labelWidgetClass,
2087 formWidget, timerArgs, XtNumber(timerArgs));
2088 XtSetArg(args[0], XtNfont, clockFontStruct);
2089 XtSetArg(args[1], XtNtop, XtChainTop);
2090 XtSetArg(args[2], XtNbottom, XtChainTop);
2091 XtSetValues(whiteTimerWidget, args, 3);
2093 widgetList[j++] = blackTimerWidget =
2094 XtCreateWidget("blackTime", labelWidgetClass,
2095 formWidget, timerArgs, XtNumber(timerArgs));
2096 XtSetArg(args[0], XtNfont, clockFontStruct);
2097 XtSetArg(args[1], XtNtop, XtChainTop);
2098 XtSetArg(args[2], XtNbottom, XtChainTop);
2099 XtSetValues(blackTimerWidget, args, 3);
2101 if (appData.titleInWindow) {
2102 widgetList[j++] = titleWidget =
2103 XtCreateWidget("title", labelWidgetClass, formWidget,
2104 titleArgs, XtNumber(titleArgs));
2105 XtSetArg(args[0], XtNtop, XtChainTop);
2106 XtSetArg(args[1], XtNbottom, XtChainTop);
2107 XtSetValues(titleWidget, args, 2);
2110 if (appData.showButtonBar) {
2111 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2112 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2113 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2114 XtSetArg(args[2], XtNtop, XtChainTop);
2115 XtSetArg(args[3], XtNbottom, XtChainTop);
2116 XtSetValues(buttonBarWidget, args, 4);
2119 widgetList[j++] = messageWidget =
2120 XtCreateWidget("message", labelWidgetClass, formWidget,
2121 messageArgs, XtNumber(messageArgs));
2122 XtSetArg(args[0], XtNtop, XtChainTop);
2123 XtSetArg(args[1], XtNbottom, XtChainTop);
2124 XtSetValues(messageWidget, args, 2);
2126 widgetList[j++] = boardWidget =
2127 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2128 XtNumber(boardArgs));
2130 XtManageChildren(widgetList, j);
2132 timerWidth = (boardWidth - sep) / 2;
2133 XtSetArg(args[0], XtNwidth, timerWidth);
2134 XtSetValues(whiteTimerWidget, args, 1);
2135 XtSetValues(blackTimerWidget, args, 1);
2137 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2138 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2139 XtGetValues(whiteTimerWidget, args, 2);
2141 if (appData.showButtonBar) {
2142 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2143 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2144 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2148 * formWidget uses these constraints but they are stored
2152 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2153 XtSetValues(menuBarWidget, args, i);
2154 if (appData.titleInWindow) {
2157 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2158 XtSetValues(whiteTimerWidget, args, i);
2160 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2161 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2162 XtSetValues(blackTimerWidget, args, i);
2164 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2165 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2166 XtSetValues(titleWidget, args, i);
2168 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2169 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2170 XtSetValues(messageWidget, args, i);
2171 if (appData.showButtonBar) {
2173 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2174 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2175 XtSetValues(buttonBarWidget, args, i);
2179 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2180 XtSetValues(whiteTimerWidget, args, i);
2182 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2183 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2184 XtSetValues(blackTimerWidget, args, i);
2186 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2187 XtSetValues(titleWidget, args, i);
2189 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2190 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2191 XtSetValues(messageWidget, args, i);
2192 if (appData.showButtonBar) {
2194 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2195 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2196 XtSetValues(buttonBarWidget, args, i);
2201 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2202 XtSetValues(whiteTimerWidget, args, i);
2204 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2205 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2206 XtSetValues(blackTimerWidget, args, i);
2208 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2209 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2210 XtSetValues(messageWidget, args, i);
2211 if (appData.showButtonBar) {
2213 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2214 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2215 XtSetValues(buttonBarWidget, args, i);
2219 XtSetArg(args[0], XtNfromVert, messageWidget);
2220 XtSetArg(args[1], XtNtop, XtChainTop);
2221 XtSetArg(args[2], XtNbottom, XtChainBottom);
2222 XtSetArg(args[3], XtNleft, XtChainLeft);
2223 XtSetArg(args[4], XtNright, XtChainRight);
2224 XtSetValues(boardWidget, args, 5);
2226 XtRealizeWidget(shellWidget);
2229 XtSetArg(args[0], XtNx, wpMain.x);
2230 XtSetArg(args[1], XtNy, wpMain.y);
2231 XtSetValues(shellWidget, args, 2);
2235 * Correct the width of the message and title widgets.
2236 * It is not known why some systems need the extra fudge term.
2237 * The value "2" is probably larger than needed.
2239 XawFormDoLayout(formWidget, False);
2241 #define WIDTH_FUDGE 2
2243 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2244 XtSetArg(args[i], XtNheight, &h); i++;
2245 XtGetValues(messageWidget, args, i);
2246 if (appData.showButtonBar) {
2248 XtSetArg(args[i], XtNwidth, &w); i++;
2249 XtGetValues(buttonBarWidget, args, i);
2250 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2252 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2255 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2256 if (gres != XtGeometryYes && appData.debugMode) {
2257 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2258 programName, gres, w, h, wr, hr);
2261 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2262 /* The size used for the child widget in layout lags one resize behind
2263 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2265 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2266 if (gres != XtGeometryYes && appData.debugMode) {
2267 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2268 programName, gres, w, h, wr, hr);
2271 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2272 XtSetArg(args[1], XtNright, XtChainRight);
2273 XtSetValues(messageWidget, args, 2);
2275 if (appData.titleInWindow) {
2277 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2278 XtSetArg(args[i], XtNheight, &h); i++;
2279 XtGetValues(titleWidget, args, i);
2281 w = boardWidth - 2*bor;
2283 XtSetArg(args[0], XtNwidth, &w);
2284 XtGetValues(menuBarWidget, args, 1);
2285 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2288 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2289 if (gres != XtGeometryYes && appData.debugMode) {
2291 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2292 programName, gres, w, h, wr, hr);
2295 XawFormDoLayout(formWidget, True);
2297 xBoardWindow = XtWindow(boardWidget);
2299 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2300 // not need to go into InitDrawingSizes().
2304 * Create X checkmark bitmap and initialize option menu checks.
2306 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2307 checkmark_bits, checkmark_width, checkmark_height);
2308 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2309 if (appData.alwaysPromoteToQueen) {
2310 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2313 if (appData.animateDragging) {
2314 XtSetValues(XtNameToWidget(menuBarWidget,
2315 "menuOptions.Animate Dragging"),
2318 if (appData.animate) {
2319 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2322 if (appData.autoComment) {
2323 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2326 if (appData.autoCallFlag) {
2327 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2330 if (appData.autoFlipView) {
2331 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2334 if (appData.autoObserve) {
2335 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2338 if (appData.autoRaiseBoard) {
2339 XtSetValues(XtNameToWidget(menuBarWidget,
2340 "menuOptions.Auto Raise Board"), args, 1);
2342 if (appData.autoSaveGames) {
2343 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2346 if (appData.saveGameFile[0] != NULLCHAR) {
2347 /* Can't turn this off from menu */
2348 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2350 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2354 if (appData.blindfold) {
2355 XtSetValues(XtNameToWidget(menuBarWidget,
2356 "menuOptions.Blindfold"), args, 1);
2358 if (appData.flashCount > 0) {
2359 XtSetValues(XtNameToWidget(menuBarWidget,
2360 "menuOptions.Flash Moves"),
2363 if (appData.getMoveList) {
2364 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2368 if (appData.highlightDragging) {
2369 XtSetValues(XtNameToWidget(menuBarWidget,
2370 "menuOptions.Highlight Dragging"),
2374 if (appData.highlightLastMove) {
2375 XtSetValues(XtNameToWidget(menuBarWidget,
2376 "menuOptions.Highlight Last Move"),
2379 if (appData.icsAlarm) {
2380 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2383 if (appData.ringBellAfterMoves) {
2384 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2387 if (appData.oldSaveStyle) {
2388 XtSetValues(XtNameToWidget(menuBarWidget,
2389 "menuOptions.Old Save Style"), args, 1);
2391 if (appData.periodicUpdates) {
2392 XtSetValues(XtNameToWidget(menuBarWidget,
2393 "menuOptions.Periodic Updates"), args, 1);
2395 if (appData.ponderNextMove) {
2396 XtSetValues(XtNameToWidget(menuBarWidget,
2397 "menuOptions.Ponder Next Move"), args, 1);
2399 if (appData.popupExitMessage) {
2400 XtSetValues(XtNameToWidget(menuBarWidget,
2401 "menuOptions.Popup Exit Message"), args, 1);
2403 if (appData.popupMoveErrors) {
2404 XtSetValues(XtNameToWidget(menuBarWidget,
2405 "menuOptions.Popup Move Errors"), args, 1);
2407 if (appData.premove) {
2408 XtSetValues(XtNameToWidget(menuBarWidget,
2409 "menuOptions.Premove"), args, 1);
2411 if (appData.quietPlay) {
2412 XtSetValues(XtNameToWidget(menuBarWidget,
2413 "menuOptions.Quiet Play"), args, 1);
2415 if (appData.showCoords) {
2416 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2419 if (appData.hideThinkingFromHuman) {
2420 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2423 if (appData.testLegality) {
2424 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2427 if (saveSettingsOnExit) {
2428 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2435 ReadBitmap(&wIconPixmap, "icon_white.bm",
2436 icon_white_bits, icon_white_width, icon_white_height);
2437 ReadBitmap(&bIconPixmap, "icon_black.bm",
2438 icon_black_bits, icon_black_width, icon_black_height);
2439 iconPixmap = wIconPixmap;
2441 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2442 XtSetValues(shellWidget, args, i);
2445 * Create a cursor for the board widget.
2447 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2448 XChangeWindowAttributes(xDisplay, xBoardWindow,
2449 CWCursor, &window_attributes);
2452 * Inhibit shell resizing.
2454 shellArgs[0].value = (XtArgVal) &w;
2455 shellArgs[1].value = (XtArgVal) &h;
2456 XtGetValues(shellWidget, shellArgs, 2);
2457 shellArgs[4].value = shellArgs[2].value = w;
2458 shellArgs[5].value = shellArgs[3].value = h;
2459 XtSetValues(shellWidget, &shellArgs[2], 4);
2460 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2461 marginH = h - boardHeight;
2463 CatchDeleteWindow(shellWidget, "QuitProc");
2468 if (appData.bitmapDirectory[0] != NULLCHAR) {
2475 /* Create regular pieces */
2476 if (!useImages) CreatePieces();
2481 if (appData.animate || appData.animateDragging)
2484 XtAugmentTranslations(formWidget,
2485 XtParseTranslationTable(globalTranslations));
2486 XtAugmentTranslations(boardWidget,
2487 XtParseTranslationTable(boardTranslations));
2488 XtAugmentTranslations(whiteTimerWidget,
2489 XtParseTranslationTable(whiteTranslations));
2490 XtAugmentTranslations(blackTimerWidget,
2491 XtParseTranslationTable(blackTranslations));
2493 /* Why is the following needed on some versions of X instead
2494 * of a translation? */
2495 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2496 (XtEventHandler) EventProc, NULL);
2499 /* [AS] Restore layout */
2500 if( wpMoveHistory.visible ) {
2504 if( wpEvalGraph.visible )
2509 if( wpEngineOutput.visible ) {
2510 EngineOutputPopUp();
2515 if (errorExitStatus == -1) {
2516 if (appData.icsActive) {
2517 /* We now wait until we see "login:" from the ICS before
2518 sending the logon script (problems with timestamp otherwise) */
2519 /*ICSInitScript();*/
2520 if (appData.icsInputBox) ICSInputBoxPopUp();
2524 signal(SIGWINCH, TermSizeSigHandler);
2526 signal(SIGINT, IntSigHandler);
2527 signal(SIGTERM, IntSigHandler);
2528 if (*appData.cmailGameName != NULLCHAR) {
2529 signal(SIGUSR1, CmailSigHandler);
2532 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2534 XtSetKeyboardFocus(shellWidget, formWidget);
2536 XtAppMainLoop(appContext);
2537 if (appData.debugMode) fclose(debugFP); // [DM] debug
2544 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2545 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2547 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2548 unlink(gameCopyFilename);
2549 unlink(gamePasteFilename);
2552 RETSIGTYPE TermSizeSigHandler(int sig)
2565 CmailSigHandler(sig)
2571 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2573 /* Activate call-back function CmailSigHandlerCallBack() */
2574 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2576 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2580 CmailSigHandlerCallBack(isr, closure, message, count, error)
2588 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2590 /**** end signal code ****/
2600 f = fopen(appData.icsLogon, "r");
2606 strcat(buf, appData.icsLogon);
2607 f = fopen(buf, "r");
2611 ProcessICSInitScript(f);
2618 EditCommentPopDown();
2633 if (!menuBarWidget) return;
2634 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2636 DisplayError("menuStep.Revert", 0);
2638 XtSetSensitive(w, !grey);
2640 w = XtNameToWidget(menuBarWidget, "menuStep.Annotate");
2642 DisplayError("menuStep.Annotate", 0);
2644 XtSetSensitive(w, !grey);
2649 SetMenuEnables(enab)
2653 if (!menuBarWidget) return;
2654 while (enab->name != NULL) {
2655 w = XtNameToWidget(menuBarWidget, enab->name);
2657 DisplayError(enab->name, 0);
2659 XtSetSensitive(w, enab->value);
2665 Enables icsEnables[] = {
2666 { "menuFile.Mail Move", False },
2667 { "menuFile.Reload CMail Message", False },
2668 { "menuMode.Machine Black", False },
2669 { "menuMode.Machine White", False },
2670 { "menuMode.Analysis Mode", False },
2671 { "menuMode.Analyze File", False },
2672 { "menuMode.Two Machines", False },
2674 { "menuHelp.Hint", False },
2675 { "menuHelp.Book", False },
2676 { "menuStep.Move Now", False },
2677 { "menuOptions.Periodic Updates", False },
2678 { "menuOptions.Hide Thinking", False },
2679 { "menuOptions.Ponder Next Move", False },
2681 { "menuStep.Annotate", False },
2685 Enables ncpEnables[] = {
2686 { "menuFile.Mail Move", False },
2687 { "menuFile.Reload CMail Message", False },
2688 { "menuMode.Machine White", False },
2689 { "menuMode.Machine Black", False },
2690 { "menuMode.Analysis Mode", False },
2691 { "menuMode.Analyze File", False },
2692 { "menuMode.Two Machines", False },
2693 { "menuMode.ICS Client", False },
2694 { "menuMode.ICS Input Box", False },
2695 { "Action", False },
2696 { "menuStep.Revert", False },
2697 { "menuStep.Annotate", False },
2698 { "menuStep.Move Now", False },
2699 { "menuStep.Retract Move", False },
2700 { "menuOptions.Auto Comment", False },
2701 { "menuOptions.Auto Flag", False },
2702 { "menuOptions.Auto Flip View", False },
2703 { "menuOptions.Auto Observe", False },
2704 { "menuOptions.Auto Raise Board", False },
2705 { "menuOptions.Get Move List", False },
2706 { "menuOptions.ICS Alarm", False },
2707 { "menuOptions.Move Sound", False },
2708 { "menuOptions.Quiet Play", False },
2709 { "menuOptions.Hide Thinking", False },
2710 { "menuOptions.Periodic Updates", False },
2711 { "menuOptions.Ponder Next Move", False },
2712 { "menuHelp.Hint", False },
2713 { "menuHelp.Book", False },
2717 Enables gnuEnables[] = {
2718 { "menuMode.ICS Client", False },
2719 { "menuMode.ICS Input Box", False },
2720 { "menuAction.Accept", False },
2721 { "menuAction.Decline", False },
2722 { "menuAction.Rematch", False },
2723 { "menuAction.Adjourn", False },
2724 { "menuAction.Stop Examining", False },
2725 { "menuAction.Stop Observing", False },
2726 { "menuAction.Upload to Examine", False },
2727 { "menuStep.Revert", False },
2728 { "menuStep.Annotate", False },
2729 { "menuOptions.Auto Comment", False },
2730 { "menuOptions.Auto Observe", False },
2731 { "menuOptions.Auto Raise Board", False },
2732 { "menuOptions.Get Move List", False },
2733 { "menuOptions.Premove", False },
2734 { "menuOptions.Quiet Play", False },
2736 /* The next two options rely on SetCmailMode being called *after* */
2737 /* SetGNUMode so that when GNU is being used to give hints these */
2738 /* menu options are still available */
2740 { "menuFile.Mail Move", False },
2741 { "menuFile.Reload CMail Message", False },
2745 Enables cmailEnables[] = {
2747 { "menuAction.Call Flag", False },
2748 { "menuAction.Draw", True },
2749 { "menuAction.Adjourn", False },
2750 { "menuAction.Abort", False },
2751 { "menuAction.Stop Observing", False },
2752 { "menuAction.Stop Examining", False },
2753 { "menuFile.Mail Move", True },
2754 { "menuFile.Reload CMail Message", True },
2758 Enables trainingOnEnables[] = {
2759 { "menuMode.Edit Comment", False },
2760 { "menuMode.Pause", False },
2761 { "menuStep.Forward", False },
2762 { "menuStep.Backward", False },
2763 { "menuStep.Forward to End", False },
2764 { "menuStep.Back to Start", False },
2765 { "menuStep.Move Now", False },
2766 { "menuStep.Truncate Game", False },
2770 Enables trainingOffEnables[] = {
2771 { "menuMode.Edit Comment", True },
2772 { "menuMode.Pause", True },
2773 { "menuStep.Forward", True },
2774 { "menuStep.Backward", True },
2775 { "menuStep.Forward to End", True },
2776 { "menuStep.Back to Start", True },
2777 { "menuStep.Move Now", True },
2778 { "menuStep.Truncate Game", True },
2782 Enables machineThinkingEnables[] = {
2783 { "menuFile.Load Game", False },
2784 { "menuFile.Load Next Game", False },
2785 { "menuFile.Load Previous Game", False },
2786 { "menuFile.Reload Same Game", False },
2787 { "menuFile.Paste Game", False },
2788 { "menuFile.Load Position", False },
2789 { "menuFile.Load Next Position", False },
2790 { "menuFile.Load Previous Position", False },
2791 { "menuFile.Reload Same Position", False },
2792 { "menuFile.Paste Position", False },
2793 { "menuMode.Machine White", False },
2794 { "menuMode.Machine Black", False },
2795 { "menuMode.Two Machines", False },
2796 { "menuStep.Retract Move", False },
2800 Enables userThinkingEnables[] = {
2801 { "menuFile.Load Game", True },
2802 { "menuFile.Load Next Game", True },
2803 { "menuFile.Load Previous Game", True },
2804 { "menuFile.Reload Same Game", True },
2805 { "menuFile.Paste Game", True },
2806 { "menuFile.Load Position", True },
2807 { "menuFile.Load Next Position", True },
2808 { "menuFile.Load Previous Position", True },
2809 { "menuFile.Reload Same Position", True },
2810 { "menuFile.Paste Position", True },
2811 { "menuMode.Machine White", True },
2812 { "menuMode.Machine Black", True },
2813 { "menuMode.Two Machines", True },
2814 { "menuStep.Retract Move", True },
2820 SetMenuEnables(icsEnables);
2823 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2824 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2831 SetMenuEnables(ncpEnables);
2837 SetMenuEnables(gnuEnables);
2843 SetMenuEnables(cmailEnables);
2849 SetMenuEnables(trainingOnEnables);
2850 if (appData.showButtonBar) {
2851 XtSetSensitive(buttonBarWidget, False);
2857 SetTrainingModeOff()
2859 SetMenuEnables(trainingOffEnables);
2860 if (appData.showButtonBar) {
2861 XtSetSensitive(buttonBarWidget, True);
2866 SetUserThinkingEnables()
2868 if (appData.noChessProgram) return;
2869 SetMenuEnables(userThinkingEnables);
2873 SetMachineThinkingEnables()
2875 if (appData.noChessProgram) return;
2876 SetMenuEnables(machineThinkingEnables);
2878 case MachinePlaysBlack:
2879 case MachinePlaysWhite:
2880 case TwoMachinesPlay:
2881 XtSetSensitive(XtNameToWidget(menuBarWidget,
2882 ModeToWidgetName(gameMode)), True);
2889 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2890 #define HISTORY_SIZE 64
\r
2891 static char *history[HISTORY_SIZE];
\r
2892 int histIn = 0, histP = 0;
\r
2895 SaveInHistory(char *cmd)
\r
2897 if (history[histIn] != NULL) {
\r
2898 free(history[histIn]);
\r
2899 history[histIn] = NULL;
\r
2901 if (*cmd == NULLCHAR) return;
\r
2902 history[histIn] = StrSave(cmd);
\r
2903 histIn = (histIn + 1) % HISTORY_SIZE;
\r
2904 if (history[histIn] != NULL) {
\r
2905 free(history[histIn]);
\r
2906 history[histIn] = NULL;
\r
2912 PrevInHistory(char *cmd)
\r
2915 if (histP == histIn) {
\r
2916 if (history[histIn] != NULL) free(history[histIn]);
\r
2917 history[histIn] = StrSave(cmd);
\r
2919 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
2920 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
2922 return history[histP];
\r
2928 if (histP == histIn) return NULL;
\r
2929 histP = (histP + 1) % HISTORY_SIZE;
\r
2930 return history[histP];
\r
2932 // end of borrowed code
\r
2934 #define Abs(n) ((n)<0 ? -(n) : (n))
2937 * Find a font that matches "pattern" that is as close as
2938 * possible to the targetPxlSize. Prefer fonts that are k
2939 * pixels smaller to fonts that are k pixels larger. The
2940 * pattern must be in the X Consortium standard format,
2941 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2942 * The return value should be freed with XtFree when no
2945 char *FindFont(pattern, targetPxlSize)
2949 char **fonts, *p, *best, *scalable, *scalableTail;
2950 int i, j, nfonts, minerr, err, pxlSize;
2953 char **missing_list;
2955 char *def_string, *base_fnt_lst, strInt[3];
2957 XFontStruct **fnt_list;
2959 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2960 sprintf(strInt, "%d", targetPxlSize);
2961 p = strstr(pattern, "--");
2962 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2963 strcat(base_fnt_lst, strInt);
2964 strcat(base_fnt_lst, strchr(p + 2, '-'));
2966 if ((fntSet = XCreateFontSet(xDisplay,
2970 &def_string)) == NULL) {
2972 fprintf(stderr, _("Unable to create font set.\n"));
2976 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2978 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2980 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2981 programName, pattern);
2989 for (i=0; i<nfonts; i++) {
2992 if (*p != '-') continue;
2994 if (*p == NULLCHAR) break;
2995 if (*p++ == '-') j++;
2997 if (j < 7) continue;
3000 scalable = fonts[i];
3003 err = pxlSize - targetPxlSize;
3004 if (Abs(err) < Abs(minerr) ||
3005 (minerr > 0 && err < 0 && -err == minerr)) {
3011 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3012 /* If the error is too big and there is a scalable font,
3013 use the scalable font. */
3014 int headlen = scalableTail - scalable;
3015 p = (char *) XtMalloc(strlen(scalable) + 10);
3016 while (isdigit(*scalableTail)) scalableTail++;
3017 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3019 p = (char *) XtMalloc(strlen(best) + 1);
3022 if (appData.debugMode) {
3023 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3024 pattern, targetPxlSize, p);
3027 if (missing_count > 0)
3028 XFreeStringList(missing_list);
3029 XFreeFontSet(xDisplay, fntSet);
3031 XFreeFontNames(fonts);
3038 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3039 | GCBackground | GCFunction | GCPlaneMask;
3040 XGCValues gc_values;
3043 gc_values.plane_mask = AllPlanes;
3044 gc_values.line_width = lineGap;
3045 gc_values.line_style = LineSolid;
3046 gc_values.function = GXcopy;
3048 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3049 gc_values.background = XBlackPixel(xDisplay, xScreen);
3050 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3052 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3053 gc_values.background = XWhitePixel(xDisplay, xScreen);
3054 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3055 XSetFont(xDisplay, coordGC, coordFontID);
3057 // [HGM] make font for holdings counts (white on black0
3058 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3059 gc_values.background = XBlackPixel(xDisplay, xScreen);
3060 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3061 XSetFont(xDisplay, countGC, countFontID);
3063 if (appData.monoMode) {
3064 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3065 gc_values.background = XWhitePixel(xDisplay, xScreen);
3066 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3068 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3069 gc_values.background = XBlackPixel(xDisplay, xScreen);
3070 lightSquareGC = wbPieceGC
3071 = XtGetGC(shellWidget, value_mask, &gc_values);
3073 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3074 gc_values.background = XWhitePixel(xDisplay, xScreen);
3075 darkSquareGC = bwPieceGC
3076 = XtGetGC(shellWidget, value_mask, &gc_values);
3078 if (DefaultDepth(xDisplay, xScreen) == 1) {
3079 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3080 gc_values.function = GXcopyInverted;
3081 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3082 gc_values.function = GXcopy;
3083 if (XBlackPixel(xDisplay, xScreen) == 1) {
3084 bwPieceGC = darkSquareGC;
3085 wbPieceGC = copyInvertedGC;
3087 bwPieceGC = copyInvertedGC;
3088 wbPieceGC = lightSquareGC;
3092 gc_values.foreground = highlightSquareColor;
3093 gc_values.background = highlightSquareColor;
3094 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3096 gc_values.foreground = premoveHighlightColor;
3097 gc_values.background = premoveHighlightColor;
3098 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3100 gc_values.foreground = lightSquareColor;
3101 gc_values.background = darkSquareColor;
3102 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3104 gc_values.foreground = darkSquareColor;
3105 gc_values.background = lightSquareColor;
3106 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3108 gc_values.foreground = jailSquareColor;
3109 gc_values.background = jailSquareColor;
3110 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3112 gc_values.foreground = whitePieceColor;
3113 gc_values.background = darkSquareColor;
3114 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3116 gc_values.foreground = whitePieceColor;
3117 gc_values.background = lightSquareColor;
3118 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3120 gc_values.foreground = whitePieceColor;
3121 gc_values.background = jailSquareColor;
3122 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3124 gc_values.foreground = blackPieceColor;
3125 gc_values.background = darkSquareColor;
3126 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3128 gc_values.foreground = blackPieceColor;
3129 gc_values.background = lightSquareColor;
3130 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3132 gc_values.foreground = blackPieceColor;
3133 gc_values.background = jailSquareColor;
3134 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3138 void loadXIM(xim, xmask, filename, dest, mask)
3151 fp = fopen(filename, "rb");
3153 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3160 for (y=0; y<h; ++y) {
3161 for (x=0; x<h; ++x) {
3166 XPutPixel(xim, x, y, blackPieceColor);
3168 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3171 XPutPixel(xim, x, y, darkSquareColor);
3173 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3176 XPutPixel(xim, x, y, whitePieceColor);
3178 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3181 XPutPixel(xim, x, y, lightSquareColor);
3183 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3189 /* create Pixmap of piece */
3190 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3192 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3195 /* create Pixmap of clipmask
3196 Note: We assume the white/black pieces have the same
3197 outline, so we make only 6 masks. This is okay
3198 since the XPM clipmask routines do the same. */
3200 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3202 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3205 /* now create the 1-bit version */
3206 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3209 values.foreground = 1;
3210 values.background = 0;
3212 /* Don't use XtGetGC, not read only */
3213 maskGC = XCreateGC(xDisplay, *mask,
3214 GCForeground | GCBackground, &values);
3215 XCopyPlane(xDisplay, temp, *mask, maskGC,
3216 0, 0, squareSize, squareSize, 0, 0, 1);
3217 XFreePixmap(xDisplay, temp);
3222 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3224 void CreateXIMPieces()
3229 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3234 /* The XSynchronize calls were copied from CreatePieces.
3235 Not sure if needed, but can't hurt */
3236 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3239 /* temp needed by loadXIM() */
3240 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3241 0, 0, ss, ss, AllPlanes, XYPixmap);
3243 if (strlen(appData.pixmapDirectory) == 0) {
3247 if (appData.monoMode) {
3248 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3252 fprintf(stderr, _("\nLoading XIMs...\n"));
3254 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3255 fprintf(stderr, "%d", piece+1);
3256 for (kind=0; kind<4; kind++) {
3257 fprintf(stderr, ".");
3258 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3259 ExpandPathName(appData.pixmapDirectory),
3260 piece <= (int) WhiteKing ? "" : "w",
3261 pieceBitmapNames[piece],
3263 ximPieceBitmap[kind][piece] =
3264 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3265 0, 0, ss, ss, AllPlanes, XYPixmap);
3266 if (appData.debugMode)
3267 fprintf(stderr, _("(File:%s:) "), buf);
3268 loadXIM(ximPieceBitmap[kind][piece],
3270 &(xpmPieceBitmap2[kind][piece]),
3271 &(ximMaskPm2[piece]));
3272 if(piece <= (int)WhiteKing)
3273 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3275 fprintf(stderr," ");
3277 /* Load light and dark squares */
3278 /* If the LSQ and DSQ pieces don't exist, we will
3279 draw them with solid squares. */
3280 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3281 if (access(buf, 0) != 0) {
3285 fprintf(stderr, _("light square "));
3287 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3288 0, 0, ss, ss, AllPlanes, XYPixmap);
3289 if (appData.debugMode)
3290 fprintf(stderr, _("(File:%s:) "), buf);
3292 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3293 fprintf(stderr, _("dark square "));
3294 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3295 ExpandPathName(appData.pixmapDirectory), ss);
3296 if (appData.debugMode)
3297 fprintf(stderr, _("(File:%s:) "), buf);
3299 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3300 0, 0, ss, ss, AllPlanes, XYPixmap);
3301 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3302 xpmJailSquare = xpmLightSquare;
3304 fprintf(stderr, _("Done.\n"));
3306 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3310 void CreateXPMPieces()
3314 u_int ss = squareSize;
3316 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3317 XpmColorSymbol symbols[4];
3319 /* The XSynchronize calls were copied from CreatePieces.
3320 Not sure if needed, but can't hurt */
3321 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3323 /* Setup translations so piece colors match square colors */
3324 symbols[0].name = "light_piece";
3325 symbols[0].value = appData.whitePieceColor;
3326 symbols[1].name = "dark_piece";
3327 symbols[1].value = appData.blackPieceColor;
3328 symbols[2].name = "light_square";
3329 symbols[2].value = appData.lightSquareColor;
3330 symbols[3].name = "dark_square";
3331 symbols[3].value = appData.darkSquareColor;
3333 attr.valuemask = XpmColorSymbols;
3334 attr.colorsymbols = symbols;
3335 attr.numsymbols = 4;
3337 if (appData.monoMode) {
3338 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3342 if (strlen(appData.pixmapDirectory) == 0) {
3343 XpmPieces* pieces = builtInXpms;
3346 while (pieces->size != squareSize && pieces->size) pieces++;
3347 if (!pieces->size) {
3348 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3351 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3352 for (kind=0; kind<4; kind++) {
3354 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3355 pieces->xpm[piece][kind],
3356 &(xpmPieceBitmap2[kind][piece]),
3357 NULL, &attr)) != 0) {
3358 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3362 if(piece <= (int) WhiteKing)
3363 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3367 xpmJailSquare = xpmLightSquare;
3371 fprintf(stderr, _("\nLoading XPMs...\n"));
3374 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3375 fprintf(stderr, "%d ", piece+1);
3376 for (kind=0; kind<4; kind++) {
3377 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3378 ExpandPathName(appData.pixmapDirectory),
3379 piece > (int) WhiteKing ? "w" : "",
3380 pieceBitmapNames[piece],
3382 if (appData.debugMode) {
3383 fprintf(stderr, _("(File:%s:) "), buf);
3385 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3386 &(xpmPieceBitmap2[kind][piece]),
3387 NULL, &attr)) != 0) {
3388 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3389 // [HGM] missing: read of unorthodox piece failed; substitute King.
3390 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3391 ExpandPathName(appData.pixmapDirectory),
3393 if (appData.debugMode) {
3394 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3396 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3397 &(xpmPieceBitmap2[kind][piece]),
3401 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3406 if(piece <= (int) WhiteKing)
3407 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3410 /* Load light and dark squares */
3411 /* If the LSQ and DSQ pieces don't exist, we will
3412 draw them with solid squares. */
3413 fprintf(stderr, _("light square "));
3414 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3415 if (access(buf, 0) != 0) {
3419 if (appData.debugMode)
3420 fprintf(stderr, _("(File:%s:) "), buf);
3422 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3423 &xpmLightSquare, NULL, &attr)) != 0) {
3424 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3427 fprintf(stderr, _("dark square "));
3428 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3429 ExpandPathName(appData.pixmapDirectory), ss);
3430 if (appData.debugMode) {
3431 fprintf(stderr, _("(File:%s:) "), buf);
3433 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3434 &xpmDarkSquare, NULL, &attr)) != 0) {
3435 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3439 xpmJailSquare = xpmLightSquare;
3440 fprintf(stderr, _("Done.\n"));
3442 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3445 #endif /* HAVE_LIBXPM */
3448 /* No built-in bitmaps */
3453 u_int ss = squareSize;
3455 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3458 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3459 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3460 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3461 pieceBitmapNames[piece],
3462 ss, kind == SOLID ? 's' : 'o');
3463 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3464 if(piece <= (int)WhiteKing)
3465 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3469 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3473 /* With built-in bitmaps */
3476 BuiltInBits* bib = builtInBits;
3479 u_int ss = squareSize;
3481 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3484 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3486 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3487 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3488 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3489 pieceBitmapNames[piece],
3490 ss, kind == SOLID ? 's' : 'o');
3491 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3492 bib->bits[kind][piece], ss, ss);
3493 if(piece <= (int)WhiteKing)
3494 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3498 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3503 void ReadBitmap(pm, name, bits, wreq, hreq)
3506 unsigned char bits[];
3512 char msg[MSG_SIZ], fullname[MSG_SIZ];
3514 if (*appData.bitmapDirectory != NULLCHAR) {
3515 strcpy(fullname, appData.bitmapDirectory);
3516 strcat(fullname, "/");
3517 strcat(fullname, name);
3518 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3519 &w, &h, pm, &x_hot, &y_hot);
3520 fprintf(stderr, "load %s\n", name);
3521 if (errcode != BitmapSuccess) {
3523 case BitmapOpenFailed:
3524 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3526 case BitmapFileInvalid:
3527 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3529 case BitmapNoMemory:
3530 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3534 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3538 fprintf(stderr, _("%s: %s...using built-in\n"),
3540 } else if (w != wreq || h != hreq) {
3542 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3543 programName, fullname, w, h, wreq, hreq);
3549 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3558 if (lineGap == 0) return;
3560 /* [HR] Split this into 2 loops for non-square boards. */
3562 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3563 gridSegments[i].x1 = 0;
3564 gridSegments[i].x2 =
3565 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3566 gridSegments[i].y1 = gridSegments[i].y2
3567 = lineGap / 2 + (i * (squareSize + lineGap));
3570 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3571 gridSegments[j + i].y1 = 0;
3572 gridSegments[j + i].y2 =
3573 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3574 gridSegments[j + i].x1 = gridSegments[j + i].x2
3575 = lineGap / 2 + (j * (squareSize + lineGap));
3579 static void MenuBarSelect(w, addr, index)
3584 XtActionProc proc = (XtActionProc) addr;
3586 (proc)(NULL, NULL, NULL, NULL);
3589 void CreateMenuBarPopup(parent, name, mb)
3599 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3602 XtSetArg(args[j], XtNleftMargin, 20); j++;
3603 XtSetArg(args[j], XtNrightMargin, 20); j++;
3605 while (mi->string != NULL) {
3606 if (strcmp(mi->string, "----") == 0) {
3607 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3610 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3611 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3613 XtAddCallback(entry, XtNcallback,
3614 (XtCallbackProc) MenuBarSelect,
3615 (caddr_t) mi->proc);
3621 Widget CreateMenuBar(mb)
3625 Widget anchor, menuBar;
3627 char menuName[MSG_SIZ];
3630 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3631 XtSetArg(args[j], XtNvSpace, 0); j++;
3632 XtSetArg(args[j], XtNborderWidth, 0); j++;
3633 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3634 formWidget, args, j);
3636 while (mb->name != NULL) {
3637 strcpy(menuName, "menu");
3638 strcat(menuName, mb->name);
3640 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3643 shortName[0] = _(mb->name)[0];
3644 shortName[1] = NULLCHAR;
3645 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3648 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3651 XtSetArg(args[j], XtNborderWidth, 0); j++;
3652 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3654 CreateMenuBarPopup(menuBar, menuName, mb);
3660 Widget CreateButtonBar(mi)
3664 Widget button, buttonBar;
3668 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3670 XtSetArg(args[j], XtNhSpace, 0); j++;
3672 XtSetArg(args[j], XtNborderWidth, 0); j++;
3673 XtSetArg(args[j], XtNvSpace, 0); j++;
3674 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3675 formWidget, args, j);
3677 while (mi->string != NULL) {
3680 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3681 XtSetArg(args[j], XtNborderWidth, 0); j++;
3683 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3684 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3685 buttonBar, args, j);
3686 XtAddCallback(button, XtNcallback,
3687 (XtCallbackProc) MenuBarSelect,
3688 (caddr_t) mi->proc);
3695 CreatePieceMenu(name, color)
3702 ChessSquare selection;
3704 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3705 boardWidget, args, 0);
3707 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3708 String item = pieceMenuStrings[color][i];
3710 if (strcmp(item, "----") == 0) {
3711 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3714 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3715 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3717 selection = pieceMenuTranslation[color][i];
3718 XtAddCallback(entry, XtNcallback,
3719 (XtCallbackProc) PieceMenuSelect,
3720 (caddr_t) selection);
3721 if (selection == WhitePawn || selection == BlackPawn) {
3722 XtSetArg(args[0], XtNpopupOnEntry, entry);
3723 XtSetValues(menu, args, 1);
3736 ChessSquare selection;
3738 whitePieceMenu = CreatePieceMenu("menuW", 0);
3739 blackPieceMenu = CreatePieceMenu("menuB", 1);
3741 XtRegisterGrabAction(PieceMenuPopup, True,
3742 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3743 GrabModeAsync, GrabModeAsync);
3745 XtSetArg(args[0], XtNlabel, _("Drop"));
3746 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3747 boardWidget, args, 1);
3748 for (i = 0; i < DROP_MENU_SIZE; i++) {
3749 String item = dropMenuStrings[i];
3751 if (strcmp(item, "----") == 0) {
3752 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3755 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3756 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3758 selection = dropMenuTranslation[i];
3759 XtAddCallback(entry, XtNcallback,
3760 (XtCallbackProc) DropMenuSelect,
3761 (caddr_t) selection);
3766 void SetupDropMenu()
3774 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3775 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3776 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3777 dmEnables[i].piece);
3778 XtSetSensitive(entry, p != NULL || !appData.testLegality
3779 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3780 && !appData.icsActive));
3782 while (p && *p++ == dmEnables[i].piece) count++;
3783 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3785 XtSetArg(args[j], XtNlabel, label); j++;
3786 XtSetValues(entry, args, j);
3790 void PieceMenuPopup(w, event, params, num_params)
3794 Cardinal *num_params;
3796 String whichMenu; int menuNr;
3797 if (event->type == ButtonRelease)
3798 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3799 else if (event->type == ButtonPress)
3800 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3802 case 0: whichMenu = params[0]; break;
3803 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3805 case -1: if (errorUp) ErrorPopDown();
3808 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3811 static void PieceMenuSelect(w, piece, junk)
3816 if (pmFromX < 0 || pmFromY < 0) return;
3817 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3820 static void DropMenuSelect(w, piece, junk)
3825 if (pmFromX < 0 || pmFromY < 0) return;
3826 DropMenuEvent(piece, pmFromX, pmFromY);
3829 void WhiteClock(w, event, prms, nprms)
3835 if (gameMode == EditPosition || gameMode == IcsExamining) {
3836 SetWhiteToPlayEvent();
3837 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3842 void BlackClock(w, event, prms, nprms)
3848 if (gameMode == EditPosition || gameMode == IcsExamining) {
3849 SetBlackToPlayEvent();
3850 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3857 * If the user selects on a border boundary, return -1; if off the board,
3858 * return -2. Otherwise map the event coordinate to the square.
3860 int EventToSquare(x, limit)
3868 if ((x % (squareSize + lineGap)) >= squareSize)
3870 x /= (squareSize + lineGap);
3876 static void do_flash_delay(msec)
3882 static void drawHighlight(file, rank, gc)
3888 if (lineGap == 0 || appData.blindfold) return;
3891 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3892 (squareSize + lineGap);
3893 y = lineGap/2 + rank * (squareSize + lineGap);
3895 x = lineGap/2 + file * (squareSize + lineGap);
3896 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3897 (squareSize + lineGap);
3900 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3901 squareSize+lineGap, squareSize+lineGap);
3904 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3905 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3908 SetHighlights(fromX, fromY, toX, toY)
3909 int fromX, fromY, toX, toY;
3911 if (hi1X != fromX || hi1Y != fromY) {
3912 if (hi1X >= 0 && hi1Y >= 0) {
3913 drawHighlight(hi1X, hi1Y, lineGC);
3915 } // [HGM] first erase both, then draw new!
3916 if (hi2X != toX || hi2Y != toY) {
3917 if (hi2X >= 0 && hi2Y >= 0) {
3918 drawHighlight(hi2X, hi2Y, lineGC);
3921 if (hi1X != fromX || hi1Y != fromY) {
3922 if (fromX >= 0 && fromY >= 0) {
3923 drawHighlight(fromX, fromY, highlineGC);
3926 if (hi2X != toX || hi2Y != toY) {
3927 if (toX >= 0 && toY >= 0) {
3928 drawHighlight(toX, toY, highlineGC);
3940 SetHighlights(-1, -1, -1, -1);
3945 SetPremoveHighlights(fromX, fromY, toX, toY)
3946 int fromX, fromY, toX, toY;
3948 if (pm1X != fromX || pm1Y != fromY) {
3949 if (pm1X >= 0 && pm1Y >= 0) {
3950 drawHighlight(pm1X, pm1Y, lineGC);
3952 if (fromX >= 0 && fromY >= 0) {
3953 drawHighlight(fromX, fromY, prelineGC);
3956 if (pm2X != toX || pm2Y != toY) {
3957 if (pm2X >= 0 && pm2Y >= 0) {
3958 drawHighlight(pm2X, pm2Y, lineGC);
3960 if (toX >= 0 && toY >= 0) {
3961 drawHighlight(toX, toY, prelineGC);
3971 ClearPremoveHighlights()
3973 SetPremoveHighlights(-1, -1, -1, -1);
3976 static void BlankSquare(x, y, color, piece, dest)
3981 if (useImages && useImageSqs) {
3985 pm = xpmLightSquare;
3990 case 2: /* neutral */
3995 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
3996 squareSize, squareSize, x, y);
4006 case 2: /* neutral */
4011 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
4016 I split out the routines to draw a piece so that I could
4017 make a generic flash routine.
4019 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4021 int square_color, x, y;
4024 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4025 switch (square_color) {
4027 case 2: /* neutral */
4029 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4030 ? *pieceToOutline(piece)
4031 : *pieceToSolid(piece),
4032 dest, bwPieceGC, 0, 0,
4033 squareSize, squareSize, x, y);
4036 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4037 ? *pieceToSolid(piece)
4038 : *pieceToOutline(piece),
4039 dest, wbPieceGC, 0, 0,
4040 squareSize, squareSize, x, y);
4045 static void monoDrawPiece(piece, square_color, x, y, dest)
4047 int square_color, x, y;
4050 switch (square_color) {
4052 case 2: /* neutral */
4054 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4055 ? *pieceToOutline(piece)
4056 : *pieceToSolid(piece),
4057 dest, bwPieceGC, 0, 0,
4058 squareSize, squareSize, x, y, 1);
4061 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4062 ? *pieceToSolid(piece)
4063 : *pieceToOutline(piece),
4064 dest, wbPieceGC, 0, 0,
4065 squareSize, squareSize, x, y, 1);
4070 static void colorDrawPiece(piece, square_color, x, y, dest)
4072 int square_color, x, y;
4075 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4076 switch (square_color) {
4078 XCopyPlane(xDisplay, *pieceToSolid(piece),
4079 dest, (int) piece < (int) BlackPawn
4080 ? wlPieceGC : blPieceGC, 0, 0,
4081 squareSize, squareSize, x, y, 1);
4084 XCopyPlane(xDisplay, *pieceToSolid(piece),
4085 dest, (int) piece < (int) BlackPawn
4086 ? wdPieceGC : bdPieceGC, 0, 0,
4087 squareSize, squareSize, x, y, 1);
4089 case 2: /* neutral */
4091 XCopyPlane(xDisplay, *pieceToSolid(piece),
4092 dest, (int) piece < (int) BlackPawn
4093 ? wjPieceGC : bjPieceGC, 0, 0,
4094 squareSize, squareSize, x, y, 1);
4099 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4101 int square_color, x, y;
4106 switch (square_color) {
4108 case 2: /* neutral */
4110 if ((int)piece < (int) BlackPawn) {
4118 if ((int)piece < (int) BlackPawn) {
4126 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4127 dest, wlPieceGC, 0, 0,
4128 squareSize, squareSize, x, y);
4131 typedef void (*DrawFunc)();
4133 DrawFunc ChooseDrawFunc()
4135 if (appData.monoMode) {
4136 if (DefaultDepth(xDisplay, xScreen) == 1) {
4137 return monoDrawPiece_1bit;
4139 return monoDrawPiece;
4143 return colorDrawPieceImage;
4145 return colorDrawPiece;
4149 /* [HR] determine square color depending on chess variant. */
4150 static int SquareColor(row, column)
4155 if (gameInfo.variant == VariantXiangqi) {
4156 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4158 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4160 } else if (row <= 4) {
4166 square_color = ((column + row) % 2) == 1;
4169 /* [hgm] holdings: next line makes all holdings squares light */
4170 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4172 return square_color;
4175 void DrawSquare(row, column, piece, do_flash)
4176 int row, column, do_flash;
4179 int square_color, x, y, direction, font_ascent, font_descent;
4182 XCharStruct overall;
4186 /* Calculate delay in milliseconds (2-delays per complete flash) */
4187 flash_delay = 500 / appData.flashRate;
4190 x = lineGap + ((BOARD_WIDTH-1)-column) *
4191 (squareSize + lineGap);
4192 y = lineGap + row * (squareSize + lineGap);
4194 x = lineGap + column * (squareSize + lineGap);
4195 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4196 (squareSize + lineGap);
4199 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4201 square_color = SquareColor(row, column);
4203 if ( // [HGM] holdings: blank out area between board and holdings
4204 column == BOARD_LEFT-1 || column == BOARD_RGHT
4205 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4206 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4207 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4209 // [HGM] print piece counts next to holdings
4210 string[1] = NULLCHAR;
4211 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4212 string[0] = '0' + piece;
4213 XTextExtents(countFontStruct, string, 1, &direction,
4214 &font_ascent, &font_descent, &overall);
4215 if (appData.monoMode) {
4216 XDrawImageString(xDisplay, xBoardWindow, countGC,
4217 x + squareSize - overall.width - 2,
4218 y + font_ascent + 1, string, 1);
4220 XDrawString(xDisplay, xBoardWindow, countGC,
4221 x + squareSize - overall.width - 2,
4222 y + font_ascent + 1, string, 1);
4225 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4226 string[0] = '0' + piece;
4227 XTextExtents(countFontStruct, string, 1, &direction,
4228 &font_ascent, &font_descent, &overall);
4229 if (appData.monoMode) {
4230 XDrawImageString(xDisplay, xBoardWindow, countGC,
4231 x + 2, y + font_ascent + 1, string, 1);
4233 XDrawString(xDisplay, xBoardWindow, countGC,
4234 x + 2, y + font_ascent + 1, string, 1);
4238 if (piece == EmptySquare || appData.blindfold) {
4239 BlankSquare(x, y, square_color, piece, xBoardWindow);
4241 drawfunc = ChooseDrawFunc();
4242 if (do_flash && appData.flashCount > 0) {
4243 for (i=0; i<appData.flashCount; ++i) {
4245 drawfunc(piece, square_color, x, y, xBoardWindow);
4246 XSync(xDisplay, False);
4247 do_flash_delay(flash_delay);
4249 BlankSquare(x, y, square_color, piece, xBoardWindow);