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 WhiteClock P((Widget w, XEvent *event,
266 String *prms, Cardinal *nprms));
267 void BlackClock P((Widget w, XEvent *event,
268 String *prms, Cardinal *nprms));
269 void DrawPositionProc P((Widget w, XEvent *event,
270 String *prms, Cardinal *nprms));
271 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
273 void CommentPopUp P((char *title, char *label));
274 void CommentPopDown P((void));
275 void CommentCallback P((Widget w, XtPointer client_data,
276 XtPointer call_data));
277 void ICSInputBoxPopUp P((void));
278 void ICSInputBoxPopDown P((void));
279 void FileNamePopUp P((char *label, char *def,
280 FileProc proc, char *openMode));
281 void FileNamePopDown P((void));
282 void FileNameCallback P((Widget w, XtPointer client_data,
283 XtPointer call_data));
284 void FileNameAction P((Widget w, XEvent *event,
285 String *prms, Cardinal *nprms));
286 void AskQuestionReplyAction P((Widget w, XEvent *event,
287 String *prms, Cardinal *nprms));
288 void AskQuestionProc P((Widget w, XEvent *event,
289 String *prms, Cardinal *nprms));
290 void AskQuestionPopDown P((void));
291 void PromotionPopDown P((void));
292 void PromotionCallback P((Widget w, XtPointer client_data,
293 XtPointer call_data));
294 void EditCommentPopDown P((void));
295 void EditCommentCallback P((Widget w, XtPointer client_data,
296 XtPointer call_data));
297 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
298 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
299 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
300 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
302 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
304 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
306 void LoadPositionProc P((Widget w, XEvent *event,
307 String *prms, Cardinal *nprms));
308 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
310 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
312 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
314 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
316 void PastePositionProc P((Widget w, XEvent *event, String *prms,
318 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
319 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
320 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
321 void SavePositionProc P((Widget w, XEvent *event,
322 String *prms, Cardinal *nprms));
323 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
324 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
326 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
327 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
328 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
330 void MachineWhiteProc P((Widget w, XEvent *event,
331 String *prms, Cardinal *nprms));
332 void AnalyzeModeProc P((Widget w, XEvent *event,
333 String *prms, Cardinal *nprms));
334 void AnalyzeFileProc P((Widget w, XEvent *event,
335 String *prms, Cardinal *nprms));
336 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
338 void IcsClientProc P((Widget w, XEvent *event, String *prms,
340 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
341 void EditPositionProc P((Widget w, XEvent *event,
342 String *prms, Cardinal *nprms));
343 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
344 void EditCommentProc P((Widget w, XEvent *event,
345 String *prms, Cardinal *nprms));
346 void IcsInputBoxProc P((Widget w, XEvent *event,
347 String *prms, Cardinal *nprms));
348 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
349 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
350 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
351 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
352 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
353 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
354 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
355 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
356 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
357 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
358 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void StopObservingProc P((Widget w, XEvent *event, String *prms,
364 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
366 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
370 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
371 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
373 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
375 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
376 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
378 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
380 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
382 void AutocommProc P((Widget w, XEvent *event, String *prms,
384 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
385 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
386 void AutobsProc P((Widget w, XEvent *event, String *prms,
388 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
389 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
390 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
391 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
393 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
394 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
396 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
398 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
400 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
401 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
402 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
404 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
406 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
408 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
410 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
412 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
413 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
414 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
416 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
418 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
420 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
422 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
423 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
424 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
425 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
426 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
427 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
428 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
429 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
430 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
431 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
432 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
433 void DisplayMove P((int moveNumber));
434 void DisplayTitle P((char *title));
435 void ICSInitScript P((void));
436 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
437 void ErrorPopUp P((char *title, char *text, int modal));
438 void ErrorPopDown P((void));
439 static char *ExpandPathName P((char *path));
440 static void CreateAnimVars P((void));
441 static void DragPieceMove P((int x, int y));
442 static void DrawDragPiece P((void));
443 char *ModeToWidgetName P((GameMode mode));
444 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
445 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
446 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
447 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
448 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
449 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
450 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
451 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
452 void GameListOptionsPopDown P(());
453 void ShufflePopDown P(());
454 void EnginePopDown P(());
455 void UciPopDown P(());
456 void TimeControlPopDown P(());
457 void NewVariantPopDown P(());
458 void SettingsPopDown P(());
459 void update_ics_width P(());
460 int get_term_width P(());
461 int CopyMemoProc P(());
463 * XBoard depends on Xt R4 or higher
465 int xtVersion = XtSpecificationRelease;
470 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
471 jailSquareColor, highlightSquareColor, premoveHighlightColor;
472 Pixel lowTimeWarningColor;
473 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
474 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
475 wjPieceGC, bjPieceGC, prelineGC, countGC;
476 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
477 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
478 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
479 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
480 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
481 ICSInputShell, fileNameShell, askQuestionShell;
482 Widget historyShell, evalGraphShell, gameListShell;
483 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
484 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
485 Font clockFontID, coordFontID, countFontID;
486 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
487 XtAppContext appContext;
489 char *oldICSInteractionTitle;
493 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
495 Position commentX = -1, commentY = -1;
496 Dimension commentW, commentH;
497 typedef unsigned int BoardSize;
499 Boolean chessProgram;
501 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
502 int squareSize, smallLayout = 0, tinyLayout = 0,
503 marginW, marginH, // [HGM] for run-time resizing
504 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
505 ICSInputBoxUp = False, askQuestionUp = False,
506 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
507 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
508 Pixel timerForegroundPixel, timerBackgroundPixel;
509 Pixel buttonForegroundPixel, buttonBackgroundPixel;
510 char *chessDir, *programName, *programVersion,
511 *gameCopyFilename, *gamePasteFilename;
512 Boolean alwaysOnTop = False;
513 Boolean saveSettingsOnExit;
514 char *settingsFileName;
515 char *icsTextMenuString;
517 char *firstChessProgramNames;
518 char *secondChessProgramNames;
520 WindowPlacement wpMain;
521 WindowPlacement wpConsole;
522 WindowPlacement wpComment;
523 WindowPlacement wpMoveHistory;
524 WindowPlacement wpEvalGraph;
525 WindowPlacement wpEngineOutput;
526 WindowPlacement wpGameList;
527 WindowPlacement wpTags;
531 Pixmap pieceBitmap[2][(int)BlackPawn];
532 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
533 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
534 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
535 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
536 int useImages, useImageSqs;
537 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
538 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
539 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
540 XImage *ximLightSquare, *ximDarkSquare;
543 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
544 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
546 #define White(piece) ((int)(piece) < (int)BlackPawn)
548 /* Variables for doing smooth animation. This whole thing
549 would be much easier if the board was double-buffered,
550 but that would require a fairly major rewrite. */
555 GC blitGC, pieceGC, outlineGC;
556 XPoint startSquare, prevFrame, mouseDelta;
560 int startBoardX, startBoardY;
563 /* There can be two pieces being animated at once: a player
564 can begin dragging a piece before the remote opponent has moved. */
566 static AnimState game, player;
568 /* Bitmaps for use as masks when drawing XPM pieces.
569 Need one for each black and white piece. */
570 static Pixmap xpmMask[BlackKing + 1];
572 /* This magic number is the number of intermediate frames used
573 in each half of the animation. For short moves it's reduced
574 by 1. The total number of frames will be factor * 2 + 1. */
577 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
579 MenuItem fileMenu[] = {
580 {N_("New Game"), ResetProc},
581 {N_("New Shuffle Game ..."), ShuffleMenuProc},
582 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
583 {"----", NothingProc},
584 {N_("Load Game"), LoadGameProc},
585 {N_("Load Next Game"), LoadNextGameProc},
586 {N_("Load Previous Game"), LoadPrevGameProc},
587 {N_("Reload Same Game"), ReloadGameProc},
588 {N_("Save Game"), SaveGameProc},
589 {"----", NothingProc},
590 {N_("Copy Game"), CopyGameProc},
591 {N_("Paste Game"), PasteGameProc},
592 {"----", NothingProc},
593 {N_("Load Position"), LoadPositionProc},
594 {N_("Load Next Position"), LoadNextPositionProc},
595 {N_("Load Previous Position"), LoadPrevPositionProc},
596 {N_("Reload Same Position"), ReloadPositionProc},
597 {N_("Save Position"), SavePositionProc},
598 {"----", NothingProc},
599 {N_("Copy Position"), CopyPositionProc},
600 {N_("Paste Position"), PastePositionProc},
601 {"----", NothingProc},
602 {N_("Mail Move"), MailMoveProc},
603 {N_("Reload CMail Message"), ReloadCmailMsgProc},
604 {"----", NothingProc},
605 {N_("Exit"), QuitProc},
609 MenuItem modeMenu[] = {
610 {N_("Machine White"), MachineWhiteProc},
611 {N_("Machine Black"), MachineBlackProc},
612 {N_("Two Machines"), TwoMachinesProc},
613 {N_("Analysis Mode"), AnalyzeModeProc},
614 {N_("Analyze File"), AnalyzeFileProc },
615 {N_("ICS Client"), IcsClientProc},
616 {N_("Edit Game"), EditGameProc},
617 {N_("Edit Position"), EditPositionProc},
618 {N_("Training"), TrainingProc},
619 {"----", NothingProc},
620 {N_("Show Engine Output"), EngineOutputProc},
621 {N_("Show Evaluation Graph"), EvalGraphProc},
622 {N_("Show Game List"), ShowGameListProc},
623 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
624 {"----", NothingProc},
625 {N_("Edit Tags"), EditTagsProc},
626 {N_("Edit Comment"), EditCommentProc},
627 {N_("ICS Input Box"), IcsInputBoxProc},
628 {N_("Pause"), PauseProc},
632 MenuItem actionMenu[] = {
633 {N_("Accept"), AcceptProc},
634 {N_("Decline"), DeclineProc},
635 {N_("Rematch"), RematchProc},
636 {"----", NothingProc},
637 {N_("Call Flag"), CallFlagProc},
638 {N_("Draw"), DrawProc},
639 {N_("Adjourn"), AdjournProc},
640 {N_("Abort"), AbortProc},
641 {N_("Resign"), ResignProc},
642 {"----", NothingProc},
643 {N_("Stop Observing"), StopObservingProc},
644 {N_("Stop Examining"), StopExaminingProc},
645 {"----", NothingProc},
646 {N_("Adjudicate to White"), AdjuWhiteProc},
647 {N_("Adjudicate to Black"), AdjuBlackProc},
648 {N_("Adjudicate Draw"), AdjuDrawProc},
652 MenuItem stepMenu[] = {
653 {N_("Backward"), BackwardProc},
654 {N_("Forward"), ForwardProc},
655 {N_("Back to Start"), ToStartProc},
656 {N_("Forward to End"), ToEndProc},
657 {N_("Revert"), RevertProc},
658 {N_("Truncate Game"), TruncateGameProc},
659 {"----", NothingProc},
660 {N_("Move Now"), MoveNowProc},
661 {N_("Retract Move"), RetractMoveProc},
665 MenuItem optionsMenu[] = {
666 {N_("Flip View"), FlipViewProc},
667 {"----", NothingProc},
668 {N_("Adjudications ..."), EngineMenuProc},
669 {N_("General Settings ..."), UciMenuProc},
670 {N_("Engine #1 Settings ..."), FirstSettingsProc},
671 {N_("Engine #2 Settings ..."), SecondSettingsProc},
672 {N_("Time Control ..."), TimeControlProc},
673 {N_("Game List ..."), GameListOptionsPopUp},
674 {"----", NothingProc},
675 {N_("Always Queen"), AlwaysQueenProc},
676 {N_("Animate Dragging"), AnimateDraggingProc},
677 {N_("Animate Moving"), AnimateMovingProc},
678 {N_("Auto Comment"), AutocommProc},
679 {N_("Auto Flag"), AutoflagProc},
680 {N_("Auto Flip View"), AutoflipProc},
681 {N_("Auto Observe"), AutobsProc},
682 {N_("Auto Raise Board"), AutoraiseProc},
683 {N_("Auto Save"), AutosaveProc},
684 {N_("Blindfold"), BlindfoldProc},
685 {N_("Flash Moves"), FlashMovesProc},
686 {N_("Get Move List"), GetMoveListProc},
688 {N_("Highlight Dragging"), HighlightDraggingProc},
690 {N_("Highlight Last Move"), HighlightLastMoveProc},
691 {N_("Move Sound"), MoveSoundProc},
692 {N_("ICS Alarm"), IcsAlarmProc},
693 {N_("Old Save Style"), OldSaveStyleProc},
694 {N_("Periodic Updates"), PeriodicUpdatesProc},
695 {N_("Ponder Next Move"), PonderNextMoveProc},
696 {N_("Popup Exit Message"), PopupExitMessageProc},
697 {N_("Popup Move Errors"), PopupMoveErrorsProc},
698 {N_("Premove"), PremoveProc},
699 {N_("Quiet Play"), QuietPlayProc},
700 {N_("Show Coords"), ShowCoordsProc},
701 {N_("Hide Thinking"), HideThinkingProc},
702 {N_("Test Legality"), TestLegalityProc},
703 {"----", NothingProc},
704 {N_("Save Settings Now"), SaveSettingsProc},
705 {N_("Save Settings on Exit"), SaveOnExitProc},
709 MenuItem helpMenu[] = {
710 {N_("Info XBoard"), InfoProc},
711 {N_("Man XBoard"), ManProc},
712 {"----", NothingProc},
713 {N_("Hint"), HintProc},
714 {N_("Book"), BookProc},
715 {"----", NothingProc},
716 {N_("About XBoard"), AboutProc},
721 {N_("File"), fileMenu},
722 {N_("Mode"), modeMenu},
723 {N_("Action"), actionMenu},
724 {N_("Step"), stepMenu},
725 {N_("Options"), optionsMenu},
726 {N_("Help"), helpMenu},
730 #define PAUSE_BUTTON N_("P")
731 MenuItem buttonBar[] = {
734 {PAUSE_BUTTON, PauseProc},
740 #define PIECE_MENU_SIZE 18
741 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
742 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
743 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
744 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
745 N_("Empty square"), N_("Clear board") },
746 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
747 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
748 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
749 N_("Empty square"), N_("Clear board") }
751 /* must be in same order as PieceMenuStrings! */
752 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
753 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
754 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
755 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
756 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
757 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
758 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
759 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
760 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
763 #define DROP_MENU_SIZE 6
764 String dropMenuStrings[DROP_MENU_SIZE] = {
765 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
767 /* must be in same order as PieceMenuStrings! */
768 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
769 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
770 WhiteRook, WhiteQueen
778 DropMenuEnables dmEnables[] = {
796 { XtNborderWidth, 0 },
797 { XtNdefaultDistance, 0 },
801 { XtNborderWidth, 0 },
802 { XtNresizable, (XtArgVal) True },
806 { XtNborderWidth, 0 },
812 { XtNjustify, (XtArgVal) XtJustifyRight },
813 { XtNlabel, (XtArgVal) "..." },
814 { XtNresizable, (XtArgVal) True },
815 { XtNresize, (XtArgVal) False }
818 Arg messageArgs[] = {
819 { XtNjustify, (XtArgVal) XtJustifyLeft },
820 { XtNlabel, (XtArgVal) "..." },
821 { XtNresizable, (XtArgVal) True },
822 { XtNresize, (XtArgVal) False }
826 { XtNborderWidth, 0 },
827 { XtNjustify, (XtArgVal) XtJustifyLeft }
830 XtResource clientResources[] = {
831 { "flashCount", "flashCount", XtRInt, sizeof(int),
832 XtOffset(AppDataPtr, flashCount), XtRImmediate,
833 (XtPointer) FLASH_COUNT },
836 XrmOptionDescRec shellOptions[] = {
837 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
838 { "-flash", "flashCount", XrmoptionNoArg, "3" },
839 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
842 XtActionsRec boardActions[] = {
843 { "DrawPosition", DrawPositionProc },
844 { "HandleUserMove", HandleUserMove },
845 { "AnimateUserMove", AnimateUserMove },
846 { "HandlePV", HandlePV },
847 { "UnLoadPV", UnLoadPV },
848 { "FileNameAction", FileNameAction },
849 { "AskQuestionProc", AskQuestionProc },
850 { "AskQuestionReplyAction", AskQuestionReplyAction },
851 { "PieceMenuPopup", PieceMenuPopup },
852 { "WhiteClock", WhiteClock },
853 { "BlackClock", BlackClock },
854 { "Iconify", Iconify },
855 { "ResetProc", ResetProc },
856 { "LoadGameProc", LoadGameProc },
857 { "LoadNextGameProc", LoadNextGameProc },
858 { "LoadPrevGameProc", LoadPrevGameProc },
859 { "LoadSelectedProc", LoadSelectedProc },
860 { "SetFilterProc", SetFilterProc },
861 { "ReloadGameProc", ReloadGameProc },
862 { "LoadPositionProc", LoadPositionProc },
863 { "LoadNextPositionProc", LoadNextPositionProc },
864 { "LoadPrevPositionProc", LoadPrevPositionProc },
865 { "ReloadPositionProc", ReloadPositionProc },
866 { "CopyPositionProc", CopyPositionProc },
867 { "PastePositionProc", PastePositionProc },
868 { "CopyGameProc", CopyGameProc },
869 { "PasteGameProc", PasteGameProc },
870 { "SaveGameProc", SaveGameProc },
871 { "SavePositionProc", SavePositionProc },
872 { "MailMoveProc", MailMoveProc },
873 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
874 { "QuitProc", QuitProc },
875 { "MachineWhiteProc", MachineWhiteProc },
876 { "MachineBlackProc", MachineBlackProc },
877 { "AnalysisModeProc", AnalyzeModeProc },
878 { "AnalyzeFileProc", AnalyzeFileProc },
879 { "TwoMachinesProc", TwoMachinesProc },
880 { "IcsClientProc", IcsClientProc },
881 { "EditGameProc", EditGameProc },
882 { "EditPositionProc", EditPositionProc },
883 { "TrainingProc", EditPositionProc },
884 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
885 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
886 { "ShowGameListProc", ShowGameListProc },
887 { "ShowMoveListProc", HistoryShowProc},
888 { "EditTagsProc", EditCommentProc },
889 { "EditCommentProc", EditCommentProc },
890 { "IcsAlarmProc", IcsAlarmProc },
891 { "IcsInputBoxProc", IcsInputBoxProc },
892 { "PauseProc", PauseProc },
893 { "AcceptProc", AcceptProc },
894 { "DeclineProc", DeclineProc },
895 { "RematchProc", RematchProc },
896 { "CallFlagProc", CallFlagProc },
897 { "DrawProc", DrawProc },
898 { "AdjournProc", AdjournProc },
899 { "AbortProc", AbortProc },
900 { "ResignProc", ResignProc },
901 { "AdjuWhiteProc", AdjuWhiteProc },
902 { "AdjuBlackProc", AdjuBlackProc },
903 { "AdjuDrawProc", AdjuDrawProc },
904 { "EnterKeyProc", EnterKeyProc },
905 { "UpKeyProc", UpKeyProc },
906 { "DownKeyProc", DownKeyProc },
907 { "StopObservingProc", StopObservingProc },
908 { "StopExaminingProc", StopExaminingProc },
909 { "BackwardProc", BackwardProc },
910 { "ForwardProc", ForwardProc },
911 { "ToStartProc", ToStartProc },
912 { "ToEndProc", ToEndProc },
913 { "RevertProc", RevertProc },
914 { "TruncateGameProc", TruncateGameProc },
915 { "MoveNowProc", MoveNowProc },
916 { "RetractMoveProc", RetractMoveProc },
917 { "AlwaysQueenProc", AlwaysQueenProc },
918 { "AnimateDraggingProc", AnimateDraggingProc },
919 { "AnimateMovingProc", AnimateMovingProc },
920 { "AutoflagProc", AutoflagProc },
921 { "AutoflipProc", AutoflipProc },
922 { "AutobsProc", AutobsProc },
923 { "AutoraiseProc", AutoraiseProc },
924 { "AutosaveProc", AutosaveProc },
925 { "BlindfoldProc", BlindfoldProc },
926 { "FlashMovesProc", FlashMovesProc },
927 { "FlipViewProc", FlipViewProc },
928 { "GetMoveListProc", GetMoveListProc },
930 { "HighlightDraggingProc", HighlightDraggingProc },
932 { "HighlightLastMoveProc", HighlightLastMoveProc },
933 { "IcsAlarmProc", IcsAlarmProc },
934 { "MoveSoundProc", MoveSoundProc },
935 { "OldSaveStyleProc", OldSaveStyleProc },
936 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
937 { "PonderNextMoveProc", PonderNextMoveProc },
938 { "PopupExitMessageProc", PopupExitMessageProc },
939 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
940 { "PremoveProc", PremoveProc },
941 { "QuietPlayProc", QuietPlayProc },
942 { "ShowCoordsProc", ShowCoordsProc },
943 { "ShowThinkingProc", ShowThinkingProc },
944 { "HideThinkingProc", HideThinkingProc },
945 { "TestLegalityProc", TestLegalityProc },
946 { "SaveSettingsProc", SaveSettingsProc },
947 { "SaveOnExitProc", SaveOnExitProc },
948 { "InfoProc", InfoProc },
949 { "ManProc", ManProc },
950 { "HintProc", HintProc },
951 { "BookProc", BookProc },
952 { "AboutGameProc", AboutGameProc },
953 { "AboutProc", AboutProc },
954 { "DebugProc", DebugProc },
955 { "NothingProc", NothingProc },
956 { "CommentPopDown", (XtActionProc) CommentPopDown },
957 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
958 { "TagsPopDown", (XtActionProc) TagsPopDown },
959 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
960 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
961 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
962 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
963 { "GameListPopDown", (XtActionProc) GameListPopDown },
964 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
965 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
966 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
967 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
968 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
969 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
970 { "EnginePopDown", (XtActionProc) EnginePopDown },
971 { "UciPopDown", (XtActionProc) UciPopDown },
972 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
973 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
974 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
975 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
978 char globalTranslations[] =
979 ":<Key>R: ResignProc() \n \
980 :<Key>r: ResetProc() \n \
981 :<Key>g: LoadGameProc() \n \
982 :<Key>N: LoadNextGameProc() \n \
983 :<Key>P: LoadPrevGameProc() \n \
984 :<Key>Q: QuitProc() \n \
985 :<Key>F: ToEndProc() \n \
986 :<Key>f: ForwardProc() \n \
987 :<Key>B: ToStartProc() \n \
988 :<Key>b: BackwardProc() \n \
989 :<Key>p: PauseProc() \n \
990 :<Key>d: DrawProc() \n \
991 :<Key>t: CallFlagProc() \n \
992 :<Key>i: Iconify() \n \
993 :<Key>c: Iconify() \n \
994 :<Key>v: FlipViewProc() \n \
995 <KeyDown>Control_L: BackwardProc() \n \
996 <KeyUp>Control_L: ForwardProc() \n \
997 <KeyDown>Control_R: BackwardProc() \n \
998 <KeyUp>Control_R: ForwardProc() \n \
999 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1000 \"Send to chess program:\",,1) \n \
1001 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1002 \"Send to second chess program:\",,2) \n";
1004 char boardTranslations[] =
1005 "<Btn1Down>: HandleUserMove() \n \
1006 <Btn1Up>: HandleUserMove() \n \
1007 <Btn1Motion>: AnimateUserMove() \n \
1008 <Btn3Motion>: HandlePV() \n \
1009 <Btn3Up>: PieceMenuPopup(menuB) \n \
1010 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1011 PieceMenuPopup(menuB) \n \
1012 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1013 PieceMenuPopup(menuW) \n \
1014 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1015 PieceMenuPopup(menuW) \n \
1016 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1017 PieceMenuPopup(menuB) \n";
1019 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1020 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1022 char ICSInputTranslations[] =
1023 "<Key>Up: UpKeyProc() \n "
1024 "<Key>Down: DownKeyProc() \n "
1025 "<Key>Return: EnterKeyProc() \n";
1027 String xboardResources[] = {
1028 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1029 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1030 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1035 /* Max possible square size */
1036 #define MAXSQSIZE 256
1038 static int xpm_avail[MAXSQSIZE];
1040 #ifdef HAVE_DIR_STRUCT
1042 /* Extract piece size from filename */
1044 xpm_getsize(name, len, ext)
1055 if ((p=strchr(name, '.')) == NULL ||
1056 StrCaseCmp(p+1, ext) != 0)
1062 while (*p && isdigit(*p))
1069 /* Setup xpm_avail */
1071 xpm_getavail(dirname, ext)
1079 for (i=0; i<MAXSQSIZE; ++i)
1082 if (appData.debugMode)
1083 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1085 dir = opendir(dirname);
1088 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1089 programName, dirname);
1093 while ((ent=readdir(dir)) != NULL) {
1094 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1095 if (i > 0 && i < MAXSQSIZE)
1105 xpm_print_avail(fp, ext)
1111 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1112 for (i=1; i<MAXSQSIZE; ++i) {
1118 /* Return XPM piecesize closest to size */
1120 xpm_closest_to(dirname, size, ext)
1126 int sm_diff = MAXSQSIZE;
1130 xpm_getavail(dirname, ext);
1132 if (appData.debugMode)
1133 xpm_print_avail(stderr, ext);
1135 for (i=1; i<MAXSQSIZE; ++i) {
1138 diff = (diff<0) ? -diff : diff;
1139 if (diff < sm_diff) {
1147 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1153 #else /* !HAVE_DIR_STRUCT */
1154 /* If we are on a system without a DIR struct, we can't
1155 read the directory, so we can't collect a list of
1156 filenames, etc., so we can't do any size-fitting. */
1158 xpm_closest_to(dirname, size, ext)
1163 fprintf(stderr, _("\
1164 Warning: No DIR structure found on this system --\n\
1165 Unable to autosize for XPM/XIM pieces.\n\
1166 Please report this error to frankm@hiwaay.net.\n\
1167 Include system type & operating system in message.\n"));
1170 #endif /* HAVE_DIR_STRUCT */
1172 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1173 "magenta", "cyan", "white" };
1177 TextColors textColors[(int)NColorClasses];
1179 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1181 parse_color(str, which)
1185 char *p, buf[100], *d;
1188 if (strlen(str) > 99) /* watch bounds on buf */
1193 for (i=0; i<which; ++i) {
1200 /* Could be looking at something like:
1202 .. in which case we want to stop on a comma also */
1203 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1207 return -1; /* Use default for empty field */
1210 if (which == 2 || isdigit(*p))
1213 while (*p && isalpha(*p))
1218 for (i=0; i<8; ++i) {
1219 if (!StrCaseCmp(buf, cnames[i]))
1220 return which? (i+40) : (i+30);
1222 if (!StrCaseCmp(buf, "default")) return -1;
1224 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1229 parse_cpair(cc, str)
1233 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1234 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1239 /* bg and attr are optional */
1240 textColors[(int)cc].bg = parse_color(str, 1);
1241 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1242 textColors[(int)cc].attr = 0;
1248 /* Arrange to catch delete-window events */
1249 Atom wm_delete_window;
1251 CatchDeleteWindow(Widget w, String procname)
1254 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1255 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1256 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1263 XtSetArg(args[0], XtNiconic, False);
1264 XtSetValues(shellWidget, args, 1);
1266 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1269 //---------------------------------------------------------------------------------------------------------
1270 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1273 #define CW_USEDEFAULT (1<<31)
1274 #define ICS_TEXT_MENU_SIZE 90
1275 #define DEBUG_FILE "xboard.debug"
1276 #define SetCurrentDirectory chdir
1277 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1281 // these two must some day move to frontend.h, when they are implemented
1282 Boolean GameListIsUp();
1284 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1287 // front-end part of option handling
1289 // [HGM] This platform-dependent table provides the location for storing the color info
1290 extern char *crWhite, * crBlack;
1294 &appData.whitePieceColor,
1295 &appData.blackPieceColor,
1296 &appData.lightSquareColor,
1297 &appData.darkSquareColor,
1298 &appData.highlightSquareColor,
1299 &appData.premoveHighlightColor,
1300 &appData.lowTimeWarningColor,
1311 // [HGM] font: keep a font for each square size, even non-stndard ones
1312 #define NUM_SIZES 18
1313 #define MAX_SIZE 130
1314 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1315 char *fontTable[NUM_FONTS][MAX_SIZE];
1318 ParseFont(char *name, int number)
1319 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1321 if(sscanf(name, "size%d:", &size)) {
1322 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1323 // defer processing it until we know if it matches our board size
1324 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1325 fontTable[number][size] = strdup(strchr(name, ':')+1);
1326 fontValid[number][size] = True;
1331 case 0: // CLOCK_FONT
1332 appData.clockFont = strdup(name);
1334 case 1: // MESSAGE_FONT
1335 appData.font = strdup(name);
1337 case 2: // COORD_FONT
1338 appData.coordFont = strdup(name);
1343 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1348 { // only 2 fonts currently
1349 appData.clockFont = CLOCK_FONT_NAME;
1350 appData.coordFont = COORD_FONT_NAME;
1351 appData.font = DEFAULT_FONT_NAME;
1356 { // no-op, until we identify the code for this already in XBoard and move it here
1360 ParseColor(int n, char *name)
1361 { // in XBoard, just copy the color-name string
1362 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1366 ParseTextAttribs(ColorClass cc, char *s)
1368 (&appData.colorShout)[cc] = strdup(s);
1372 ParseBoardSize(void *addr, char *name)
1374 appData.boardSize = strdup(name);
1379 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1383 SetCommPortDefaults()
1384 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1387 // [HGM] args: these three cases taken out to stay in front-end
1389 SaveFontArg(FILE *f, ArgDescriptor *ad)
1391 char *name, buf[MSG_SIZ];
1392 int i, n = (int)ad->argLoc;
1394 case 0: // CLOCK_FONT
1395 name = appData.clockFont;
1397 case 1: // MESSAGE_FONT
1398 name = appData.font;
1400 case 2: // COORD_FONT
1401 name = appData.coordFont;
1406 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1407 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1408 fontTable[n][squareSize] = strdup(name);
1409 fontValid[n][squareSize] = True;
1412 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1413 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1418 { // nothing to do, as the sounds are at all times represented by their text-string names already
1422 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1423 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1424 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1428 SaveColor(FILE *f, ArgDescriptor *ad)
1429 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1430 if(colorVariable[(int)ad->argLoc])
1431 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1435 SaveBoardSize(FILE *f, char *name, void *addr)
1436 { // wrapper to shield back-end from BoardSize & sizeInfo
1437 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1441 ParseCommPortSettings(char *s)
1442 { // no such option in XBoard (yet)
1445 extern Widget engineOutputShell;
1446 extern Widget tagsShell, editTagsShell;
1448 GetActualPlacement(Widget wg, WindowPlacement *wp)
1458 XtSetArg(args[i], XtNx, &x); i++;
1459 XtSetArg(args[i], XtNy, &y); i++;
1460 XtSetArg(args[i], XtNwidth, &w); i++;
1461 XtSetArg(args[i], XtNheight, &h); i++;
1462 XtGetValues(wg, args, i);
1471 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1472 // In XBoard this will have to wait until awareness of window parameters is implemented
1473 GetActualPlacement(shellWidget, &wpMain);
1474 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1475 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1476 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1477 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1478 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1479 else GetActualPlacement(editShell, &wpComment);
1480 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1481 else GetActualPlacement(editTagsShell, &wpTags);
1485 PrintCommPortSettings(FILE *f, char *name)
1486 { // This option does not exist in XBoard
1490 MySearchPath(char *installDir, char *name, char *fullname)
1491 { // just append installDir and name. Perhaps ExpandPath should be used here?
1492 name = ExpandPathName(name);
1493 if(name && name[0] == '/') strcpy(fullname, name); else {
1494 sprintf(fullname, "%s%c%s", installDir, '/', name);
1500 MyGetFullPathName(char *name, char *fullname)
1501 { // should use ExpandPath?
1502 name = ExpandPathName(name);
1503 strcpy(fullname, name);
1508 EnsureOnScreen(int *x, int *y, int minX, int minY)
1515 { // [HGM] args: allows testing if main window is realized from back-end
1516 return xBoardWindow != 0;
1520 PopUpStartupDialog()
1521 { // start menu not implemented in XBoard
1524 ConvertToLine(int argc, char **argv)
1526 static char line[128*1024], buf[1024];
1530 for(i=1; i<argc; i++) {
1531 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1532 && argv[i][0] != '{' )
1533 sprintf(buf, "{%s} ", argv[i]);
1534 else sprintf(buf, "%s ", argv[i]);
1537 line[strlen(line)-1] = NULLCHAR;
1541 //--------------------------------------------------------------------------------------------
1544 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1546 #define BoardSize int
1547 void InitDrawingSizes(BoardSize boardSize, int flags)
1548 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1549 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1551 XtGeometryResult gres;
1554 if(!formWidget) return;
1557 * Enable shell resizing.
1559 shellArgs[0].value = (XtArgVal) &w;
1560 shellArgs[1].value = (XtArgVal) &h;
1561 XtGetValues(shellWidget, shellArgs, 2);
1563 shellArgs[4].value = 2*w; shellArgs[2].value = 10;
1564 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1565 XtSetValues(shellWidget, &shellArgs[2], 4);
1567 XtSetArg(args[0], XtNdefaultDistance, &sep);
1568 XtGetValues(formWidget, args, 1);
1570 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1571 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1574 XtSetArg(args[0], XtNwidth, boardWidth);
1575 XtSetArg(args[1], XtNheight, boardHeight);
1576 XtSetValues(boardWidget, args, 2);
1578 timerWidth = (boardWidth - sep) / 2;
1579 XtSetArg(args[0], XtNwidth, timerWidth);
1580 XtSetValues(whiteTimerWidget, args, 1);
1581 XtSetValues(blackTimerWidget, args, 1);
1583 XawFormDoLayout(formWidget, False);
1585 if (appData.titleInWindow) {
1587 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1588 XtSetArg(args[i], XtNheight, &h); i++;
1589 XtGetValues(titleWidget, args, i);
1591 w = boardWidth - 2*bor;
1593 XtSetArg(args[0], XtNwidth, &w);
1594 XtGetValues(menuBarWidget, args, 1);
1595 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1598 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1599 if (gres != XtGeometryYes && appData.debugMode) {
1601 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1602 programName, gres, w, h, wr, hr);
1606 XawFormDoLayout(formWidget, True);
1609 * Inhibit shell resizing.
1611 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW;
1612 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1613 shellArgs[4].value = shellArgs[2].value = w;
1614 shellArgs[5].value = shellArgs[3].value = h;
1615 XtSetValues(shellWidget, &shellArgs[0], 6);
1617 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1620 for(i=0; i<4; i++) {
1622 for(p=0; p<=(int)WhiteKing; p++)
1623 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1624 if(gameInfo.variant == VariantShogi) {
1625 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1626 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1627 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1628 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1629 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1632 if(gameInfo.variant == VariantGothic) {
1633 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1637 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1638 for(p=0; p<=(int)WhiteKing; p++)
1639 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1640 if(gameInfo.variant == VariantShogi) {
1641 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1642 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1643 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1644 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1645 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1648 if(gameInfo.variant == VariantGothic) {
1649 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1655 for(i=0; i<2; i++) {
1657 for(p=0; p<=(int)WhiteKing; p++)
1658 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1659 if(gameInfo.variant == VariantShogi) {
1660 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1661 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1662 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1663 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1664 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1667 if(gameInfo.variant == VariantGothic) {
1668 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1679 void EscapeExpand(char *p, char *q)
1680 { // [HGM] initstring: routine to shape up string arguments
1681 while(*p++ = *q++) if(p[-1] == '\\')
1683 case 'n': p[-1] = '\n'; break;
1684 case 'r': p[-1] = '\r'; break;
1685 case 't': p[-1] = '\t'; break;
1686 case '\\': p[-1] = '\\'; break;
1687 case 0: *p = 0; return;
1688 default: p[-1] = q[-1]; break;
1697 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1698 XSetWindowAttributes window_attributes;
1700 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1701 XrmValue vFrom, vTo;
1702 XtGeometryResult gres;
1705 int forceMono = False;
1707 srandom(time(0)); // [HGM] book: make random truly random
1709 setbuf(stdout, NULL);
1710 setbuf(stderr, NULL);
1713 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1714 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1718 programName = strrchr(argv[0], '/');
1719 if (programName == NULL)
1720 programName = argv[0];
1725 XtSetLanguageProc(NULL, NULL, NULL);
1726 bindtextdomain(PACKAGE, LOCALEDIR);
1727 textdomain(PACKAGE);
1731 XtAppInitialize(&appContext, "XBoard", shellOptions,
1732 XtNumber(shellOptions),
1733 &argc, argv, xboardResources, NULL, 0);
1734 appData.boardSize = "";
1735 InitAppData(ConvertToLine(argc, argv));
1737 if (p == NULL) p = "/tmp";
1738 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1739 gameCopyFilename = (char*) malloc(i);
1740 gamePasteFilename = (char*) malloc(i);
1741 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1742 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1744 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1745 clientResources, XtNumber(clientResources),
1748 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1749 static char buf[MSG_SIZ];
1750 EscapeExpand(buf, appData.initString);
1751 appData.initString = strdup(buf);
1752 EscapeExpand(buf, appData.secondInitString);
1753 appData.secondInitString = strdup(buf);
1754 EscapeExpand(buf, appData.firstComputerString);
1755 appData.firstComputerString = strdup(buf);
1756 EscapeExpand(buf, appData.secondComputerString);
1757 appData.secondComputerString = strdup(buf);
1760 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1763 if (chdir(chessDir) != 0) {
1764 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1770 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1771 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1772 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1773 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1776 setbuf(debugFP, NULL);
1779 /* [HGM,HR] make sure board size is acceptable */
1780 if(appData.NrFiles > BOARD_FILES ||
1781 appData.NrRanks > BOARD_RANKS )
1782 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1785 /* This feature does not work; animation needs a rewrite */
1786 appData.highlightDragging = FALSE;
1790 xDisplay = XtDisplay(shellWidget);
1791 xScreen = DefaultScreen(xDisplay);
1792 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1794 gameInfo.variant = StringToVariant(appData.variant);
1795 InitPosition(FALSE);
1798 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1800 if (isdigit(appData.boardSize[0])) {
1801 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1802 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1803 &fontPxlSize, &smallLayout, &tinyLayout);
1805 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1806 programName, appData.boardSize);
1810 /* Find some defaults; use the nearest known size */
1811 SizeDefaults *szd, *nearest;
1812 int distance = 99999;
1813 nearest = szd = sizeDefaults;
1814 while (szd->name != NULL) {
1815 if (abs(szd->squareSize - squareSize) < distance) {
1817 distance = abs(szd->squareSize - squareSize);
1818 if (distance == 0) break;
1822 if (i < 2) lineGap = nearest->lineGap;
1823 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1824 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1825 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1826 if (i < 6) smallLayout = nearest->smallLayout;
1827 if (i < 7) tinyLayout = nearest->tinyLayout;
1830 SizeDefaults *szd = sizeDefaults;
1831 if (*appData.boardSize == NULLCHAR) {
1832 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1833 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1836 if (szd->name == NULL) szd--;
1837 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1839 while (szd->name != NULL &&
1840 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1841 if (szd->name == NULL) {
1842 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1843 programName, appData.boardSize);
1847 squareSize = szd->squareSize;
1848 lineGap = szd->lineGap;
1849 clockFontPxlSize = szd->clockFontPxlSize;
1850 coordFontPxlSize = szd->coordFontPxlSize;
1851 fontPxlSize = szd->fontPxlSize;
1852 smallLayout = szd->smallLayout;
1853 tinyLayout = szd->tinyLayout;
1854 // [HGM] font: use defaults from settings file if available and not overruled
1856 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
1857 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
1858 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
1859 appData.font = fontTable[MESSAGE_FONT][squareSize];
1860 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
1861 appData.coordFont = fontTable[COORD_FONT][squareSize];
1863 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1864 if (strlen(appData.pixmapDirectory) > 0) {
1865 p = ExpandPathName(appData.pixmapDirectory);
1867 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1868 appData.pixmapDirectory);
1871 if (appData.debugMode) {
1872 fprintf(stderr, _("\
1873 XBoard square size (hint): %d\n\
1874 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1876 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1877 if (appData.debugMode) {
1878 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1882 /* [HR] height treated separately (hacked) */
1883 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1884 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1885 if (appData.showJail == 1) {
1886 /* Jail on top and bottom */
1887 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1888 XtSetArg(boardArgs[2], XtNheight,
1889 boardHeight + 2*(lineGap + squareSize));
1890 } else if (appData.showJail == 2) {
1892 XtSetArg(boardArgs[1], XtNwidth,
1893 boardWidth + 2*(lineGap + squareSize));
1894 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1897 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1898 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1902 * Determine what fonts to use.
1904 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1905 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1906 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1907 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1908 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1909 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1910 appData.font = FindFont(appData.font, fontPxlSize);
1911 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1912 countFontStruct = XQueryFont(xDisplay, countFontID);
1913 // appData.font = FindFont(appData.font, fontPxlSize);
1915 xdb = XtDatabase(xDisplay);
1916 XrmPutStringResource(&xdb, "*font", appData.font);
1919 * Detect if there are not enough colors available and adapt.
1921 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1922 appData.monoMode = True;
1925 if (!appData.monoMode) {
1926 vFrom.addr = (caddr_t) appData.lightSquareColor;
1927 vFrom.size = strlen(appData.lightSquareColor);
1928 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1929 if (vTo.addr == NULL) {
1930 appData.monoMode = True;
1933 lightSquareColor = *(Pixel *) vTo.addr;
1936 if (!appData.monoMode) {
1937 vFrom.addr = (caddr_t) appData.darkSquareColor;
1938 vFrom.size = strlen(appData.darkSquareColor);
1939 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1940 if (vTo.addr == NULL) {
1941 appData.monoMode = True;
1944 darkSquareColor = *(Pixel *) vTo.addr;
1947 if (!appData.monoMode) {
1948 vFrom.addr = (caddr_t) appData.whitePieceColor;
1949 vFrom.size = strlen(appData.whitePieceColor);
1950 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1951 if (vTo.addr == NULL) {
1952 appData.monoMode = True;
1955 whitePieceColor = *(Pixel *) vTo.addr;
1958 if (!appData.monoMode) {
1959 vFrom.addr = (caddr_t) appData.blackPieceColor;
1960 vFrom.size = strlen(appData.blackPieceColor);
1961 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1962 if (vTo.addr == NULL) {
1963 appData.monoMode = True;
1966 blackPieceColor = *(Pixel *) vTo.addr;
1970 if (!appData.monoMode) {
1971 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1972 vFrom.size = strlen(appData.highlightSquareColor);
1973 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1974 if (vTo.addr == NULL) {
1975 appData.monoMode = True;
1978 highlightSquareColor = *(Pixel *) vTo.addr;
1982 if (!appData.monoMode) {
1983 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1984 vFrom.size = strlen(appData.premoveHighlightColor);
1985 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1986 if (vTo.addr == NULL) {
1987 appData.monoMode = True;
1990 premoveHighlightColor = *(Pixel *) vTo.addr;
1995 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1998 if (appData.bitmapDirectory == NULL ||
1999 appData.bitmapDirectory[0] == NULLCHAR)
2000 appData.bitmapDirectory = DEF_BITMAP_DIR;
2003 if (appData.lowTimeWarning && !appData.monoMode) {
2004 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2005 vFrom.size = strlen(appData.lowTimeWarningColor);
2006 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2007 if (vTo.addr == NULL)
2008 appData.monoMode = True;
2010 lowTimeWarningColor = *(Pixel *) vTo.addr;
2013 if (appData.monoMode && appData.debugMode) {
2014 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2015 (unsigned long) XWhitePixel(xDisplay, xScreen),
2016 (unsigned long) XBlackPixel(xDisplay, xScreen));
2019 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2020 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2021 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2022 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2023 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2024 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2025 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2026 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2027 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2028 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2030 if (appData.colorize) {
2032 _("%s: can't parse color names; disabling colorization\n"),
2035 appData.colorize = FALSE;
2037 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2038 textColors[ColorNone].attr = 0;
2040 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2046 layoutName = "tinyLayout";
2047 } else if (smallLayout) {
2048 layoutName = "smallLayout";
2050 layoutName = "normalLayout";
2052 /* Outer layoutWidget is there only to provide a name for use in
2053 resources that depend on the layout style */
2055 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2056 layoutArgs, XtNumber(layoutArgs));
2058 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2059 formArgs, XtNumber(formArgs));
2060 XtSetArg(args[0], XtNdefaultDistance, &sep);
2061 XtGetValues(formWidget, args, 1);
2064 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2065 XtSetArg(args[0], XtNtop, XtChainTop);
2066 XtSetArg(args[1], XtNbottom, XtChainTop);
2067 XtSetArg(args[2], XtNright, XtChainLeft);
2068 XtSetValues(menuBarWidget, args, 3);
2070 widgetList[j++] = whiteTimerWidget =
2071 XtCreateWidget("whiteTime", labelWidgetClass,
2072 formWidget, timerArgs, XtNumber(timerArgs));
2073 XtSetArg(args[0], XtNfont, clockFontStruct);
2074 XtSetArg(args[1], XtNtop, XtChainTop);
2075 XtSetArg(args[2], XtNbottom, XtChainTop);
2076 XtSetValues(whiteTimerWidget, args, 3);
2078 widgetList[j++] = blackTimerWidget =
2079 XtCreateWidget("blackTime", labelWidgetClass,
2080 formWidget, timerArgs, XtNumber(timerArgs));
2081 XtSetArg(args[0], XtNfont, clockFontStruct);
2082 XtSetArg(args[1], XtNtop, XtChainTop);
2083 XtSetArg(args[2], XtNbottom, XtChainTop);
2084 XtSetValues(blackTimerWidget, args, 3);
2086 if (appData.titleInWindow) {
2087 widgetList[j++] = titleWidget =
2088 XtCreateWidget("title", labelWidgetClass, formWidget,
2089 titleArgs, XtNumber(titleArgs));
2090 XtSetArg(args[0], XtNtop, XtChainTop);
2091 XtSetArg(args[1], XtNbottom, XtChainTop);
2092 XtSetValues(titleWidget, args, 2);
2095 if (appData.showButtonBar) {
2096 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2097 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2098 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2099 XtSetArg(args[2], XtNtop, XtChainTop);
2100 XtSetArg(args[3], XtNbottom, XtChainTop);
2101 XtSetValues(buttonBarWidget, args, 4);
2104 widgetList[j++] = messageWidget =
2105 XtCreateWidget("message", labelWidgetClass, formWidget,
2106 messageArgs, XtNumber(messageArgs));
2107 XtSetArg(args[0], XtNtop, XtChainTop);
2108 XtSetArg(args[1], XtNbottom, XtChainTop);
2109 XtSetValues(messageWidget, args, 2);
2111 widgetList[j++] = boardWidget =
2112 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2113 XtNumber(boardArgs));
2115 XtManageChildren(widgetList, j);
2117 timerWidth = (boardWidth - sep) / 2;
2118 XtSetArg(args[0], XtNwidth, timerWidth);
2119 XtSetValues(whiteTimerWidget, args, 1);
2120 XtSetValues(blackTimerWidget, args, 1);
2122 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2123 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2124 XtGetValues(whiteTimerWidget, args, 2);
2126 if (appData.showButtonBar) {
2127 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2128 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2129 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2133 * formWidget uses these constraints but they are stored
2137 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2138 XtSetValues(menuBarWidget, args, i);
2139 if (appData.titleInWindow) {
2142 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2143 XtSetValues(whiteTimerWidget, args, i);
2145 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2146 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2147 XtSetValues(blackTimerWidget, args, i);
2149 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2150 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2151 XtSetValues(titleWidget, args, i);
2153 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2154 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2155 XtSetValues(messageWidget, args, i);
2156 if (appData.showButtonBar) {
2158 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2159 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2160 XtSetValues(buttonBarWidget, args, i);
2164 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2165 XtSetValues(whiteTimerWidget, args, i);
2167 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2168 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2169 XtSetValues(blackTimerWidget, args, i);
2171 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2172 XtSetValues(titleWidget, args, i);
2174 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2175 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2176 XtSetValues(messageWidget, args, i);
2177 if (appData.showButtonBar) {
2179 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2180 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2181 XtSetValues(buttonBarWidget, args, i);
2186 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2187 XtSetValues(whiteTimerWidget, args, i);
2189 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2190 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2191 XtSetValues(blackTimerWidget, args, i);
2193 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2194 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2195 XtSetValues(messageWidget, args, i);
2196 if (appData.showButtonBar) {
2198 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2199 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2200 XtSetValues(buttonBarWidget, args, i);
2204 XtSetArg(args[0], XtNfromVert, messageWidget);
2205 XtSetArg(args[1], XtNtop, XtChainTop);
2206 XtSetArg(args[2], XtNbottom, XtChainBottom);
2207 XtSetArg(args[3], XtNleft, XtChainLeft);
2208 XtSetArg(args[4], XtNright, XtChainRight);
2209 XtSetValues(boardWidget, args, 5);
2211 XtRealizeWidget(shellWidget);
2214 XtSetArg(args[0], XtNx, wpMain.x);
2215 XtSetArg(args[1], XtNy, wpMain.y);
2216 XtSetValues(shellWidget, args, 2);
2220 * Correct the width of the message and title widgets.
2221 * It is not known why some systems need the extra fudge term.
2222 * The value "2" is probably larger than needed.
2224 XawFormDoLayout(formWidget, False);
2226 #define WIDTH_FUDGE 2
2228 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2229 XtSetArg(args[i], XtNheight, &h); i++;
2230 XtGetValues(messageWidget, args, i);
2231 if (appData.showButtonBar) {
2233 XtSetArg(args[i], XtNwidth, &w); i++;
2234 XtGetValues(buttonBarWidget, args, i);
2235 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2237 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2240 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2241 if (gres != XtGeometryYes && appData.debugMode) {
2242 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2243 programName, gres, w, h, wr, hr);
2246 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2247 /* The size used for the child widget in layout lags one resize behind
2248 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2250 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2251 if (gres != XtGeometryYes && appData.debugMode) {
2252 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2253 programName, gres, w, h, wr, hr);
2256 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2257 XtSetArg(args[1], XtNright, XtChainRight);
2258 XtSetValues(messageWidget, args, 2);
2260 if (appData.titleInWindow) {
2262 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2263 XtSetArg(args[i], XtNheight, &h); i++;
2264 XtGetValues(titleWidget, args, i);
2266 w = boardWidth - 2*bor;
2268 XtSetArg(args[0], XtNwidth, &w);
2269 XtGetValues(menuBarWidget, args, 1);
2270 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2273 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2274 if (gres != XtGeometryYes && appData.debugMode) {
2276 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2277 programName, gres, w, h, wr, hr);
2280 XawFormDoLayout(formWidget, True);
2282 xBoardWindow = XtWindow(boardWidget);
2284 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2285 // not need to go into InitDrawingSizes().
2289 * Create X checkmark bitmap and initialize option menu checks.
2291 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2292 checkmark_bits, checkmark_width, checkmark_height);
2293 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2294 if (appData.alwaysPromoteToQueen) {
2295 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2298 if (appData.animateDragging) {
2299 XtSetValues(XtNameToWidget(menuBarWidget,
2300 "menuOptions.Animate Dragging"),
2303 if (appData.animate) {
2304 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2307 if (appData.autoComment) {
2308 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2311 if (appData.autoCallFlag) {
2312 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2315 if (appData.autoFlipView) {
2316 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2319 if (appData.autoObserve) {
2320 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2323 if (appData.autoRaiseBoard) {
2324 XtSetValues(XtNameToWidget(menuBarWidget,
2325 "menuOptions.Auto Raise Board"), args, 1);
2327 if (appData.autoSaveGames) {
2328 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2331 if (appData.saveGameFile[0] != NULLCHAR) {
2332 /* Can't turn this off from menu */
2333 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2335 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2339 if (appData.blindfold) {
2340 XtSetValues(XtNameToWidget(menuBarWidget,
2341 "menuOptions.Blindfold"), args, 1);
2343 if (appData.flashCount > 0) {
2344 XtSetValues(XtNameToWidget(menuBarWidget,
2345 "menuOptions.Flash Moves"),
2348 if (appData.getMoveList) {
2349 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2353 if (appData.highlightDragging) {
2354 XtSetValues(XtNameToWidget(menuBarWidget,
2355 "menuOptions.Highlight Dragging"),
2359 if (appData.highlightLastMove) {
2360 XtSetValues(XtNameToWidget(menuBarWidget,
2361 "menuOptions.Highlight Last Move"),
2364 if (appData.icsAlarm) {
2365 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2368 if (appData.ringBellAfterMoves) {
2369 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2372 if (appData.oldSaveStyle) {
2373 XtSetValues(XtNameToWidget(menuBarWidget,
2374 "menuOptions.Old Save Style"), args, 1);
2376 if (appData.periodicUpdates) {
2377 XtSetValues(XtNameToWidget(menuBarWidget,
2378 "menuOptions.Periodic Updates"), args, 1);
2380 if (appData.ponderNextMove) {
2381 XtSetValues(XtNameToWidget(menuBarWidget,
2382 "menuOptions.Ponder Next Move"), args, 1);
2384 if (appData.popupExitMessage) {
2385 XtSetValues(XtNameToWidget(menuBarWidget,
2386 "menuOptions.Popup Exit Message"), args, 1);
2388 if (appData.popupMoveErrors) {
2389 XtSetValues(XtNameToWidget(menuBarWidget,
2390 "menuOptions.Popup Move Errors"), args, 1);
2392 if (appData.premove) {
2393 XtSetValues(XtNameToWidget(menuBarWidget,
2394 "menuOptions.Premove"), args, 1);
2396 if (appData.quietPlay) {
2397 XtSetValues(XtNameToWidget(menuBarWidget,
2398 "menuOptions.Quiet Play"), args, 1);
2400 if (appData.showCoords) {
2401 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2404 if (appData.hideThinkingFromHuman) {
2405 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2408 if (appData.testLegality) {
2409 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2412 if (saveSettingsOnExit) {
2413 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2420 ReadBitmap(&wIconPixmap, "icon_white.bm",
2421 icon_white_bits, icon_white_width, icon_white_height);
2422 ReadBitmap(&bIconPixmap, "icon_black.bm",
2423 icon_black_bits, icon_black_width, icon_black_height);
2424 iconPixmap = wIconPixmap;
2426 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2427 XtSetValues(shellWidget, args, i);
2430 * Create a cursor for the board widget.
2432 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2433 XChangeWindowAttributes(xDisplay, xBoardWindow,
2434 CWCursor, &window_attributes);
2437 * Inhibit shell resizing.
2439 shellArgs[0].value = (XtArgVal) &w;
2440 shellArgs[1].value = (XtArgVal) &h;
2441 XtGetValues(shellWidget, shellArgs, 2);
2442 shellArgs[4].value = shellArgs[2].value = w;
2443 shellArgs[5].value = shellArgs[3].value = h;
2444 XtSetValues(shellWidget, &shellArgs[2], 4);
2445 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2446 marginH = h - boardHeight;
2448 CatchDeleteWindow(shellWidget, "QuitProc");
2453 if (appData.bitmapDirectory[0] != NULLCHAR) {
2460 /* Create regular pieces */
2461 if (!useImages) CreatePieces();
2466 if (appData.animate || appData.animateDragging)
2469 XtAugmentTranslations(formWidget,
2470 XtParseTranslationTable(globalTranslations));
2471 XtAugmentTranslations(boardWidget,
2472 XtParseTranslationTable(boardTranslations));
2473 XtAugmentTranslations(whiteTimerWidget,
2474 XtParseTranslationTable(whiteTranslations));
2475 XtAugmentTranslations(blackTimerWidget,
2476 XtParseTranslationTable(blackTranslations));
2478 /* Why is the following needed on some versions of X instead
2479 * of a translation? */
2480 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2481 (XtEventHandler) EventProc, NULL);
2484 /* [AS] Restore layout */
2485 if( wpMoveHistory.visible ) {
2489 if( wpEvalGraph.visible )
2494 if( wpEngineOutput.visible ) {
2495 EngineOutputPopUp();
2500 if (errorExitStatus == -1) {
2501 if (appData.icsActive) {
2502 /* We now wait until we see "login:" from the ICS before
2503 sending the logon script (problems with timestamp otherwise) */
2504 /*ICSInitScript();*/
2505 if (appData.icsInputBox) ICSInputBoxPopUp();
2509 signal(SIGWINCH, TermSizeSigHandler);
2511 signal(SIGINT, IntSigHandler);
2512 signal(SIGTERM, IntSigHandler);
2513 if (*appData.cmailGameName != NULLCHAR) {
2514 signal(SIGUSR1, CmailSigHandler);
2517 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2520 XtAppMainLoop(appContext);
2521 if (appData.debugMode) fclose(debugFP); // [DM] debug
2528 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2529 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2531 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2532 unlink(gameCopyFilename);
2533 unlink(gamePasteFilename);
2536 RETSIGTYPE TermSizeSigHandler(int sig)
2549 CmailSigHandler(sig)
2555 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2557 /* Activate call-back function CmailSigHandlerCallBack() */
2558 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2560 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2564 CmailSigHandlerCallBack(isr, closure, message, count, error)
2572 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2574 /**** end signal code ****/
2584 f = fopen(appData.icsLogon, "r");
2590 strcat(buf, appData.icsLogon);
2591 f = fopen(buf, "r");
2595 ProcessICSInitScript(f);
2602 EditCommentPopDown();
2617 if (!menuBarWidget) return;
2618 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2620 DisplayError("menuStep.Revert", 0);
2622 XtSetSensitive(w, !grey);
2627 SetMenuEnables(enab)
2631 if (!menuBarWidget) return;
2632 while (enab->name != NULL) {
2633 w = XtNameToWidget(menuBarWidget, enab->name);
2635 DisplayError(enab->name, 0);
2637 XtSetSensitive(w, enab->value);
2643 Enables icsEnables[] = {
2644 { "menuFile.Mail Move", False },
2645 { "menuFile.Reload CMail Message", False },
2646 { "menuMode.Machine Black", False },
2647 { "menuMode.Machine White", False },
2648 { "menuMode.Analysis Mode", False },
2649 { "menuMode.Analyze File", False },
2650 { "menuMode.Two Machines", False },
2652 { "menuHelp.Hint", False },
2653 { "menuHelp.Book", False },
2654 { "menuStep.Move Now", False },
2655 { "menuOptions.Periodic Updates", False },
2656 { "menuOptions.Hide Thinking", False },
2657 { "menuOptions.Ponder Next Move", False },
2662 Enables ncpEnables[] = {
2663 { "menuFile.Mail Move", False },
2664 { "menuFile.Reload CMail Message", False },
2665 { "menuMode.Machine White", False },
2666 { "menuMode.Machine Black", False },
2667 { "menuMode.Analysis Mode", False },
2668 { "menuMode.Analyze File", False },
2669 { "menuMode.Two Machines", False },
2670 { "menuMode.ICS Client", False },
2671 { "menuMode.ICS Input Box", False },
2672 { "Action", False },
2673 { "menuStep.Revert", False },
2674 { "menuStep.Move Now", False },
2675 { "menuStep.Retract Move", False },
2676 { "menuOptions.Auto Comment", False },
2677 { "menuOptions.Auto Flag", False },
2678 { "menuOptions.Auto Flip View", False },
2679 { "menuOptions.Auto Observe", False },
2680 { "menuOptions.Auto Raise Board", False },
2681 { "menuOptions.Get Move List", False },
2682 { "menuOptions.ICS Alarm", False },
2683 { "menuOptions.Move Sound", False },
2684 { "menuOptions.Quiet Play", False },
2685 { "menuOptions.Hide Thinking", False },
2686 { "menuOptions.Periodic Updates", False },
2687 { "menuOptions.Ponder Next Move", False },
2688 { "menuHelp.Hint", False },
2689 { "menuHelp.Book", False },
2693 Enables gnuEnables[] = {
2694 { "menuMode.ICS Client", False },
2695 { "menuMode.ICS Input Box", False },
2696 { "menuAction.Accept", False },
2697 { "menuAction.Decline", False },
2698 { "menuAction.Rematch", False },
2699 { "menuAction.Adjourn", False },
2700 { "menuAction.Stop Examining", False },
2701 { "menuAction.Stop Observing", False },
2702 { "menuStep.Revert", False },
2703 { "menuOptions.Auto Comment", False },
2704 { "menuOptions.Auto Observe", False },
2705 { "menuOptions.Auto Raise Board", False },
2706 { "menuOptions.Get Move List", False },
2707 { "menuOptions.Premove", False },
2708 { "menuOptions.Quiet Play", False },
2710 /* The next two options rely on SetCmailMode being called *after* */
2711 /* SetGNUMode so that when GNU is being used to give hints these */
2712 /* menu options are still available */
2714 { "menuFile.Mail Move", False },
2715 { "menuFile.Reload CMail Message", False },
2719 Enables cmailEnables[] = {
2721 { "menuAction.Call Flag", False },
2722 { "menuAction.Draw", True },
2723 { "menuAction.Adjourn", False },
2724 { "menuAction.Abort", False },
2725 { "menuAction.Stop Observing", False },
2726 { "menuAction.Stop Examining", False },
2727 { "menuFile.Mail Move", True },
2728 { "menuFile.Reload CMail Message", True },
2732 Enables trainingOnEnables[] = {
2733 { "menuMode.Edit Comment", False },
2734 { "menuMode.Pause", False },
2735 { "menuStep.Forward", False },
2736 { "menuStep.Backward", False },
2737 { "menuStep.Forward to End", False },
2738 { "menuStep.Back to Start", False },
2739 { "menuStep.Move Now", False },
2740 { "menuStep.Truncate Game", False },
2744 Enables trainingOffEnables[] = {
2745 { "menuMode.Edit Comment", True },
2746 { "menuMode.Pause", True },
2747 { "menuStep.Forward", True },
2748 { "menuStep.Backward", True },
2749 { "menuStep.Forward to End", True },
2750 { "menuStep.Back to Start", True },
2751 { "menuStep.Move Now", True },
2752 { "menuStep.Truncate Game", True },
2756 Enables machineThinkingEnables[] = {
2757 { "menuFile.Load Game", False },
2758 { "menuFile.Load Next Game", False },
2759 { "menuFile.Load Previous Game", False },
2760 { "menuFile.Reload Same Game", False },
2761 { "menuFile.Paste Game", False },
2762 { "menuFile.Load Position", False },
2763 { "menuFile.Load Next Position", False },
2764 { "menuFile.Load Previous Position", False },
2765 { "menuFile.Reload Same Position", False },
2766 { "menuFile.Paste Position", False },
2767 { "menuMode.Machine White", False },
2768 { "menuMode.Machine Black", False },
2769 { "menuMode.Two Machines", False },
2770 { "menuStep.Retract Move", False },
2774 Enables userThinkingEnables[] = {
2775 { "menuFile.Load Game", True },
2776 { "menuFile.Load Next Game", True },
2777 { "menuFile.Load Previous Game", True },
2778 { "menuFile.Reload Same Game", True },
2779 { "menuFile.Paste Game", True },
2780 { "menuFile.Load Position", True },
2781 { "menuFile.Load Next Position", True },
2782 { "menuFile.Load Previous Position", True },
2783 { "menuFile.Reload Same Position", True },
2784 { "menuFile.Paste Position", True },
2785 { "menuMode.Machine White", True },
2786 { "menuMode.Machine Black", True },
2787 { "menuMode.Two Machines", True },
2788 { "menuStep.Retract Move", True },
2794 SetMenuEnables(icsEnables);
2797 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2798 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2805 SetMenuEnables(ncpEnables);
2811 SetMenuEnables(gnuEnables);
2817 SetMenuEnables(cmailEnables);
2823 SetMenuEnables(trainingOnEnables);
2824 if (appData.showButtonBar) {
2825 XtSetSensitive(buttonBarWidget, False);
2831 SetTrainingModeOff()
2833 SetMenuEnables(trainingOffEnables);
2834 if (appData.showButtonBar) {
2835 XtSetSensitive(buttonBarWidget, True);
2840 SetUserThinkingEnables()
2842 if (appData.noChessProgram) return;
2843 SetMenuEnables(userThinkingEnables);
2847 SetMachineThinkingEnables()
2849 if (appData.noChessProgram) return;
2850 SetMenuEnables(machineThinkingEnables);
2852 case MachinePlaysBlack:
2853 case MachinePlaysWhite:
2854 case TwoMachinesPlay:
2855 XtSetSensitive(XtNameToWidget(menuBarWidget,
2856 ModeToWidgetName(gameMode)), True);
2863 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2864 #define HISTORY_SIZE 64
\r
2865 static char *history[HISTORY_SIZE];
\r
2866 int histIn = 0, histP = 0;
\r
2869 SaveInHistory(char *cmd)
\r
2871 if (history[histIn] != NULL) {
\r
2872 free(history[histIn]);
\r
2873 history[histIn] = NULL;
\r
2875 if (*cmd == NULLCHAR) return;
\r
2876 history[histIn] = StrSave(cmd);
\r
2877 histIn = (histIn + 1) % HISTORY_SIZE;
\r
2878 if (history[histIn] != NULL) {
\r
2879 free(history[histIn]);
\r
2880 history[histIn] = NULL;
\r
2886 PrevInHistory(char *cmd)
\r
2889 if (histP == histIn) {
\r
2890 if (history[histIn] != NULL) free(history[histIn]);
\r
2891 history[histIn] = StrSave(cmd);
\r
2893 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
2894 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
2896 return history[histP];
\r
2902 if (histP == histIn) return NULL;
\r
2903 histP = (histP + 1) % HISTORY_SIZE;
\r
2904 return history[histP];
\r
2906 // end of borrowed code
\r
2908 #define Abs(n) ((n)<0 ? -(n) : (n))
2911 * Find a font that matches "pattern" that is as close as
2912 * possible to the targetPxlSize. Prefer fonts that are k
2913 * pixels smaller to fonts that are k pixels larger. The
2914 * pattern must be in the X Consortium standard format,
2915 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2916 * The return value should be freed with XtFree when no
2919 char *FindFont(pattern, targetPxlSize)
2923 char **fonts, *p, *best, *scalable, *scalableTail;
2924 int i, j, nfonts, minerr, err, pxlSize;
2927 char **missing_list;
2929 char *def_string, *base_fnt_lst, strInt[3];
2931 XFontStruct **fnt_list;
2933 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2934 sprintf(strInt, "%d", targetPxlSize);
2935 p = strstr(pattern, "--");
2936 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2937 strcat(base_fnt_lst, strInt);
2938 strcat(base_fnt_lst, strchr(p + 2, '-'));
2940 if ((fntSet = XCreateFontSet(xDisplay,
2944 &def_string)) == NULL) {
2946 fprintf(stderr, _("Unable to create font set.\n"));
2950 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2952 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2954 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2955 programName, pattern);
2963 for (i=0; i<nfonts; i++) {
2966 if (*p != '-') continue;
2968 if (*p == NULLCHAR) break;
2969 if (*p++ == '-') j++;
2971 if (j < 7) continue;
2974 scalable = fonts[i];
2977 err = pxlSize - targetPxlSize;
2978 if (Abs(err) < Abs(minerr) ||
2979 (minerr > 0 && err < 0 && -err == minerr)) {
2985 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
2986 /* If the error is too big and there is a scalable font,
2987 use the scalable font. */
2988 int headlen = scalableTail - scalable;
2989 p = (char *) XtMalloc(strlen(scalable) + 10);
2990 while (isdigit(*scalableTail)) scalableTail++;
2991 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
2993 p = (char *) XtMalloc(strlen(best) + 1);
2996 if (appData.debugMode) {
2997 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
2998 pattern, targetPxlSize, p);
3001 if (missing_count > 0)
3002 XFreeStringList(missing_list);
3003 XFreeFontSet(xDisplay, fntSet);
3005 XFreeFontNames(fonts);
3012 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3013 | GCBackground | GCFunction | GCPlaneMask;
3014 XGCValues gc_values;
3017 gc_values.plane_mask = AllPlanes;
3018 gc_values.line_width = lineGap;
3019 gc_values.line_style = LineSolid;
3020 gc_values.function = GXcopy;
3022 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3023 gc_values.background = XBlackPixel(xDisplay, xScreen);
3024 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3026 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3027 gc_values.background = XWhitePixel(xDisplay, xScreen);
3028 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3029 XSetFont(xDisplay, coordGC, coordFontID);
3031 // [HGM] make font for holdings counts (white on black0
3032 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3033 gc_values.background = XBlackPixel(xDisplay, xScreen);
3034 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3035 XSetFont(xDisplay, countGC, countFontID);
3037 if (appData.monoMode) {
3038 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3039 gc_values.background = XWhitePixel(xDisplay, xScreen);
3040 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3042 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3043 gc_values.background = XBlackPixel(xDisplay, xScreen);
3044 lightSquareGC = wbPieceGC
3045 = XtGetGC(shellWidget, value_mask, &gc_values);
3047 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3048 gc_values.background = XWhitePixel(xDisplay, xScreen);
3049 darkSquareGC = bwPieceGC
3050 = XtGetGC(shellWidget, value_mask, &gc_values);
3052 if (DefaultDepth(xDisplay, xScreen) == 1) {
3053 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3054 gc_values.function = GXcopyInverted;
3055 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3056 gc_values.function = GXcopy;
3057 if (XBlackPixel(xDisplay, xScreen) == 1) {
3058 bwPieceGC = darkSquareGC;
3059 wbPieceGC = copyInvertedGC;
3061 bwPieceGC = copyInvertedGC;
3062 wbPieceGC = lightSquareGC;
3066 gc_values.foreground = highlightSquareColor;
3067 gc_values.background = highlightSquareColor;
3068 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3070 gc_values.foreground = premoveHighlightColor;
3071 gc_values.background = premoveHighlightColor;
3072 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3074 gc_values.foreground = lightSquareColor;
3075 gc_values.background = darkSquareColor;
3076 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3078 gc_values.foreground = darkSquareColor;
3079 gc_values.background = lightSquareColor;
3080 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3082 gc_values.foreground = jailSquareColor;
3083 gc_values.background = jailSquareColor;
3084 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3086 gc_values.foreground = whitePieceColor;
3087 gc_values.background = darkSquareColor;
3088 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3090 gc_values.foreground = whitePieceColor;
3091 gc_values.background = lightSquareColor;
3092 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3094 gc_values.foreground = whitePieceColor;
3095 gc_values.background = jailSquareColor;
3096 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3098 gc_values.foreground = blackPieceColor;
3099 gc_values.background = darkSquareColor;
3100 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3102 gc_values.foreground = blackPieceColor;
3103 gc_values.background = lightSquareColor;
3104 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3106 gc_values.foreground = blackPieceColor;
3107 gc_values.background = jailSquareColor;
3108 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3112 void loadXIM(xim, xmask, filename, dest, mask)
3125 fp = fopen(filename, "rb");
3127 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3134 for (y=0; y<h; ++y) {
3135 for (x=0; x<h; ++x) {
3140 XPutPixel(xim, x, y, blackPieceColor);
3142 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3145 XPutPixel(xim, x, y, darkSquareColor);
3147 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3150 XPutPixel(xim, x, y, whitePieceColor);
3152 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3155 XPutPixel(xim, x, y, lightSquareColor);
3157 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3163 /* create Pixmap of piece */
3164 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3166 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3169 /* create Pixmap of clipmask
3170 Note: We assume the white/black pieces have the same
3171 outline, so we make only 6 masks. This is okay
3172 since the XPM clipmask routines do the same. */
3174 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3176 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3179 /* now create the 1-bit version */
3180 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3183 values.foreground = 1;
3184 values.background = 0;
3186 /* Don't use XtGetGC, not read only */
3187 maskGC = XCreateGC(xDisplay, *mask,
3188 GCForeground | GCBackground, &values);
3189 XCopyPlane(xDisplay, temp, *mask, maskGC,
3190 0, 0, squareSize, squareSize, 0, 0, 1);
3191 XFreePixmap(xDisplay, temp);
3196 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3198 void CreateXIMPieces()
3203 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3208 /* The XSynchronize calls were copied from CreatePieces.
3209 Not sure if needed, but can't hurt */
3210 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3213 /* temp needed by loadXIM() */
3214 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3215 0, 0, ss, ss, AllPlanes, XYPixmap);
3217 if (strlen(appData.pixmapDirectory) == 0) {
3221 if (appData.monoMode) {
3222 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3226 fprintf(stderr, _("\nLoading XIMs...\n"));
3228 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3229 fprintf(stderr, "%d", piece+1);
3230 for (kind=0; kind<4; kind++) {
3231 fprintf(stderr, ".");
3232 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3233 ExpandPathName(appData.pixmapDirectory),
3234 piece <= (int) WhiteKing ? "" : "w",
3235 pieceBitmapNames[piece],
3237 ximPieceBitmap[kind][piece] =
3238 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3239 0, 0, ss, ss, AllPlanes, XYPixmap);
3240 if (appData.debugMode)
3241 fprintf(stderr, _("(File:%s:) "), buf);
3242 loadXIM(ximPieceBitmap[kind][piece],
3244 &(xpmPieceBitmap2[kind][piece]),
3245 &(ximMaskPm2[piece]));
3246 if(piece <= (int)WhiteKing)
3247 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3249 fprintf(stderr," ");
3251 /* Load light and dark squares */
3252 /* If the LSQ and DSQ pieces don't exist, we will
3253 draw them with solid squares. */
3254 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3255 if (access(buf, 0) != 0) {
3259 fprintf(stderr, _("light square "));
3261 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3262 0, 0, ss, ss, AllPlanes, XYPixmap);
3263 if (appData.debugMode)
3264 fprintf(stderr, _("(File:%s:) "), buf);
3266 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3267 fprintf(stderr, _("dark square "));
3268 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3269 ExpandPathName(appData.pixmapDirectory), ss);
3270 if (appData.debugMode)
3271 fprintf(stderr, _("(File:%s:) "), buf);
3273 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3274 0, 0, ss, ss, AllPlanes, XYPixmap);
3275 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3276 xpmJailSquare = xpmLightSquare;
3278 fprintf(stderr, _("Done.\n"));
3280 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3284 void CreateXPMPieces()
3288 u_int ss = squareSize;
3290 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3291 XpmColorSymbol symbols[4];
3293 /* The XSynchronize calls were copied from CreatePieces.
3294 Not sure if needed, but can't hurt */
3295 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3297 /* Setup translations so piece colors match square colors */
3298 symbols[0].name = "light_piece";
3299 symbols[0].value = appData.whitePieceColor;
3300 symbols[1].name = "dark_piece";
3301 symbols[1].value = appData.blackPieceColor;
3302 symbols[2].name = "light_square";
3303 symbols[2].value = appData.lightSquareColor;
3304 symbols[3].name = "dark_square";
3305 symbols[3].value = appData.darkSquareColor;
3307 attr.valuemask = XpmColorSymbols;
3308 attr.colorsymbols = symbols;
3309 attr.numsymbols = 4;
3311 if (appData.monoMode) {
3312 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3316 if (strlen(appData.pixmapDirectory) == 0) {
3317 XpmPieces* pieces = builtInXpms;
3320 while (pieces->size != squareSize && pieces->size) pieces++;
3321 if (!pieces->size) {
3322 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3325 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3326 for (kind=0; kind<4; kind++) {
3328 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3329 pieces->xpm[piece][kind],
3330 &(xpmPieceBitmap2[kind][piece]),
3331 NULL, &attr)) != 0) {
3332 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3336 if(piece <= (int) WhiteKing)
3337 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3341 xpmJailSquare = xpmLightSquare;
3345 fprintf(stderr, _("\nLoading XPMs...\n"));
3348 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3349 fprintf(stderr, "%d ", piece+1);
3350 for (kind=0; kind<4; kind++) {
3351 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3352 ExpandPathName(appData.pixmapDirectory),
3353 piece > (int) WhiteKing ? "w" : "",
3354 pieceBitmapNames[piece],
3356 if (appData.debugMode) {
3357 fprintf(stderr, _("(File:%s:) "), buf);
3359 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3360 &(xpmPieceBitmap2[kind][piece]),
3361 NULL, &attr)) != 0) {
3362 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3363 // [HGM] missing: read of unorthodox piece failed; substitute King.
3364 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3365 ExpandPathName(appData.pixmapDirectory),
3367 if (appData.debugMode) {
3368 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3370 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3371 &(xpmPieceBitmap2[kind][piece]),
3375 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3380 if(piece <= (int) WhiteKing)
3381 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3384 /* Load light and dark squares */
3385 /* If the LSQ and DSQ pieces don't exist, we will
3386 draw them with solid squares. */
3387 fprintf(stderr, _("light square "));
3388 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3389 if (access(buf, 0) != 0) {
3393 if (appData.debugMode)
3394 fprintf(stderr, _("(File:%s:) "), buf);
3396 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3397 &xpmLightSquare, NULL, &attr)) != 0) {
3398 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3401 fprintf(stderr, _("dark square "));
3402 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3403 ExpandPathName(appData.pixmapDirectory), ss);
3404 if (appData.debugMode) {
3405 fprintf(stderr, _("(File:%s:) "), buf);
3407 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3408 &xpmDarkSquare, NULL, &attr)) != 0) {
3409 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3413 xpmJailSquare = xpmLightSquare;
3414 fprintf(stderr, _("Done.\n"));
3416 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3419 #endif /* HAVE_LIBXPM */
3422 /* No built-in bitmaps */
3427 u_int ss = squareSize;
3429 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3432 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3433 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3434 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3435 pieceBitmapNames[piece],
3436 ss, kind == SOLID ? 's' : 'o');
3437 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3438 if(piece <= (int)WhiteKing)
3439 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3443 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3447 /* With built-in bitmaps */
3450 BuiltInBits* bib = builtInBits;
3453 u_int ss = squareSize;
3455 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3458 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3460 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3461 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3462 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3463 pieceBitmapNames[piece],
3464 ss, kind == SOLID ? 's' : 'o');
3465 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3466 bib->bits[kind][piece], ss, ss);
3467 if(piece <= (int)WhiteKing)
3468 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3472 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3477 void ReadBitmap(pm, name, bits, wreq, hreq)
3480 unsigned char bits[];
3486 char msg[MSG_SIZ], fullname[MSG_SIZ];
3488 if (*appData.bitmapDirectory != NULLCHAR) {
3489 strcpy(fullname, appData.bitmapDirectory);
3490 strcat(fullname, "/");
3491 strcat(fullname, name);
3492 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3493 &w, &h, pm, &x_hot, &y_hot);
3494 fprintf(stderr, "load %s\n", name);
3495 if (errcode != BitmapSuccess) {
3497 case BitmapOpenFailed:
3498 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3500 case BitmapFileInvalid:
3501 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3503 case BitmapNoMemory:
3504 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3508 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3512 fprintf(stderr, _("%s: %s...using built-in\n"),
3514 } else if (w != wreq || h != hreq) {
3516 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3517 programName, fullname, w, h, wreq, hreq);
3523 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3532 if (lineGap == 0) return;
3534 /* [HR] Split this into 2 loops for non-square boards. */
3536 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3537 gridSegments[i].x1 = 0;
3538 gridSegments[i].x2 =
3539 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3540 gridSegments[i].y1 = gridSegments[i].y2
3541 = lineGap / 2 + (i * (squareSize + lineGap));
3544 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3545 gridSegments[j + i].y1 = 0;
3546 gridSegments[j + i].y2 =
3547 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3548 gridSegments[j + i].x1 = gridSegments[j + i].x2
3549 = lineGap / 2 + (j * (squareSize + lineGap));
3553 static void MenuBarSelect(w, addr, index)
3558 XtActionProc proc = (XtActionProc) addr;
3560 (proc)(NULL, NULL, NULL, NULL);
3563 void CreateMenuBarPopup(parent, name, mb)
3573 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3576 XtSetArg(args[j], XtNleftMargin, 20); j++;
3577 XtSetArg(args[j], XtNrightMargin, 20); j++;
3579 while (mi->string != NULL) {
3580 if (strcmp(mi->string, "----") == 0) {
3581 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3584 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3585 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3587 XtAddCallback(entry, XtNcallback,
3588 (XtCallbackProc) MenuBarSelect,
3589 (caddr_t) mi->proc);
3595 Widget CreateMenuBar(mb)
3599 Widget anchor, menuBar;
3601 char menuName[MSG_SIZ];
3604 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3605 XtSetArg(args[j], XtNvSpace, 0); j++;
3606 XtSetArg(args[j], XtNborderWidth, 0); j++;
3607 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3608 formWidget, args, j);
3610 while (mb->name != NULL) {
3611 strcpy(menuName, "menu");
3612 strcat(menuName, mb->name);
3614 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3617 shortName[0] = _(mb->name)[0];
3618 shortName[1] = NULLCHAR;
3619 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3622 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3625 XtSetArg(args[j], XtNborderWidth, 0); j++;
3626 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3628 CreateMenuBarPopup(menuBar, menuName, mb);
3634 Widget CreateButtonBar(mi)
3638 Widget button, buttonBar;
3642 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3644 XtSetArg(args[j], XtNhSpace, 0); j++;
3646 XtSetArg(args[j], XtNborderWidth, 0); j++;
3647 XtSetArg(args[j], XtNvSpace, 0); j++;
3648 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3649 formWidget, args, j);
3651 while (mi->string != NULL) {
3654 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3655 XtSetArg(args[j], XtNborderWidth, 0); j++;
3657 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3658 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3659 buttonBar, args, j);
3660 XtAddCallback(button, XtNcallback,
3661 (XtCallbackProc) MenuBarSelect,
3662 (caddr_t) mi->proc);
3669 CreatePieceMenu(name, color)
3676 ChessSquare selection;
3678 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3679 boardWidget, args, 0);
3681 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3682 String item = pieceMenuStrings[color][i];
3684 if (strcmp(item, "----") == 0) {
3685 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3688 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3689 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3691 selection = pieceMenuTranslation[color][i];
3692 XtAddCallback(entry, XtNcallback,
3693 (XtCallbackProc) PieceMenuSelect,
3694 (caddr_t) selection);
3695 if (selection == WhitePawn || selection == BlackPawn) {
3696 XtSetArg(args[0], XtNpopupOnEntry, entry);
3697 XtSetValues(menu, args, 1);
3710 ChessSquare selection;
3712 whitePieceMenu = CreatePieceMenu("menuW", 0);
3713 blackPieceMenu = CreatePieceMenu("menuB", 1);
3715 XtRegisterGrabAction(PieceMenuPopup, True,
3716 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3717 GrabModeAsync, GrabModeAsync);
3719 XtSetArg(args[0], XtNlabel, _("Drop"));
3720 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3721 boardWidget, args, 1);
3722 for (i = 0; i < DROP_MENU_SIZE; i++) {
3723 String item = dropMenuStrings[i];
3725 if (strcmp(item, "----") == 0) {
3726 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3729 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3730 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3732 selection = dropMenuTranslation[i];
3733 XtAddCallback(entry, XtNcallback,
3734 (XtCallbackProc) DropMenuSelect,
3735 (caddr_t) selection);
3740 void SetupDropMenu()
3748 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3749 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3750 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3751 dmEnables[i].piece);
3752 XtSetSensitive(entry, p != NULL || !appData.testLegality
3753 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3754 && !appData.icsActive));
3756 while (p && *p++ == dmEnables[i].piece) count++;
3757 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3759 XtSetArg(args[j], XtNlabel, label); j++;
3760 XtSetValues(entry, args, j);
3764 void PieceMenuPopup(w, event, params, num_params)
3768 Cardinal *num_params;
3770 String whichMenu; int menuNr;
3771 if (event->type == ButtonRelease)
3772 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3773 else if (event->type == ButtonPress)
3774 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3776 case 0: whichMenu = params[0]; break;
3777 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3779 case -1: if (errorUp) ErrorPopDown();
3782 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3785 static void PieceMenuSelect(w, piece, junk)
3790 if (pmFromX < 0 || pmFromY < 0) return;
3791 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3794 static void DropMenuSelect(w, piece, junk)
3799 if (pmFromX < 0 || pmFromY < 0) return;
3800 DropMenuEvent(piece, pmFromX, pmFromY);
3803 void WhiteClock(w, event, prms, nprms)
3809 if (gameMode == EditPosition || gameMode == IcsExamining) {
3810 SetWhiteToPlayEvent();
3811 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3816 void BlackClock(w, event, prms, nprms)
3822 if (gameMode == EditPosition || gameMode == IcsExamining) {
3823 SetBlackToPlayEvent();
3824 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3831 * If the user selects on a border boundary, return -1; if off the board,
3832 * return -2. Otherwise map the event coordinate to the square.
3834 int EventToSquare(x, limit)
3842 if ((x % (squareSize + lineGap)) >= squareSize)
3844 x /= (squareSize + lineGap);
3850 static void do_flash_delay(msec)
3856 static void drawHighlight(file, rank, gc)
3862 if (lineGap == 0 || appData.blindfold) return;
3865 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3866 (squareSize + lineGap);
3867 y = lineGap/2 + rank * (squareSize + lineGap);
3869 x = lineGap/2 + file * (squareSize + lineGap);
3870 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3871 (squareSize + lineGap);
3874 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3875 squareSize+lineGap, squareSize+lineGap);
3878 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3879 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3882 SetHighlights(fromX, fromY, toX, toY)
3883 int fromX, fromY, toX, toY;
3885 if (hi1X != fromX || hi1Y != fromY) {
3886 if (hi1X >= 0 && hi1Y >= 0) {
3887 drawHighlight(hi1X, hi1Y, lineGC);
3889 } // [HGM] first erase both, then draw new!
3890 if (hi2X != toX || hi2Y != toY) {
3891 if (hi2X >= 0 && hi2Y >= 0) {
3892 drawHighlight(hi2X, hi2Y, lineGC);
3895 if (hi1X != fromX || hi1Y != fromY) {
3896 if (fromX >= 0 && fromY >= 0) {
3897 drawHighlight(fromX, fromY, highlineGC);
3900 if (hi2X != toX || hi2Y != toY) {
3901 if (toX >= 0 && toY >= 0) {
3902 drawHighlight(toX, toY, highlineGC);
3914 SetHighlights(-1, -1, -1, -1);
3919 SetPremoveHighlights(fromX, fromY, toX, toY)
3920 int fromX, fromY, toX, toY;
3922 if (pm1X != fromX || pm1Y != fromY) {
3923 if (pm1X >= 0 && pm1Y >= 0) {
3924 drawHighlight(pm1X, pm1Y, lineGC);
3926 if (fromX >= 0 && fromY >= 0) {
3927 drawHighlight(fromX, fromY, prelineGC);
3930 if (pm2X != toX || pm2Y != toY) {
3931 if (pm2X >= 0 && pm2Y >= 0) {
3932 drawHighlight(pm2X, pm2Y, lineGC);
3934 if (toX >= 0 && toY >= 0) {
3935 drawHighlight(toX, toY, prelineGC);
3945 ClearPremoveHighlights()
3947 SetPremoveHighlights(-1, -1, -1, -1);
3950 static void BlankSquare(x, y, color, piece, dest)
3955 if (useImages && useImageSqs) {
3959 pm = xpmLightSquare;
3964 case 2: /* neutral */
3969 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
3970 squareSize, squareSize, x, y);
3980 case 2: /* neutral */
3985 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
3990 I split out the routines to draw a piece so that I could
3991 make a generic flash routine.
3993 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
3995 int square_color, x, y;
3998 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3999 switch (square_color) {
4001 case 2: /* neutral */
4003 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4004 ? *pieceToOutline(piece)
4005 : *pieceToSolid(piece),
4006 dest, bwPieceGC, 0, 0,
4007 squareSize, squareSize, x, y);
4010 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4011 ? *pieceToSolid(piece)
4012 : *pieceToOutline(piece),
4013 dest, wbPieceGC, 0, 0,
4014 squareSize, squareSize, x, y);
4019 static void monoDrawPiece(piece, square_color, x, y, dest)
4021 int square_color, x, y;
4024 switch (square_color) {
4026 case 2: /* neutral */
4028 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4029 ? *pieceToOutline(piece)
4030 : *pieceToSolid(piece),
4031 dest, bwPieceGC, 0, 0,
4032 squareSize, squareSize, x, y, 1);
4035 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4036 ? *pieceToSolid(piece)
4037 : *pieceToOutline(piece),
4038 dest, wbPieceGC, 0, 0,
4039 squareSize, squareSize, x, y, 1);
4044 static void colorDrawPiece(piece, square_color, x, y, dest)
4046 int square_color, x, y;
4049 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4050 switch (square_color) {
4052 XCopyPlane(xDisplay, *pieceToSolid(piece),
4053 dest, (int) piece < (int) BlackPawn
4054 ? wlPieceGC : blPieceGC, 0, 0,
4055 squareSize, squareSize, x, y, 1);
4058 XCopyPlane(xDisplay, *pieceToSolid(piece),
4059 dest, (int) piece < (int) BlackPawn
4060 ? wdPieceGC : bdPieceGC, 0, 0,
4061 squareSize, squareSize, x, y, 1);
4063 case 2: /* neutral */
4065 XCopyPlane(xDisplay, *pieceToSolid(piece),
4066 dest, (int) piece < (int) BlackPawn
4067 ? wjPieceGC : bjPieceGC, 0, 0,
4068 squareSize, squareSize, x, y, 1);
4073 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4075 int square_color, x, y;
4080 switch (square_color) {
4082 case 2: /* neutral */
4084 if ((int)piece < (int) BlackPawn) {
4092 if ((int)piece < (int) BlackPawn) {
4100 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4101 dest, wlPieceGC, 0, 0,
4102 squareSize, squareSize, x, y);
4105 typedef void (*DrawFunc)();
4107 DrawFunc ChooseDrawFunc()
4109 if (appData.monoMode) {
4110 if (DefaultDepth(xDisplay, xScreen) == 1) {
4111 return monoDrawPiece_1bit;
4113 return monoDrawPiece;
4117 return colorDrawPieceImage;
4119 return colorDrawPiece;
4123 /* [HR] determine square color depending on chess variant. */
4124 static int SquareColor(row, column)
4129 if (gameInfo.variant == VariantXiangqi) {
4130 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4132 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4134 } else if (row <= 4) {
4140 square_color = ((column + row) % 2) == 1;
4143 /* [hgm] holdings: next line makes all holdings squares light */
4144 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4146 return square_color;
4149 void DrawSquare(row, column, piece, do_flash)
4150 int row, column, do_flash;
4153 int square_color, x, y, direction, font_ascent, font_descent;
4156 XCharStruct overall;
4160 /* Calculate delay in milliseconds (2-delays per complete flash) */
4161 flash_delay = 500 / appData.flashRate;
4164 x = lineGap + ((BOARD_WIDTH-1)-column) *
4165 (squareSize + lineGap);
4166 y = lineGap + row * (squareSize + lineGap);
4168 x = lineGap + column * (squareSize + lineGap);
4169 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4170 (squareSize + lineGap);
4173 square_color = SquareColor(row, column);
4175 if ( // [HGM] holdings: blank out area between board and holdings
4176 column == BOARD_LEFT-1 || column == BOARD_RGHT
4177 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4178 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4179 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4181 // [HGM] print piece counts next to holdings
4182 string[1] = NULLCHAR;
4183 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4184 string[0] = '0' + piece;
4185 XTextExtents(countFontStruct, string, 1, &direction,
4186 &font_ascent, &font_descent, &overall);
4187 if (appData.monoMode) {
4188 XDrawImageString(xDisplay, xBoardWindow, countGC,
4189 x + squareSize - overall.width - 2,
4190 y + font_ascent + 1, string, 1);
4192 XDrawString(xDisplay, xBoardWindow, countGC,
4193 x + squareSize - overall.width - 2,
4194 y + font_ascent + 1, string, 1);
4197 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4198 string[0] = '0' + piece;
4199 XTextExtents(countFontStruct, string, 1, &direction,
4200 &font_ascent, &font_descent, &overall);
4201 if (appData.monoMode) {
4202 XDrawImageString(xDisplay, xBoardWindow, countGC,
4203 x + 2, y + font_ascent + 1, string, 1);
4205 XDrawString(xDisplay, xBoardWindow, countGC,
4206 x + 2, y + font_ascent + 1, string, 1);
4210 if (piece == EmptySquare || appData.blindfold) {
4211 BlankSquare(x, y, square_color, piece, xBoardWindow);
4213 drawfunc = ChooseDrawFunc();
4214 if (do_flash && appData.flashCount > 0) {
4215 for (i=0; i<appData.flashCount; ++i) {
4217 drawfunc(piece, square_color, x, y, xBoardWindow);
4218 XSync(xDisplay, False);
4219 do_flash_delay(flash_delay);
4221 BlankSquare(x, y, square_color, piece, xBoardWindow);
4222 XSync(xDisplay, False);
4223 do_flash_delay(flash_delay);
4226 drawfunc(piece, square_color, x, y, xBoardWindow);
4230 string[1] = NULLCHAR;
4231 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4232 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4233 string[0] = 'a' + column - BOARD_LEFT;
4234 XTextExtents(coordFontStruct, string, 1, &direction,
4235 &font_ascent, &font_descent, &overall);
4236 if (appData.monoMode) {
4237 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4238 x + squareSize - overall.width - 2,
4239 y + squareSize - font_descent - 1, string, 1);
4241 XDrawString(xDisplay, xBoardWindow, coordGC,
4242 x + squareSize - overall.width - 2,
4243 y + squareSize - font_descent - 1, string, 1);