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];
1707 void EscapeExpand(char *p, char *q)
1708 { // [HGM] initstring: routine to shape up string arguments
1709 while(*p++ = *q++) if(p[-1] == '\\')
1711 case 'n': p[-1] = '\n'; break;
1712 case 'r': p[-1] = '\r'; break;
1713 case 't': p[-1] = '\t'; break;
1714 case '\\': p[-1] = '\\'; break;
1715 case 0: *p = 0; return;
1716 default: p[-1] = q[-1]; break;
1725 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1726 XSetWindowAttributes window_attributes;
1728 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1729 XrmValue vFrom, vTo;
1730 XtGeometryResult gres;
1733 int forceMono = False;
1735 srandom(time(0)); // [HGM] book: make random truly random
1737 setbuf(stdout, NULL);
1738 setbuf(stderr, NULL);
1741 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1742 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1746 programName = strrchr(argv[0], '/');
1747 if (programName == NULL)
1748 programName = argv[0];
1753 XtSetLanguageProc(NULL, NULL, NULL);
1754 bindtextdomain(PACKAGE, LOCALEDIR);
1755 textdomain(PACKAGE);
1759 XtAppInitialize(&appContext, "XBoard", shellOptions,
1760 XtNumber(shellOptions),
1761 &argc, argv, xboardResources, NULL, 0);
1762 appData.boardSize = "";
1763 InitAppData(ConvertToLine(argc, argv));
1765 if (p == NULL) p = "/tmp";
1766 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1767 gameCopyFilename = (char*) malloc(i);
1768 gamePasteFilename = (char*) malloc(i);
1769 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1770 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1772 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1773 clientResources, XtNumber(clientResources),
1776 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1777 static char buf[MSG_SIZ];
1778 EscapeExpand(buf, appData.initString);
1779 appData.initString = strdup(buf);
1780 EscapeExpand(buf, appData.secondInitString);
1781 appData.secondInitString = strdup(buf);
1782 EscapeExpand(buf, appData.firstComputerString);
1783 appData.firstComputerString = strdup(buf);
1784 EscapeExpand(buf, appData.secondComputerString);
1785 appData.secondComputerString = strdup(buf);
1788 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1791 if (chdir(chessDir) != 0) {
1792 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1798 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1799 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1800 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1801 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1804 setbuf(debugFP, NULL);
1807 /* [HGM,HR] make sure board size is acceptable */
1808 if(appData.NrFiles > BOARD_FILES ||
1809 appData.NrRanks > BOARD_RANKS )
1810 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1813 /* This feature does not work; animation needs a rewrite */
1814 appData.highlightDragging = FALSE;
1818 xDisplay = XtDisplay(shellWidget);
1819 xScreen = DefaultScreen(xDisplay);
1820 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1822 gameInfo.variant = StringToVariant(appData.variant);
1823 InitPosition(FALSE);
1826 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1828 if (isdigit(appData.boardSize[0])) {
1829 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1830 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1831 &fontPxlSize, &smallLayout, &tinyLayout);
1833 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1834 programName, appData.boardSize);
1838 /* Find some defaults; use the nearest known size */
1839 SizeDefaults *szd, *nearest;
1840 int distance = 99999;
1841 nearest = szd = sizeDefaults;
1842 while (szd->name != NULL) {
1843 if (abs(szd->squareSize - squareSize) < distance) {
1845 distance = abs(szd->squareSize - squareSize);
1846 if (distance == 0) break;
1850 if (i < 2) lineGap = nearest->lineGap;
1851 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1852 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1853 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1854 if (i < 6) smallLayout = nearest->smallLayout;
1855 if (i < 7) tinyLayout = nearest->tinyLayout;
1858 SizeDefaults *szd = sizeDefaults;
1859 if (*appData.boardSize == NULLCHAR) {
1860 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1861 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1864 if (szd->name == NULL) szd--;
1865 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1867 while (szd->name != NULL &&
1868 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1869 if (szd->name == NULL) {
1870 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1871 programName, appData.boardSize);
1875 squareSize = szd->squareSize;
1876 lineGap = szd->lineGap;
1877 clockFontPxlSize = szd->clockFontPxlSize;
1878 coordFontPxlSize = szd->coordFontPxlSize;
1879 fontPxlSize = szd->fontPxlSize;
1880 smallLayout = szd->smallLayout;
1881 tinyLayout = szd->tinyLayout;
1882 // [HGM] font: use defaults from settings file if available and not overruled
1884 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
1885 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
1886 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
1887 appData.font = fontTable[MESSAGE_FONT][squareSize];
1888 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
1889 appData.coordFont = fontTable[COORD_FONT][squareSize];
1891 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1892 if (strlen(appData.pixmapDirectory) > 0) {
1893 p = ExpandPathName(appData.pixmapDirectory);
1895 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1896 appData.pixmapDirectory);
1899 if (appData.debugMode) {
1900 fprintf(stderr, _("\
1901 XBoard square size (hint): %d\n\
1902 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1904 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1905 if (appData.debugMode) {
1906 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1910 /* [HR] height treated separately (hacked) */
1911 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1912 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1913 if (appData.showJail == 1) {
1914 /* Jail on top and bottom */
1915 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1916 XtSetArg(boardArgs[2], XtNheight,
1917 boardHeight + 2*(lineGap + squareSize));
1918 } else if (appData.showJail == 2) {
1920 XtSetArg(boardArgs[1], XtNwidth,
1921 boardWidth + 2*(lineGap + squareSize));
1922 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1925 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1926 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1930 * Determine what fonts to use.
1932 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1933 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1934 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1935 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1936 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1937 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1938 appData.font = FindFont(appData.font, fontPxlSize);
1939 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1940 countFontStruct = XQueryFont(xDisplay, countFontID);
1941 // appData.font = FindFont(appData.font, fontPxlSize);
1943 xdb = XtDatabase(xDisplay);
1944 XrmPutStringResource(&xdb, "*font", appData.font);
1947 * Detect if there are not enough colors available and adapt.
1949 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1950 appData.monoMode = True;
1953 if (!appData.monoMode) {
1954 vFrom.addr = (caddr_t) appData.lightSquareColor;
1955 vFrom.size = strlen(appData.lightSquareColor);
1956 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1957 if (vTo.addr == NULL) {
1958 appData.monoMode = True;
1961 lightSquareColor = *(Pixel *) vTo.addr;
1964 if (!appData.monoMode) {
1965 vFrom.addr = (caddr_t) appData.darkSquareColor;
1966 vFrom.size = strlen(appData.darkSquareColor);
1967 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1968 if (vTo.addr == NULL) {
1969 appData.monoMode = True;
1972 darkSquareColor = *(Pixel *) vTo.addr;
1975 if (!appData.monoMode) {
1976 vFrom.addr = (caddr_t) appData.whitePieceColor;
1977 vFrom.size = strlen(appData.whitePieceColor);
1978 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1979 if (vTo.addr == NULL) {
1980 appData.monoMode = True;
1983 whitePieceColor = *(Pixel *) vTo.addr;
1986 if (!appData.monoMode) {
1987 vFrom.addr = (caddr_t) appData.blackPieceColor;
1988 vFrom.size = strlen(appData.blackPieceColor);
1989 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1990 if (vTo.addr == NULL) {
1991 appData.monoMode = True;
1994 blackPieceColor = *(Pixel *) vTo.addr;
1998 if (!appData.monoMode) {
1999 vFrom.addr = (caddr_t) appData.highlightSquareColor;
2000 vFrom.size = strlen(appData.highlightSquareColor);
2001 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2002 if (vTo.addr == NULL) {
2003 appData.monoMode = True;
2006 highlightSquareColor = *(Pixel *) vTo.addr;
2010 if (!appData.monoMode) {
2011 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
2012 vFrom.size = strlen(appData.premoveHighlightColor);
2013 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2014 if (vTo.addr == NULL) {
2015 appData.monoMode = True;
2018 premoveHighlightColor = *(Pixel *) vTo.addr;
2023 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2026 if (appData.bitmapDirectory == NULL ||
2027 appData.bitmapDirectory[0] == NULLCHAR)
2028 appData.bitmapDirectory = DEF_BITMAP_DIR;
2031 if (appData.lowTimeWarning && !appData.monoMode) {
2032 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2033 vFrom.size = strlen(appData.lowTimeWarningColor);
2034 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2035 if (vTo.addr == NULL)
2036 appData.monoMode = True;
2038 lowTimeWarningColor = *(Pixel *) vTo.addr;
2041 if (appData.monoMode && appData.debugMode) {
2042 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2043 (unsigned long) XWhitePixel(xDisplay, xScreen),
2044 (unsigned long) XBlackPixel(xDisplay, xScreen));
2047 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2048 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2049 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2050 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2051 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2052 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2053 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2054 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2055 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2056 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2058 if (appData.colorize) {
2060 _("%s: can't parse color names; disabling colorization\n"),
2063 appData.colorize = FALSE;
2065 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2066 textColors[ColorNone].attr = 0;
2068 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2074 layoutName = "tinyLayout";
2075 } else if (smallLayout) {
2076 layoutName = "smallLayout";
2078 layoutName = "normalLayout";
2080 /* Outer layoutWidget is there only to provide a name for use in
2081 resources that depend on the layout style */
2083 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2084 layoutArgs, XtNumber(layoutArgs));
2086 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2087 formArgs, XtNumber(formArgs));
2088 XtSetArg(args[0], XtNdefaultDistance, &sep);
2089 XtGetValues(formWidget, args, 1);
2092 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2093 XtSetArg(args[0], XtNtop, XtChainTop);
2094 XtSetArg(args[1], XtNbottom, XtChainTop);
2095 XtSetArg(args[2], XtNright, XtChainLeft);
2096 XtSetValues(menuBarWidget, args, 3);
2098 widgetList[j++] = whiteTimerWidget =
2099 XtCreateWidget("whiteTime", labelWidgetClass,
2100 formWidget, timerArgs, XtNumber(timerArgs));
2101 XtSetArg(args[0], XtNfont, clockFontStruct);
2102 XtSetArg(args[1], XtNtop, XtChainTop);
2103 XtSetArg(args[2], XtNbottom, XtChainTop);
2104 XtSetValues(whiteTimerWidget, args, 3);
2106 widgetList[j++] = blackTimerWidget =
2107 XtCreateWidget("blackTime", labelWidgetClass,
2108 formWidget, timerArgs, XtNumber(timerArgs));
2109 XtSetArg(args[0], XtNfont, clockFontStruct);
2110 XtSetArg(args[1], XtNtop, XtChainTop);
2111 XtSetArg(args[2], XtNbottom, XtChainTop);
2112 XtSetValues(blackTimerWidget, args, 3);
2114 if (appData.titleInWindow) {
2115 widgetList[j++] = titleWidget =
2116 XtCreateWidget("title", labelWidgetClass, formWidget,
2117 titleArgs, XtNumber(titleArgs));
2118 XtSetArg(args[0], XtNtop, XtChainTop);
2119 XtSetArg(args[1], XtNbottom, XtChainTop);
2120 XtSetValues(titleWidget, args, 2);
2123 if (appData.showButtonBar) {
2124 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2125 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2126 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2127 XtSetArg(args[2], XtNtop, XtChainTop);
2128 XtSetArg(args[3], XtNbottom, XtChainTop);
2129 XtSetValues(buttonBarWidget, args, 4);
2132 widgetList[j++] = messageWidget =
2133 XtCreateWidget("message", labelWidgetClass, formWidget,
2134 messageArgs, XtNumber(messageArgs));
2135 XtSetArg(args[0], XtNtop, XtChainTop);
2136 XtSetArg(args[1], XtNbottom, XtChainTop);
2137 XtSetValues(messageWidget, args, 2);
2139 widgetList[j++] = boardWidget =
2140 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2141 XtNumber(boardArgs));
2143 XtManageChildren(widgetList, j);
2145 timerWidth = (boardWidth - sep) / 2;
2146 XtSetArg(args[0], XtNwidth, timerWidth);
2147 XtSetValues(whiteTimerWidget, args, 1);
2148 XtSetValues(blackTimerWidget, args, 1);
2150 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2151 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2152 XtGetValues(whiteTimerWidget, args, 2);
2154 if (appData.showButtonBar) {
2155 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2156 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2157 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2161 * formWidget uses these constraints but they are stored
2165 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2166 XtSetValues(menuBarWidget, args, i);
2167 if (appData.titleInWindow) {
2170 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2171 XtSetValues(whiteTimerWidget, args, i);
2173 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2174 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2175 XtSetValues(blackTimerWidget, args, i);
2177 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2178 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2179 XtSetValues(titleWidget, args, i);
2181 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2182 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2183 XtSetValues(messageWidget, args, i);
2184 if (appData.showButtonBar) {
2186 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2187 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2188 XtSetValues(buttonBarWidget, args, i);
2192 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2193 XtSetValues(whiteTimerWidget, args, i);
2195 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2196 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2197 XtSetValues(blackTimerWidget, args, i);
2199 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2200 XtSetValues(titleWidget, args, i);
2202 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2203 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2204 XtSetValues(messageWidget, args, i);
2205 if (appData.showButtonBar) {
2207 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2208 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2209 XtSetValues(buttonBarWidget, args, i);
2214 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2215 XtSetValues(whiteTimerWidget, args, i);
2217 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2218 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2219 XtSetValues(blackTimerWidget, args, i);
2221 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2222 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2223 XtSetValues(messageWidget, args, i);
2224 if (appData.showButtonBar) {
2226 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2227 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2228 XtSetValues(buttonBarWidget, args, i);
2232 XtSetArg(args[0], XtNfromVert, messageWidget);
2233 XtSetArg(args[1], XtNtop, XtChainTop);
2234 XtSetArg(args[2], XtNbottom, XtChainBottom);
2235 XtSetArg(args[3], XtNleft, XtChainLeft);
2236 XtSetArg(args[4], XtNright, XtChainRight);
2237 XtSetValues(boardWidget, args, 5);
2239 XtRealizeWidget(shellWidget);
2242 XtSetArg(args[0], XtNx, wpMain.x);
2243 XtSetArg(args[1], XtNy, wpMain.y);
2244 XtSetValues(shellWidget, args, 2);
2248 * Correct the width of the message and title widgets.
2249 * It is not known why some systems need the extra fudge term.
2250 * The value "2" is probably larger than needed.
2252 XawFormDoLayout(formWidget, False);
2254 #define WIDTH_FUDGE 2
2256 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2257 XtSetArg(args[i], XtNheight, &h); i++;
2258 XtGetValues(messageWidget, args, i);
2259 if (appData.showButtonBar) {
2261 XtSetArg(args[i], XtNwidth, &w); i++;
2262 XtGetValues(buttonBarWidget, args, i);
2263 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2265 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2268 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2269 if (gres != XtGeometryYes && appData.debugMode) {
2270 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2271 programName, gres, w, h, wr, hr);
2274 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2275 /* The size used for the child widget in layout lags one resize behind
2276 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2278 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2279 if (gres != XtGeometryYes && appData.debugMode) {
2280 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2281 programName, gres, w, h, wr, hr);
2284 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2285 XtSetArg(args[1], XtNright, XtChainRight);
2286 XtSetValues(messageWidget, args, 2);
2288 if (appData.titleInWindow) {
2290 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2291 XtSetArg(args[i], XtNheight, &h); i++;
2292 XtGetValues(titleWidget, args, i);
2294 w = boardWidth - 2*bor;
2296 XtSetArg(args[0], XtNwidth, &w);
2297 XtGetValues(menuBarWidget, args, 1);
2298 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2301 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2302 if (gres != XtGeometryYes && appData.debugMode) {
2304 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2305 programName, gres, w, h, wr, hr);
2308 XawFormDoLayout(formWidget, True);
2310 xBoardWindow = XtWindow(boardWidget);
2312 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2313 // not need to go into InitDrawingSizes().
2317 * Create X checkmark bitmap and initialize option menu checks.
2319 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2320 checkmark_bits, checkmark_width, checkmark_height);
2321 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2322 if (appData.alwaysPromoteToQueen) {
2323 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2326 if (appData.animateDragging) {
2327 XtSetValues(XtNameToWidget(menuBarWidget,
2328 "menuOptions.Animate Dragging"),
2331 if (appData.animate) {
2332 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2335 if (appData.autoComment) {
2336 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2339 if (appData.autoCallFlag) {
2340 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2343 if (appData.autoFlipView) {
2344 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2347 if (appData.autoObserve) {
2348 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2351 if (appData.autoRaiseBoard) {
2352 XtSetValues(XtNameToWidget(menuBarWidget,
2353 "menuOptions.Auto Raise Board"), args, 1);
2355 if (appData.autoSaveGames) {
2356 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2359 if (appData.saveGameFile[0] != NULLCHAR) {
2360 /* Can't turn this off from menu */
2361 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2363 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2367 if (appData.blindfold) {
2368 XtSetValues(XtNameToWidget(menuBarWidget,
2369 "menuOptions.Blindfold"), args, 1);
2371 if (appData.flashCount > 0) {
2372 XtSetValues(XtNameToWidget(menuBarWidget,
2373 "menuOptions.Flash Moves"),
2376 if (appData.getMoveList) {
2377 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2381 if (appData.highlightDragging) {
2382 XtSetValues(XtNameToWidget(menuBarWidget,
2383 "menuOptions.Highlight Dragging"),
2387 if (appData.highlightLastMove) {
2388 XtSetValues(XtNameToWidget(menuBarWidget,
2389 "menuOptions.Highlight Last Move"),
2392 if (appData.icsAlarm) {
2393 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2396 if (appData.ringBellAfterMoves) {
2397 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2400 if (appData.oldSaveStyle) {
2401 XtSetValues(XtNameToWidget(menuBarWidget,
2402 "menuOptions.Old Save Style"), args, 1);
2404 if (appData.periodicUpdates) {
2405 XtSetValues(XtNameToWidget(menuBarWidget,
2406 "menuOptions.Periodic Updates"), args, 1);
2408 if (appData.ponderNextMove) {
2409 XtSetValues(XtNameToWidget(menuBarWidget,
2410 "menuOptions.Ponder Next Move"), args, 1);
2412 if (appData.popupExitMessage) {
2413 XtSetValues(XtNameToWidget(menuBarWidget,
2414 "menuOptions.Popup Exit Message"), args, 1);
2416 if (appData.popupMoveErrors) {
2417 XtSetValues(XtNameToWidget(menuBarWidget,
2418 "menuOptions.Popup Move Errors"), args, 1);
2420 if (appData.premove) {
2421 XtSetValues(XtNameToWidget(menuBarWidget,
2422 "menuOptions.Premove"), args, 1);
2424 if (appData.quietPlay) {
2425 XtSetValues(XtNameToWidget(menuBarWidget,
2426 "menuOptions.Quiet Play"), args, 1);
2428 if (appData.showCoords) {
2429 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2432 if (appData.hideThinkingFromHuman) {
2433 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2436 if (appData.testLegality) {
2437 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2440 if (saveSettingsOnExit) {
2441 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2448 ReadBitmap(&wIconPixmap, "icon_white.bm",
2449 icon_white_bits, icon_white_width, icon_white_height);
2450 ReadBitmap(&bIconPixmap, "icon_black.bm",
2451 icon_black_bits, icon_black_width, icon_black_height);
2452 iconPixmap = wIconPixmap;
2454 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2455 XtSetValues(shellWidget, args, i);
2458 * Create a cursor for the board widget.
2460 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2461 XChangeWindowAttributes(xDisplay, xBoardWindow,
2462 CWCursor, &window_attributes);
2465 * Inhibit shell resizing.
2467 shellArgs[0].value = (XtArgVal) &w;
2468 shellArgs[1].value = (XtArgVal) &h;
2469 XtGetValues(shellWidget, shellArgs, 2);
2470 shellArgs[4].value = shellArgs[2].value = w;
2471 shellArgs[5].value = shellArgs[3].value = h;
2472 XtSetValues(shellWidget, &shellArgs[2], 4);
2473 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2474 marginH = h - boardHeight;
2476 CatchDeleteWindow(shellWidget, "QuitProc");
2481 if (appData.bitmapDirectory[0] != NULLCHAR) {
2488 /* Create regular pieces */
2489 if (!useImages) CreatePieces();
2494 if (appData.animate || appData.animateDragging)
2497 XtAugmentTranslations(formWidget,
2498 XtParseTranslationTable(globalTranslations));
2499 XtAugmentTranslations(boardWidget,
2500 XtParseTranslationTable(boardTranslations));
2501 XtAugmentTranslations(whiteTimerWidget,
2502 XtParseTranslationTable(whiteTranslations));
2503 XtAugmentTranslations(blackTimerWidget,
2504 XtParseTranslationTable(blackTranslations));
2506 /* Why is the following needed on some versions of X instead
2507 * of a translation? */
2508 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2509 (XtEventHandler) EventProc, NULL);
2512 /* [AS] Restore layout */
2513 if( wpMoveHistory.visible ) {
2517 if( wpEvalGraph.visible )
2522 if( wpEngineOutput.visible ) {
2523 EngineOutputPopUp();
2528 if (errorExitStatus == -1) {
2529 if (appData.icsActive) {
2530 /* We now wait until we see "login:" from the ICS before
2531 sending the logon script (problems with timestamp otherwise) */
2532 /*ICSInitScript();*/
2533 if (appData.icsInputBox) ICSInputBoxPopUp();
2537 signal(SIGWINCH, TermSizeSigHandler);
2539 signal(SIGINT, IntSigHandler);
2540 signal(SIGTERM, IntSigHandler);
2541 if (*appData.cmailGameName != NULLCHAR) {
2542 signal(SIGUSR1, CmailSigHandler);
2545 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2547 XtSetKeyboardFocus(shellWidget, formWidget);
2549 XtAppMainLoop(appContext);
2550 if (appData.debugMode) fclose(debugFP); // [DM] debug
2557 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2558 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2560 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2561 unlink(gameCopyFilename);
2562 unlink(gamePasteFilename);
2565 RETSIGTYPE TermSizeSigHandler(int sig)
2578 CmailSigHandler(sig)
2584 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2586 /* Activate call-back function CmailSigHandlerCallBack() */
2587 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2589 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2593 CmailSigHandlerCallBack(isr, closure, message, count, error)
2601 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2603 /**** end signal code ****/
2613 f = fopen(appData.icsLogon, "r");
2619 strcat(buf, appData.icsLogon);
2620 f = fopen(buf, "r");
2624 ProcessICSInitScript(f);
2631 EditCommentPopDown();
2646 if (!menuBarWidget) return;
2647 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2649 DisplayError("menuStep.Revert", 0);
2651 XtSetSensitive(w, !grey);
2653 w = XtNameToWidget(menuBarWidget, "menuStep.Annotate");
2655 DisplayError("menuStep.Annotate", 0);
2657 XtSetSensitive(w, !grey);
2662 SetMenuEnables(enab)
2666 if (!menuBarWidget) return;
2667 while (enab->name != NULL) {
2668 w = XtNameToWidget(menuBarWidget, enab->name);
2670 DisplayError(enab->name, 0);
2672 XtSetSensitive(w, enab->value);
2678 Enables icsEnables[] = {
2679 { "menuFile.Mail Move", False },
2680 { "menuFile.Reload CMail Message", False },
2681 { "menuMode.Machine Black", False },
2682 { "menuMode.Machine White", False },
2683 { "menuMode.Analysis Mode", False },
2684 { "menuMode.Analyze File", False },
2685 { "menuMode.Two Machines", False },
2687 { "menuHelp.Hint", False },
2688 { "menuHelp.Book", False },
2689 { "menuStep.Move Now", False },
2690 { "menuOptions.Periodic Updates", False },
2691 { "menuOptions.Hide Thinking", False },
2692 { "menuOptions.Ponder Next Move", False },
2694 { "menuStep.Annotate", False },
2698 Enables ncpEnables[] = {
2699 { "menuFile.Mail Move", False },
2700 { "menuFile.Reload CMail Message", False },
2701 { "menuMode.Machine White", False },
2702 { "menuMode.Machine Black", False },
2703 { "menuMode.Analysis Mode", False },
2704 { "menuMode.Analyze File", False },
2705 { "menuMode.Two Machines", False },
2706 { "menuMode.ICS Client", False },
2707 { "menuMode.ICS Input Box", False },
2708 { "Action", False },
2709 { "menuStep.Revert", False },
2710 { "menuStep.Annotate", False },
2711 { "menuStep.Move Now", False },
2712 { "menuStep.Retract Move", False },
2713 { "menuOptions.Auto Comment", False },
2714 { "menuOptions.Auto Flag", False },
2715 { "menuOptions.Auto Flip View", False },
2716 { "menuOptions.Auto Observe", False },
2717 { "menuOptions.Auto Raise Board", False },
2718 { "menuOptions.Get Move List", False },
2719 { "menuOptions.ICS Alarm", False },
2720 { "menuOptions.Move Sound", False },
2721 { "menuOptions.Quiet Play", False },
2722 { "menuOptions.Hide Thinking", False },
2723 { "menuOptions.Periodic Updates", False },
2724 { "menuOptions.Ponder Next Move", False },
2725 { "menuHelp.Hint", False },
2726 { "menuHelp.Book", False },
2730 Enables gnuEnables[] = {
2731 { "menuMode.ICS Client", False },
2732 { "menuMode.ICS Input Box", False },
2733 { "menuAction.Accept", False },
2734 { "menuAction.Decline", False },
2735 { "menuAction.Rematch", False },
2736 { "menuAction.Adjourn", False },
2737 { "menuAction.Stop Examining", False },
2738 { "menuAction.Stop Observing", False },
2739 { "menuAction.Upload to Examine", False },
2740 { "menuStep.Revert", False },
2741 { "menuStep.Annotate", False },
2742 { "menuOptions.Auto Comment", False },
2743 { "menuOptions.Auto Observe", False },
2744 { "menuOptions.Auto Raise Board", False },
2745 { "menuOptions.Get Move List", False },
2746 { "menuOptions.Premove", False },
2747 { "menuOptions.Quiet Play", False },
2749 /* The next two options rely on SetCmailMode being called *after* */
2750 /* SetGNUMode so that when GNU is being used to give hints these */
2751 /* menu options are still available */
2753 { "menuFile.Mail Move", False },
2754 { "menuFile.Reload CMail Message", False },
2758 Enables cmailEnables[] = {
2760 { "menuAction.Call Flag", False },
2761 { "menuAction.Draw", True },
2762 { "menuAction.Adjourn", False },
2763 { "menuAction.Abort", False },
2764 { "menuAction.Stop Observing", False },
2765 { "menuAction.Stop Examining", False },
2766 { "menuFile.Mail Move", True },
2767 { "menuFile.Reload CMail Message", True },
2771 Enables trainingOnEnables[] = {
2772 { "menuMode.Edit Comment", False },
2773 { "menuMode.Pause", False },
2774 { "menuStep.Forward", False },
2775 { "menuStep.Backward", False },
2776 { "menuStep.Forward to End", False },
2777 { "menuStep.Back to Start", False },
2778 { "menuStep.Move Now", False },
2779 { "menuStep.Truncate Game", False },
2783 Enables trainingOffEnables[] = {
2784 { "menuMode.Edit Comment", True },
2785 { "menuMode.Pause", True },
2786 { "menuStep.Forward", True },
2787 { "menuStep.Backward", True },
2788 { "menuStep.Forward to End", True },
2789 { "menuStep.Back to Start", True },
2790 { "menuStep.Move Now", True },
2791 { "menuStep.Truncate Game", True },
2795 Enables machineThinkingEnables[] = {
2796 { "menuFile.Load Game", False },
2797 { "menuFile.Load Next Game", False },
2798 { "menuFile.Load Previous Game", False },
2799 { "menuFile.Reload Same Game", False },
2800 { "menuFile.Paste Game", False },
2801 { "menuFile.Load Position", False },
2802 { "menuFile.Load Next Position", False },
2803 { "menuFile.Load Previous Position", False },
2804 { "menuFile.Reload Same Position", False },
2805 { "menuFile.Paste Position", False },
2806 { "menuMode.Machine White", False },
2807 { "menuMode.Machine Black", False },
2808 { "menuMode.Two Machines", False },
2809 { "menuStep.Retract Move", False },
2813 Enables userThinkingEnables[] = {
2814 { "menuFile.Load Game", True },
2815 { "menuFile.Load Next Game", True },
2816 { "menuFile.Load Previous Game", True },
2817 { "menuFile.Reload Same Game", True },
2818 { "menuFile.Paste Game", True },
2819 { "menuFile.Load Position", True },
2820 { "menuFile.Load Next Position", True },
2821 { "menuFile.Load Previous Position", True },
2822 { "menuFile.Reload Same Position", True },
2823 { "menuFile.Paste Position", True },
2824 { "menuMode.Machine White", True },
2825 { "menuMode.Machine Black", True },
2826 { "menuMode.Two Machines", True },
2827 { "menuStep.Retract Move", True },
2833 SetMenuEnables(icsEnables);
2836 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2837 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2844 SetMenuEnables(ncpEnables);
2850 SetMenuEnables(gnuEnables);
2856 SetMenuEnables(cmailEnables);
2862 SetMenuEnables(trainingOnEnables);
2863 if (appData.showButtonBar) {
2864 XtSetSensitive(buttonBarWidget, False);
2870 SetTrainingModeOff()
2872 SetMenuEnables(trainingOffEnables);
2873 if (appData.showButtonBar) {
2874 XtSetSensitive(buttonBarWidget, True);
2879 SetUserThinkingEnables()
2881 if (appData.noChessProgram) return;
2882 SetMenuEnables(userThinkingEnables);
2886 SetMachineThinkingEnables()
2888 if (appData.noChessProgram) return;
2889 SetMenuEnables(machineThinkingEnables);
2891 case MachinePlaysBlack:
2892 case MachinePlaysWhite:
2893 case TwoMachinesPlay:
2894 XtSetSensitive(XtNameToWidget(menuBarWidget,
2895 ModeToWidgetName(gameMode)), True);
2902 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2903 #define HISTORY_SIZE 64
\r
2904 static char *history[HISTORY_SIZE];
\r
2905 int histIn = 0, histP = 0;
\r
2908 SaveInHistory(char *cmd)
\r
2910 if (history[histIn] != NULL) {
\r
2911 free(history[histIn]);
\r
2912 history[histIn] = NULL;
\r
2914 if (*cmd == NULLCHAR) return;
\r
2915 history[histIn] = StrSave(cmd);
\r
2916 histIn = (histIn + 1) % HISTORY_SIZE;
\r
2917 if (history[histIn] != NULL) {
\r
2918 free(history[histIn]);
\r
2919 history[histIn] = NULL;
\r
2925 PrevInHistory(char *cmd)
\r
2928 if (histP == histIn) {
\r
2929 if (history[histIn] != NULL) free(history[histIn]);
\r
2930 history[histIn] = StrSave(cmd);
\r
2932 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
2933 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
2935 return history[histP];
\r
2941 if (histP == histIn) return NULL;
\r
2942 histP = (histP + 1) % HISTORY_SIZE;
\r
2943 return history[histP];
\r
2945 // end of borrowed code
\r
2947 #define Abs(n) ((n)<0 ? -(n) : (n))
2950 * Find a font that matches "pattern" that is as close as
2951 * possible to the targetPxlSize. Prefer fonts that are k
2952 * pixels smaller to fonts that are k pixels larger. The
2953 * pattern must be in the X Consortium standard format,
2954 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2955 * The return value should be freed with XtFree when no
2958 char *FindFont(pattern, targetPxlSize)
2962 char **fonts, *p, *best, *scalable, *scalableTail;
2963 int i, j, nfonts, minerr, err, pxlSize;
2966 char **missing_list;
2968 char *def_string, *base_fnt_lst, strInt[3];
2970 XFontStruct **fnt_list;
2972 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2973 sprintf(strInt, "%d", targetPxlSize);
2974 p = strstr(pattern, "--");
2975 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2976 strcat(base_fnt_lst, strInt);
2977 strcat(base_fnt_lst, strchr(p + 2, '-'));
2979 if ((fntSet = XCreateFontSet(xDisplay,
2983 &def_string)) == NULL) {
2985 fprintf(stderr, _("Unable to create font set.\n"));
2989 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2991 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2993 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2994 programName, pattern);
3002 for (i=0; i<nfonts; i++) {
3005 if (*p != '-') continue;
3007 if (*p == NULLCHAR) break;
3008 if (*p++ == '-') j++;
3010 if (j < 7) continue;
3013 scalable = fonts[i];
3016 err = pxlSize - targetPxlSize;
3017 if (Abs(err) < Abs(minerr) ||
3018 (minerr > 0 && err < 0 && -err == minerr)) {
3024 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3025 /* If the error is too big and there is a scalable font,
3026 use the scalable font. */
3027 int headlen = scalableTail - scalable;
3028 p = (char *) XtMalloc(strlen(scalable) + 10);
3029 while (isdigit(*scalableTail)) scalableTail++;
3030 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3032 p = (char *) XtMalloc(strlen(best) + 1);
3035 if (appData.debugMode) {
3036 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3037 pattern, targetPxlSize, p);
3040 if (missing_count > 0)
3041 XFreeStringList(missing_list);
3042 XFreeFontSet(xDisplay, fntSet);
3044 XFreeFontNames(fonts);
3051 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3052 | GCBackground | GCFunction | GCPlaneMask;
3053 XGCValues gc_values;
3056 gc_values.plane_mask = AllPlanes;
3057 gc_values.line_width = lineGap;
3058 gc_values.line_style = LineSolid;
3059 gc_values.function = GXcopy;
3061 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3062 gc_values.background = XBlackPixel(xDisplay, xScreen);
3063 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3065 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3066 gc_values.background = XWhitePixel(xDisplay, xScreen);
3067 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3068 XSetFont(xDisplay, coordGC, coordFontID);
3070 // [HGM] make font for holdings counts (white on black0
3071 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3072 gc_values.background = XBlackPixel(xDisplay, xScreen);
3073 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3074 XSetFont(xDisplay, countGC, countFontID);
3076 if (appData.monoMode) {
3077 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3078 gc_values.background = XWhitePixel(xDisplay, xScreen);
3079 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3081 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3082 gc_values.background = XBlackPixel(xDisplay, xScreen);
3083 lightSquareGC = wbPieceGC
3084 = XtGetGC(shellWidget, value_mask, &gc_values);
3086 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3087 gc_values.background = XWhitePixel(xDisplay, xScreen);
3088 darkSquareGC = bwPieceGC
3089 = XtGetGC(shellWidget, value_mask, &gc_values);
3091 if (DefaultDepth(xDisplay, xScreen) == 1) {
3092 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3093 gc_values.function = GXcopyInverted;
3094 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3095 gc_values.function = GXcopy;
3096 if (XBlackPixel(xDisplay, xScreen) == 1) {
3097 bwPieceGC = darkSquareGC;
3098 wbPieceGC = copyInvertedGC;
3100 bwPieceGC = copyInvertedGC;
3101 wbPieceGC = lightSquareGC;
3105 gc_values.foreground = highlightSquareColor;
3106 gc_values.background = highlightSquareColor;
3107 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3109 gc_values.foreground = premoveHighlightColor;
3110 gc_values.background = premoveHighlightColor;
3111 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3113 gc_values.foreground = lightSquareColor;
3114 gc_values.background = darkSquareColor;
3115 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3117 gc_values.foreground = darkSquareColor;
3118 gc_values.background = lightSquareColor;
3119 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3121 gc_values.foreground = jailSquareColor;
3122 gc_values.background = jailSquareColor;
3123 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3125 gc_values.foreground = whitePieceColor;
3126 gc_values.background = darkSquareColor;
3127 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3129 gc_values.foreground = whitePieceColor;
3130 gc_values.background = lightSquareColor;
3131 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3133 gc_values.foreground = whitePieceColor;
3134 gc_values.background = jailSquareColor;
3135 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3137 gc_values.foreground = blackPieceColor;
3138 gc_values.background = darkSquareColor;
3139 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3141 gc_values.foreground = blackPieceColor;
3142 gc_values.background = lightSquareColor;
3143 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3145 gc_values.foreground = blackPieceColor;
3146 gc_values.background = jailSquareColor;
3147 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3151 void loadXIM(xim, xmask, filename, dest, mask)
3164 fp = fopen(filename, "rb");
3166 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3173 for (y=0; y<h; ++y) {
3174 for (x=0; x<h; ++x) {
3179 XPutPixel(xim, x, y, blackPieceColor);
3181 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3184 XPutPixel(xim, x, y, darkSquareColor);
3186 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3189 XPutPixel(xim, x, y, whitePieceColor);
3191 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3194 XPutPixel(xim, x, y, lightSquareColor);
3196 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3202 /* create Pixmap of piece */
3203 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3205 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3208 /* create Pixmap of clipmask
3209 Note: We assume the white/black pieces have the same
3210 outline, so we make only 6 masks. This is okay
3211 since the XPM clipmask routines do the same. */
3213 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3215 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3218 /* now create the 1-bit version */
3219 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3222 values.foreground = 1;
3223 values.background = 0;
3225 /* Don't use XtGetGC, not read only */
3226 maskGC = XCreateGC(xDisplay, *mask,
3227 GCForeground | GCBackground, &values);
3228 XCopyPlane(xDisplay, temp, *mask, maskGC,
3229 0, 0, squareSize, squareSize, 0, 0, 1);
3230 XFreePixmap(xDisplay, temp);
3235 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3237 void CreateXIMPieces()
3242 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3247 /* The XSynchronize calls were copied from CreatePieces.
3248 Not sure if needed, but can't hurt */
3249 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3252 /* temp needed by loadXIM() */
3253 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3254 0, 0, ss, ss, AllPlanes, XYPixmap);
3256 if (strlen(appData.pixmapDirectory) == 0) {
3260 if (appData.monoMode) {
3261 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3265 fprintf(stderr, _("\nLoading XIMs...\n"));
3267 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3268 fprintf(stderr, "%d", piece+1);
3269 for (kind=0; kind<4; kind++) {
3270 fprintf(stderr, ".");
3271 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3272 ExpandPathName(appData.pixmapDirectory),
3273 piece <= (int) WhiteKing ? "" : "w",
3274 pieceBitmapNames[piece],
3276 ximPieceBitmap[kind][piece] =
3277 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3278 0, 0, ss, ss, AllPlanes, XYPixmap);
3279 if (appData.debugMode)
3280 fprintf(stderr, _("(File:%s:) "), buf);
3281 loadXIM(ximPieceBitmap[kind][piece],
3283 &(xpmPieceBitmap2[kind][piece]),
3284 &(ximMaskPm2[piece]));
3285 if(piece <= (int)WhiteKing)
3286 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3288 fprintf(stderr," ");
3290 /* Load light and dark squares */
3291 /* If the LSQ and DSQ pieces don't exist, we will
3292 draw them with solid squares. */
3293 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3294 if (access(buf, 0) != 0) {
3298 fprintf(stderr, _("light square "));
3300 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3301 0, 0, ss, ss, AllPlanes, XYPixmap);
3302 if (appData.debugMode)
3303 fprintf(stderr, _("(File:%s:) "), buf);
3305 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3306 fprintf(stderr, _("dark square "));
3307 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3308 ExpandPathName(appData.pixmapDirectory), ss);
3309 if (appData.debugMode)
3310 fprintf(stderr, _("(File:%s:) "), buf);
3312 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3313 0, 0, ss, ss, AllPlanes, XYPixmap);
3314 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3315 xpmJailSquare = xpmLightSquare;
3317 fprintf(stderr, _("Done.\n"));
3319 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3323 void CreateXPMPieces()
3327 u_int ss = squareSize;
3329 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3330 XpmColorSymbol symbols[4];
3332 /* The XSynchronize calls were copied from CreatePieces.
3333 Not sure if needed, but can't hurt */
3334 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3336 /* Setup translations so piece colors match square colors */
3337 symbols[0].name = "light_piece";
3338 symbols[0].value = appData.whitePieceColor;
3339 symbols[1].name = "dark_piece";
3340 symbols[1].value = appData.blackPieceColor;
3341 symbols[2].name = "light_square";
3342 symbols[2].value = appData.lightSquareColor;
3343 symbols[3].name = "dark_square";
3344 symbols[3].value = appData.darkSquareColor;
3346 attr.valuemask = XpmColorSymbols;
3347 attr.colorsymbols = symbols;
3348 attr.numsymbols = 4;
3350 if (appData.monoMode) {
3351 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3355 if (strlen(appData.pixmapDirectory) == 0) {
3356 XpmPieces* pieces = builtInXpms;
3359 while (pieces->size != squareSize && pieces->size) pieces++;
3360 if (!pieces->size) {
3361 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3364 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3365 for (kind=0; kind<4; kind++) {
3367 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3368 pieces->xpm[piece][kind],
3369 &(xpmPieceBitmap2[kind][piece]),
3370 NULL, &attr)) != 0) {
3371 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3375 if(piece <= (int) WhiteKing)
3376 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3380 xpmJailSquare = xpmLightSquare;
3384 fprintf(stderr, _("\nLoading XPMs...\n"));
3387 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3388 fprintf(stderr, "%d ", piece+1);
3389 for (kind=0; kind<4; kind++) {
3390 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3391 ExpandPathName(appData.pixmapDirectory),
3392 piece > (int) WhiteKing ? "w" : "",
3393 pieceBitmapNames[piece],
3395 if (appData.debugMode) {
3396 fprintf(stderr, _("(File:%s:) "), buf);
3398 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3399 &(xpmPieceBitmap2[kind][piece]),
3400 NULL, &attr)) != 0) {
3401 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3402 // [HGM] missing: read of unorthodox piece failed; substitute King.
3403 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3404 ExpandPathName(appData.pixmapDirectory),
3406 if (appData.debugMode) {
3407 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3409 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3410 &(xpmPieceBitmap2[kind][piece]),
3414 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3419 if(piece <= (int) WhiteKing)
3420 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3423 /* Load light and dark squares */
3424 /* If the LSQ and DSQ pieces don't exist, we will
3425 draw them with solid squares. */
3426 fprintf(stderr, _("light square "));
3427 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3428 if (access(buf, 0) != 0) {
3432 if (appData.debugMode)
3433 fprintf(stderr, _("(File:%s:) "), buf);
3435 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3436 &xpmLightSquare, NULL, &attr)) != 0) {
3437 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3440 fprintf(stderr, _("dark square "));
3441 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3442 ExpandPathName(appData.pixmapDirectory), ss);
3443 if (appData.debugMode) {
3444 fprintf(stderr, _("(File:%s:) "), buf);
3446 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3447 &xpmDarkSquare, NULL, &attr)) != 0) {
3448 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3452 xpmJailSquare = xpmLightSquare;
3453 fprintf(stderr, _("Done.\n"));
3455 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3458 #endif /* HAVE_LIBXPM */
3461 /* No built-in bitmaps */
3466 u_int ss = squareSize;
3468 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3471 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3472 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3473 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3474 pieceBitmapNames[piece],
3475 ss, kind == SOLID ? 's' : 'o');
3476 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3477 if(piece <= (int)WhiteKing)
3478 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3482 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3486 /* With built-in bitmaps */
3489 BuiltInBits* bib = builtInBits;
3492 u_int ss = squareSize;
3494 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3497 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3499 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3500 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3501 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3502 pieceBitmapNames[piece],
3503 ss, kind == SOLID ? 's' : 'o');
3504 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3505 bib->bits[kind][piece], ss, ss);
3506 if(piece <= (int)WhiteKing)
3507 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3511 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3516 void ReadBitmap(pm, name, bits, wreq, hreq)
3519 unsigned char bits[];
3525 char msg[MSG_SIZ], fullname[MSG_SIZ];
3527 if (*appData.bitmapDirectory != NULLCHAR) {
3528 strcpy(fullname, appData.bitmapDirectory);
3529 strcat(fullname, "/");
3530 strcat(fullname, name);
3531 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3532 &w, &h, pm, &x_hot, &y_hot);
3533 fprintf(stderr, "load %s\n", name);
3534 if (errcode != BitmapSuccess) {
3536 case BitmapOpenFailed:
3537 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3539 case BitmapFileInvalid:
3540 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3542 case BitmapNoMemory:
3543 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3547 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3551 fprintf(stderr, _("%s: %s...using built-in\n"),
3553 } else if (w != wreq || h != hreq) {
3555 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3556 programName, fullname, w, h, wreq, hreq);
3562 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3571 if (lineGap == 0) return;
3573 /* [HR] Split this into 2 loops for non-square boards. */
3575 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3576 gridSegments[i].x1 = 0;
3577 gridSegments[i].x2 =
3578 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3579 gridSegments[i].y1 = gridSegments[i].y2
3580 = lineGap / 2 + (i * (squareSize + lineGap));
3583 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3584 gridSegments[j + i].y1 = 0;
3585 gridSegments[j + i].y2 =
3586 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3587 gridSegments[j + i].x1 = gridSegments[j + i].x2
3588 = lineGap / 2 + (j * (squareSize + lineGap));
3592 static void MenuBarSelect(w, addr, index)
3597 XtActionProc proc = (XtActionProc) addr;
3599 (proc)(NULL, NULL, NULL, NULL);
3602 void CreateMenuBarPopup(parent, name, mb)
3612 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3615 XtSetArg(args[j], XtNleftMargin, 20); j++;
3616 XtSetArg(args[j], XtNrightMargin, 20); j++;
3618 while (mi->string != NULL) {
3619 if (strcmp(mi->string, "----") == 0) {
3620 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3623 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3624 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3626 XtAddCallback(entry, XtNcallback,
3627 (XtCallbackProc) MenuBarSelect,
3628 (caddr_t) mi->proc);
3634 Widget CreateMenuBar(mb)
3638 Widget anchor, menuBar;
3640 char menuName[MSG_SIZ];
3643 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3644 XtSetArg(args[j], XtNvSpace, 0); j++;
3645 XtSetArg(args[j], XtNborderWidth, 0); j++;
3646 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3647 formWidget, args, j);
3649 while (mb->name != NULL) {
3650 strcpy(menuName, "menu");
3651 strcat(menuName, mb->name);
3653 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3656 shortName[0] = _(mb->name)[0];
3657 shortName[1] = NULLCHAR;
3658 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3661 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3664 XtSetArg(args[j], XtNborderWidth, 0); j++;
3665 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3667 CreateMenuBarPopup(menuBar, menuName, mb);
3673 Widget CreateButtonBar(mi)
3677 Widget button, buttonBar;
3681 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3683 XtSetArg(args[j], XtNhSpace, 0); j++;
3685 XtSetArg(args[j], XtNborderWidth, 0); j++;
3686 XtSetArg(args[j], XtNvSpace, 0); j++;
3687 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3688 formWidget, args, j);
3690 while (mi->string != NULL) {
3693 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3694 XtSetArg(args[j], XtNborderWidth, 0); j++;
3696 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3697 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3698 buttonBar, args, j);
3699 XtAddCallback(button, XtNcallback,
3700 (XtCallbackProc) MenuBarSelect,
3701 (caddr_t) mi->proc);
3708 CreatePieceMenu(name, color)
3715 ChessSquare selection;
3717 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3718 boardWidget, args, 0);
3720 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3721 String item = pieceMenuStrings[color][i];
3723 if (strcmp(item, "----") == 0) {
3724 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3727 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3728 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3730 selection = pieceMenuTranslation[color][i];
3731 XtAddCallback(entry, XtNcallback,
3732 (XtCallbackProc) PieceMenuSelect,
3733 (caddr_t) selection);
3734 if (selection == WhitePawn || selection == BlackPawn) {
3735 XtSetArg(args[0], XtNpopupOnEntry, entry);
3736 XtSetValues(menu, args, 1);
3749 ChessSquare selection;
3751 whitePieceMenu = CreatePieceMenu("menuW", 0);
3752 blackPieceMenu = CreatePieceMenu("menuB", 1);
3754 XtRegisterGrabAction(PieceMenuPopup, True,
3755 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3756 GrabModeAsync, GrabModeAsync);
3758 XtSetArg(args[0], XtNlabel, _("Drop"));
3759 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3760 boardWidget, args, 1);
3761 for (i = 0; i < DROP_MENU_SIZE; i++) {
3762 String item = dropMenuStrings[i];
3764 if (strcmp(item, "----") == 0) {
3765 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3768 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3769 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3771 selection = dropMenuTranslation[i];
3772 XtAddCallback(entry, XtNcallback,
3773 (XtCallbackProc) DropMenuSelect,
3774 (caddr_t) selection);
3779 void SetupDropMenu()
3787 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3788 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3789 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3790 dmEnables[i].piece);
3791 XtSetSensitive(entry, p != NULL || !appData.testLegality
3792 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3793 && !appData.icsActive));
3795 while (p && *p++ == dmEnables[i].piece) count++;
3796 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3798 XtSetArg(args[j], XtNlabel, label); j++;
3799 XtSetValues(entry, args, j);
3803 void PieceMenuPopup(w, event, params, num_params)
3807 Cardinal *num_params;
3809 String whichMenu; int menuNr;
3810 if (event->type == ButtonRelease)
3811 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3812 else if (event->type == ButtonPress)
3813 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3815 case 0: whichMenu = params[0]; break;
3816 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3818 case -1: if (errorUp) ErrorPopDown();
3821 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3824 static void PieceMenuSelect(w, piece, junk)
3829 if (pmFromX < 0 || pmFromY < 0) return;
3830 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3833 static void DropMenuSelect(w, piece, junk)
3838 if (pmFromX < 0 || pmFromY < 0) return;
3839 DropMenuEvent(piece, pmFromX, pmFromY);
3842 void WhiteClock(w, event, prms, nprms)
3848 if (gameMode == EditPosition || gameMode == IcsExamining) {
3849 SetWhiteToPlayEvent();
3850 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3855 void BlackClock(w, event, prms, nprms)
3861 if (gameMode == EditPosition || gameMode == IcsExamining) {
3862 SetBlackToPlayEvent();
3863 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3870 * If the user selects on a border boundary, return -1; if off the board,
3871 * return -2. Otherwise map the event coordinate to the square.
3873 int EventToSquare(x, limit)
3881 if ((x % (squareSize + lineGap)) >= squareSize)
3883 x /= (squareSize + lineGap);
3889 static void do_flash_delay(msec)
3895 static void drawHighlight(file, rank, gc)
3901 if (lineGap == 0 || appData.blindfold) return;
3904 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3905 (squareSize + lineGap);
3906 y = lineGap/2 + rank * (squareSize + lineGap);
3908 x = lineGap/2 + file * (squareSize + lineGap);
3909 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3910 (squareSize + lineGap);
3913 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3914 squareSize+lineGap, squareSize+lineGap);
3917 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3918 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3921 SetHighlights(fromX, fromY, toX, toY)
3922 int fromX, fromY, toX, toY;
3924 if (hi1X != fromX || hi1Y != fromY) {
3925 if (hi1X >= 0 && hi1Y >= 0) {
3926 drawHighlight(hi1X, hi1Y, lineGC);
3928 } // [HGM] first erase both, then draw new!
3929 if (hi2X != toX || hi2Y != toY) {
3930 if (hi2X >= 0 && hi2Y >= 0) {
3931 drawHighlight(hi2X, hi2Y, lineGC);
3934 if (hi1X != fromX || hi1Y != fromY) {
3935 if (fromX >= 0 && fromY >= 0) {
3936 drawHighlight(fromX, fromY, highlineGC);
3939 if (hi2X != toX || hi2Y != toY) {
3940 if (toX >= 0 && toY >= 0) {
3941 drawHighlight(toX, toY, highlineGC);
3953 SetHighlights(-1, -1, -1, -1);
3958 SetPremoveHighlights(fromX, fromY, toX, toY)
3959 int fromX, fromY, toX, toY;
3961 if (pm1X != fromX || pm1Y != fromY) {
3962 if (pm1X >= 0 && pm1Y >= 0) {
3963 drawHighlight(pm1X, pm1Y, lineGC);
3965 if (fromX >= 0 && fromY >= 0) {
3966 drawHighlight(fromX, fromY, prelineGC);
3969 if (pm2X != toX || pm2Y != toY) {
3970 if (pm2X >= 0 && pm2Y >= 0) {
3971 drawHighlight(pm2X, pm2Y, lineGC);
3973 if (toX >= 0 && toY >= 0) {
3974 drawHighlight(toX, toY, prelineGC);
3984 ClearPremoveHighlights()
3986 SetPremoveHighlights(-1, -1, -1, -1);
3989 static void BlankSquare(x, y, color, piece, dest)
3994 if (useImages && useImageSqs) {
3998 pm = xpmLightSquare;
4003 case 2: /* neutral */
4008 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4009 squareSize, squareSize, x, y);
4019 case 2: /* neutral */
4024 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
4029 I split out the routines to draw a piece so that I could
4030 make a generic flash routine.
4032 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4034 int square_color, x, y;
4037 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4038 switch (square_color) {
4040 case 2: /* neutral */
4042 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4043 ? *pieceToOutline(piece)
4044 : *pieceToSolid(piece),
4045 dest, bwPieceGC, 0, 0,
4046 squareSize, squareSize, x, y);
4049 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4050 ? *pieceToSolid(piece)
4051 : *pieceToOutline(piece),
4052 dest, wbPieceGC, 0, 0,
4053 squareSize, squareSize, x, y);
4058 static void monoDrawPiece(piece, square_color, x, y, dest)
4060 int square_color, x, y;
4063 switch (square_color) {
4065 case 2: /* neutral */
4067 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4068 ? *pieceToOutline(piece)
4069 : *pieceToSolid(piece),
4070 dest, bwPieceGC, 0, 0,
4071 squareSize, squareSize, x, y, 1);
4074 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4075 ? *pieceToSolid(piece)
4076 : *pieceToOutline(piece),
4077 dest, wbPieceGC, 0, 0,
4078 squareSize, squareSize, x, y, 1);
4083 static void colorDrawPiece(piece, square_color, x, y, dest)
4085 int square_color, x, y;
4088 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4089 switch (square_color) {
4091 XCopyPlane(xDisplay, *pieceToSolid(piece),
4092 dest, (int) piece < (int) BlackPawn
4093 ? wlPieceGC : blPieceGC, 0, 0,
4094 squareSize, squareSize, x, y, 1);
4097 XCopyPlane(xDisplay, *pieceToSolid(piece),
4098 dest, (int) piece < (int) BlackPawn
4099 ? wdPieceGC : bdPieceGC, 0, 0,
4100 squareSize, squareSize, x, y, 1);
4102 case 2: /* neutral */
4104 XCopyPlane(xDisplay, *pieceToSolid(piece),
4105 dest, (int) piece < (int) BlackPawn
4106 ? wjPieceGC : bjPieceGC, 0, 0,
4107 squareSize, squareSize, x, y, 1);
4112 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4114 int square_color, x, y;
4119 switch (square_color) {
4121 case 2: /* neutral */
4123 if ((int)piece < (int) BlackPawn) {
4131 if ((int)piece < (int) BlackPawn) {
4139 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4140 dest, wlPieceGC, 0, 0,
4141 squareSize, squareSize, x, y);
4144 typedef void (*DrawFunc)();
4146 DrawFunc ChooseDrawFunc()
4148 if (appData.monoMode) {
4149 if (DefaultDepth(xDisplay, xScreen) == 1) {
4150 return monoDrawPiece_1bit;
4152 return monoDrawPiece;
4156 return colorDrawPieceImage;
4158 return colorDrawPiece;
4162 /* [HR] determine square color depending on chess variant. */
4163 static int SquareColor(row, column)
4168 if (gameInfo.variant == VariantXiangqi) {
4169 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4171 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4173 } else if (row <= 4) {
4179 square_color = ((column + row) % 2) == 1;
4182 /* [hgm] holdings: next line makes all holdings squares light */
4183 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4185 return square_color;
4188 void DrawSquare(row, column, piece, do_flash)
4189 int row, column, do_flash;
4192 int square_color, x, y, direction, font_ascent, font_descent;
4195 XCharStruct overall;
4199 /* Calculate delay in milliseconds (2-delays per complete flash) */
4200 flash_delay = 500 / appData.flashRate;
4203 x = lineGap + ((BOARD_WIDTH-1)-column) *
4204 (squareSize + lineGap);
4205 y = lineGap + row * (squareSize + lineGap);
4207 x = lineGap + column * (squareSize + lineGap);
4208 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4209 (squareSize + lineGap);
4212 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4214 square_color = SquareColor(row, column);
4216 if ( // [HGM] holdings: blank out area between board and holdings
4217 column == BOARD_LEFT-1 || column == BOARD_RGHT
4218 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4219 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4220 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4222 // [HGM] print piece counts next to holdings
4223 string[1] = NULLCHAR;
4224 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4225 string[0] = '0' + piece;
4226 XTextExtents(countFontStruct, string, 1, &direction,
4227 &font_ascent, &font_descent, &overall);
4228 if (appData.monoMode) {
4229 XDrawImageString(xDisplay, xBoardWindow, countGC,
4230 x + squareSize - overall.width - 2,
4231 y + font_ascent + 1, string, 1);
4233 XDrawString(xDisplay, xBoardWindow, countGC,
4234 x + squareSize - overall.width - 2,
4235 y + font_ascent + 1, string, 1);
4238 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4239 string[0] = '0' + piece;
4240 XTextExtents(countFontStruct, string, 1, &direction,
4241 &font_ascent, &font_descent, &overall);
4242 if (appData.monoMode) {
4243 XDrawImageString(xDisplay, xBoardWindow, countGC,
4244 x + 2, y + font_ascent + 1, string, 1);
4246 XDrawString(xDisplay, xBoardWindow, countGC,
4247 x + 2, y + font_ascent + 1, string, 1);
4251 if (piece == EmptySquare || appData.blindfold) {
4252 BlankSquare(x, y, square_color, piece, xBoardWindow);