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 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 RETSIGTYPE CmailSigHandler P((int sig));
237 RETSIGTYPE IntSigHandler P((int sig));
238 RETSIGTYPE TermSizeSigHandler P((int sig));
239 void CreateGCs P((void));
240 void CreateXIMPieces P((void));
241 void CreateXPMPieces P((void));
242 void CreatePieces P((void));
243 void CreatePieceMenus P((void));
244 Widget CreateMenuBar P((Menu *mb));
245 Widget CreateButtonBar P ((MenuItem *mi));
246 char *FindFont P((char *pattern, int targetPxlSize));
247 void PieceMenuPopup P((Widget w, XEvent *event,
248 String *params, Cardinal *num_params));
249 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
250 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
251 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
252 u_int wreq, u_int hreq));
253 void CreateGrid P((void));
254 int EventToSquare P((int x, int limit));
255 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
256 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
257 void HandleUserMove P((Widget w, XEvent *event,
258 String *prms, Cardinal *nprms));
259 void AnimateUserMove P((Widget w, XEvent * event,
260 String * params, Cardinal * nParams));
261 void HandlePV P((Widget w, XEvent * event,
262 String * params, Cardinal * nParams));
263 void WhiteClock P((Widget w, XEvent *event,
264 String *prms, Cardinal *nprms));
265 void BlackClock P((Widget w, XEvent *event,
266 String *prms, Cardinal *nprms));
267 void DrawPositionProc P((Widget w, XEvent *event,
268 String *prms, Cardinal *nprms));
269 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
271 void CommentPopUp P((char *title, char *label));
272 void CommentPopDown P((void));
273 void CommentCallback P((Widget w, XtPointer client_data,
274 XtPointer call_data));
275 void ICSInputBoxPopUp P((void));
276 void ICSInputBoxPopDown P((void));
277 void FileNamePopUp P((char *label, char *def,
278 FileProc proc, char *openMode));
279 void FileNamePopDown P((void));
280 void FileNameCallback P((Widget w, XtPointer client_data,
281 XtPointer call_data));
282 void FileNameAction P((Widget w, XEvent *event,
283 String *prms, Cardinal *nprms));
284 void AskQuestionReplyAction P((Widget w, XEvent *event,
285 String *prms, Cardinal *nprms));
286 void AskQuestionProc P((Widget w, XEvent *event,
287 String *prms, Cardinal *nprms));
288 void AskQuestionPopDown P((void));
289 void PromotionPopDown P((void));
290 void PromotionCallback P((Widget w, XtPointer client_data,
291 XtPointer call_data));
292 void EditCommentPopDown P((void));
293 void EditCommentCallback P((Widget w, XtPointer client_data,
294 XtPointer call_data));
295 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
296 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
297 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
298 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
300 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
302 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
304 void LoadPositionProc P((Widget w, XEvent *event,
305 String *prms, Cardinal *nprms));
306 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
308 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
310 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
312 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
314 void PastePositionProc P((Widget w, XEvent *event, String *prms,
316 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
317 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
318 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
319 void SavePositionProc P((Widget w, XEvent *event,
320 String *prms, Cardinal *nprms));
321 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
322 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
324 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
325 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
326 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
328 void MachineWhiteProc P((Widget w, XEvent *event,
329 String *prms, Cardinal *nprms));
330 void AnalyzeModeProc P((Widget w, XEvent *event,
331 String *prms, Cardinal *nprms));
332 void AnalyzeFileProc P((Widget w, XEvent *event,
333 String *prms, Cardinal *nprms));
334 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
336 void IcsClientProc P((Widget w, XEvent *event, String *prms,
338 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
339 void EditPositionProc P((Widget w, XEvent *event,
340 String *prms, Cardinal *nprms));
341 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
342 void EditCommentProc P((Widget w, XEvent *event,
343 String *prms, Cardinal *nprms));
344 void IcsInputBoxProc P((Widget w, XEvent *event,
345 String *prms, Cardinal *nprms));
346 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
347 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
348 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
349 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
350 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
351 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
352 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
353 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
354 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
355 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
356 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
357 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
358 void StopObservingProc P((Widget w, XEvent *event, String *prms,
360 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
362 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
365 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
369 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
371 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
372 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
374 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
376 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
378 void AutocommProc P((Widget w, XEvent *event, String *prms,
380 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void AutobsProc P((Widget w, XEvent *event, String *prms,
384 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
385 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
386 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
387 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
389 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
390 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
392 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
394 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
396 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
397 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
398 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
400 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
402 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
404 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
406 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
408 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
409 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
410 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
412 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
414 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
416 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
418 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
419 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
420 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
421 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
422 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
423 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
424 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
425 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
426 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
427 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
428 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
429 void DisplayMove P((int moveNumber));
430 void DisplayTitle P((char *title));
431 void ICSInitScript P((void));
432 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
433 void ErrorPopUp P((char *title, char *text, int modal));
434 void ErrorPopDown P((void));
435 static char *ExpandPathName P((char *path));
436 static void CreateAnimVars P((void));
437 static void DragPieceMove P((int x, int y));
438 static void DrawDragPiece P((void));
439 char *ModeToWidgetName P((GameMode mode));
440 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
442 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
443 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
444 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
445 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
446 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
447 void ShufflePopDown P(());
448 void EnginePopDown P(());
449 void UciPopDown P(());
450 void TimeControlPopDown P(());
451 void NewVariantPopDown P(());
452 void SettingsPopDown P(());
453 void update_ics_width P(());
454 int get_term_width P(());
455 int CopyMemoProc P(());
457 * XBoard depends on Xt R4 or higher
459 int xtVersion = XtSpecificationRelease;
464 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
465 jailSquareColor, highlightSquareColor, premoveHighlightColor;
466 Pixel lowTimeWarningColor;
467 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
468 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
469 wjPieceGC, bjPieceGC, prelineGC, countGC;
470 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
471 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
472 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
473 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
474 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
475 ICSInputShell, fileNameShell, askQuestionShell;
476 Widget historyShell, evalGraphShell, gameListShell;
477 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
478 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
479 Font clockFontID, coordFontID, countFontID;
480 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
481 XtAppContext appContext;
483 char *oldICSInteractionTitle;
487 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
489 Position commentX = -1, commentY = -1;
490 Dimension commentW, commentH;
491 typedef unsigned int BoardSize;
493 Boolean chessProgram;
495 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
496 int squareSize, smallLayout = 0, tinyLayout = 0,
497 marginW, marginH, // [HGM] for run-time resizing
498 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
499 ICSInputBoxUp = False, askQuestionUp = False,
500 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
501 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
502 Pixel timerForegroundPixel, timerBackgroundPixel;
503 Pixel buttonForegroundPixel, buttonBackgroundPixel;
504 char *chessDir, *programName, *programVersion,
505 *gameCopyFilename, *gamePasteFilename;
506 Boolean alwaysOnTop = False;
507 Boolean saveSettingsOnExit;
508 char *settingsFileName;
509 char *icsTextMenuString;
511 char *firstChessProgramNames;
512 char *secondChessProgramNames;
514 WindowPlacement wpMain;
515 WindowPlacement wpConsole;
516 WindowPlacement wpComment;
517 WindowPlacement wpMoveHistory;
518 WindowPlacement wpEvalGraph;
519 WindowPlacement wpEngineOutput;
520 WindowPlacement wpGameList;
521 WindowPlacement wpTags;
525 Pixmap pieceBitmap[2][(int)BlackPawn];
526 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
527 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
528 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
529 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
530 int useImages, useImageSqs;
531 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
532 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
533 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
534 XImage *ximLightSquare, *ximDarkSquare;
537 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
538 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
540 #define White(piece) ((int)(piece) < (int)BlackPawn)
542 /* Variables for doing smooth animation. This whole thing
543 would be much easier if the board was double-buffered,
544 but that would require a fairly major rewrite. */
549 GC blitGC, pieceGC, outlineGC;
550 XPoint startSquare, prevFrame, mouseDelta;
554 int startBoardX, startBoardY;
557 /* There can be two pieces being animated at once: a player
558 can begin dragging a piece before the remote opponent has moved. */
560 static AnimState game, player;
562 /* Bitmaps for use as masks when drawing XPM pieces.
563 Need one for each black and white piece. */
564 static Pixmap xpmMask[BlackKing + 1];
566 /* This magic number is the number of intermediate frames used
567 in each half of the animation. For short moves it's reduced
568 by 1. The total number of frames will be factor * 2 + 1. */
571 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
573 MenuItem fileMenu[] = {
574 {N_("New Game"), ResetProc},
575 {N_("New Shuffle Game ..."), ShuffleMenuProc},
576 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
577 {"----", NothingProc},
578 {N_("Load Game"), LoadGameProc},
579 {N_("Load Next Game"), LoadNextGameProc},
580 {N_("Load Previous Game"), LoadPrevGameProc},
581 {N_("Reload Same Game"), ReloadGameProc},
582 {N_("Save Game"), SaveGameProc},
583 {"----", NothingProc},
584 {N_("Copy Game"), CopyGameProc},
585 {N_("Paste Game"), PasteGameProc},
586 {"----", NothingProc},
587 {N_("Load Position"), LoadPositionProc},
588 {N_("Load Next Position"), LoadNextPositionProc},
589 {N_("Load Previous Position"), LoadPrevPositionProc},
590 {N_("Reload Same Position"), ReloadPositionProc},
591 {N_("Save Position"), SavePositionProc},
592 {"----", NothingProc},
593 {N_("Copy Position"), CopyPositionProc},
594 {N_("Paste Position"), PastePositionProc},
595 {"----", NothingProc},
596 {N_("Mail Move"), MailMoveProc},
597 {N_("Reload CMail Message"), ReloadCmailMsgProc},
598 {"----", NothingProc},
599 {N_("Exit"), QuitProc},
603 MenuItem modeMenu[] = {
604 {N_("Machine White"), MachineWhiteProc},
605 {N_("Machine Black"), MachineBlackProc},
606 {N_("Two Machines"), TwoMachinesProc},
607 {N_("Analysis Mode"), AnalyzeModeProc},
608 {N_("Analyze File"), AnalyzeFileProc },
609 {N_("ICS Client"), IcsClientProc},
610 {N_("Edit Game"), EditGameProc},
611 {N_("Edit Position"), EditPositionProc},
612 {N_("Training"), TrainingProc},
613 {"----", NothingProc},
614 {N_("Show Engine Output"), EngineOutputProc},
615 {N_("Show Evaluation Graph"), EvalGraphProc},
616 {N_("Show Game List"), ShowGameListProc},
617 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
618 {"----", NothingProc},
619 {N_("Edit Tags"), EditTagsProc},
620 {N_("Edit Comment"), EditCommentProc},
621 {N_("ICS Input Box"), IcsInputBoxProc},
622 {N_("Pause"), PauseProc},
626 MenuItem actionMenu[] = {
627 {N_("Accept"), AcceptProc},
628 {N_("Decline"), DeclineProc},
629 {N_("Rematch"), RematchProc},
630 {"----", NothingProc},
631 {N_("Call Flag"), CallFlagProc},
632 {N_("Draw"), DrawProc},
633 {N_("Adjourn"), AdjournProc},
634 {N_("Abort"), AbortProc},
635 {N_("Resign"), ResignProc},
636 {"----", NothingProc},
637 {N_("Stop Observing"), StopObservingProc},
638 {N_("Stop Examining"), StopExaminingProc},
639 {"----", NothingProc},
640 {N_("Adjudicate to White"), AdjuWhiteProc},
641 {N_("Adjudicate to Black"), AdjuBlackProc},
642 {N_("Adjudicate Draw"), AdjuDrawProc},
646 MenuItem stepMenu[] = {
647 {N_("Backward"), BackwardProc},
648 {N_("Forward"), ForwardProc},
649 {N_("Back to Start"), ToStartProc},
650 {N_("Forward to End"), ToEndProc},
651 {N_("Revert"), RevertProc},
652 {N_("Truncate Game"), TruncateGameProc},
653 {"----", NothingProc},
654 {N_("Move Now"), MoveNowProc},
655 {N_("Retract Move"), RetractMoveProc},
659 MenuItem optionsMenu[] = {
660 {N_("Flip View"), FlipViewProc},
661 {"----", NothingProc},
662 {N_("Adjudications ..."), EngineMenuProc},
663 {N_("General Settings ..."), UciMenuProc},
664 {N_("Engine #1 Settings ..."), FirstSettingsProc},
665 {N_("Engine #2 Settings ..."), SecondSettingsProc},
666 {N_("Time Control ..."), TimeControlProc},
667 {"----", NothingProc},
668 {N_("Always Queen"), AlwaysQueenProc},
669 {N_("Animate Dragging"), AnimateDraggingProc},
670 {N_("Animate Moving"), AnimateMovingProc},
671 {N_("Auto Comment"), AutocommProc},
672 {N_("Auto Flag"), AutoflagProc},
673 {N_("Auto Flip View"), AutoflipProc},
674 {N_("Auto Observe"), AutobsProc},
675 {N_("Auto Raise Board"), AutoraiseProc},
676 {N_("Auto Save"), AutosaveProc},
677 {N_("Blindfold"), BlindfoldProc},
678 {N_("Flash Moves"), FlashMovesProc},
679 {N_("Get Move List"), GetMoveListProc},
681 {N_("Highlight Dragging"), HighlightDraggingProc},
683 {N_("Highlight Last Move"), HighlightLastMoveProc},
684 {N_("Move Sound"), MoveSoundProc},
685 {N_("ICS Alarm"), IcsAlarmProc},
686 {N_("Old Save Style"), OldSaveStyleProc},
687 {N_("Periodic Updates"), PeriodicUpdatesProc},
688 {N_("Ponder Next Move"), PonderNextMoveProc},
689 {N_("Popup Exit Message"), PopupExitMessageProc},
690 {N_("Popup Move Errors"), PopupMoveErrorsProc},
691 {N_("Premove"), PremoveProc},
692 {N_("Quiet Play"), QuietPlayProc},
693 {N_("Show Coords"), ShowCoordsProc},
694 {N_("Hide Thinking"), HideThinkingProc},
695 {N_("Test Legality"), TestLegalityProc},
696 {"----", NothingProc},
697 {N_("Save Settings Now"), SaveSettingsProc},
698 {N_("Save Settings on Exit"), SaveOnExitProc},
702 MenuItem helpMenu[] = {
703 {N_("Info XBoard"), InfoProc},
704 {N_("Man XBoard"), ManProc},
705 {"----", NothingProc},
706 {N_("Hint"), HintProc},
707 {N_("Book"), BookProc},
708 {"----", NothingProc},
709 {N_("About XBoard"), AboutProc},
714 {N_("File"), fileMenu},
715 {N_("Mode"), modeMenu},
716 {N_("Action"), actionMenu},
717 {N_("Step"), stepMenu},
718 {N_("Options"), optionsMenu},
719 {N_("Help"), helpMenu},
723 #define PAUSE_BUTTON N_("P")
724 MenuItem buttonBar[] = {
727 {PAUSE_BUTTON, PauseProc},
733 #define PIECE_MENU_SIZE 18
734 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
735 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
736 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
737 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
738 N_("Empty square"), N_("Clear board") },
739 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
740 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
741 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
742 N_("Empty square"), N_("Clear board") }
744 /* must be in same order as PieceMenuStrings! */
745 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
746 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
747 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
748 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
749 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
750 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
751 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
752 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
753 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
756 #define DROP_MENU_SIZE 6
757 String dropMenuStrings[DROP_MENU_SIZE] = {
758 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
760 /* must be in same order as PieceMenuStrings! */
761 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
762 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
763 WhiteRook, WhiteQueen
771 DropMenuEnables dmEnables[] = {
789 { XtNborderWidth, 0 },
790 { XtNdefaultDistance, 0 },
794 { XtNborderWidth, 0 },
795 { XtNresizable, (XtArgVal) True },
799 { XtNborderWidth, 0 },
805 { XtNjustify, (XtArgVal) XtJustifyRight },
806 { XtNlabel, (XtArgVal) "..." },
807 { XtNresizable, (XtArgVal) True },
808 { XtNresize, (XtArgVal) False }
811 Arg messageArgs[] = {
812 { XtNjustify, (XtArgVal) XtJustifyLeft },
813 { XtNlabel, (XtArgVal) "..." },
814 { XtNresizable, (XtArgVal) True },
815 { XtNresize, (XtArgVal) False }
819 { XtNborderWidth, 0 },
820 { XtNjustify, (XtArgVal) XtJustifyLeft }
823 XtResource clientResources[] = {
824 { "flashCount", "flashCount", XtRInt, sizeof(int),
825 XtOffset(AppDataPtr, flashCount), XtRImmediate,
826 (XtPointer) FLASH_COUNT },
829 XrmOptionDescRec shellOptions[] = {
830 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
831 { "-flash", "flashCount", XrmoptionNoArg, "3" },
832 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
835 XtActionsRec boardActions[] = {
836 { "DrawPosition", DrawPositionProc },
837 { "HandleUserMove", HandleUserMove },
838 { "AnimateUserMove", AnimateUserMove },
839 { "HandlePV", HandlePV },
840 { "UnLoadPV", UnLoadPV },
841 { "FileNameAction", FileNameAction },
842 { "AskQuestionProc", AskQuestionProc },
843 { "AskQuestionReplyAction", AskQuestionReplyAction },
844 { "PieceMenuPopup", PieceMenuPopup },
845 { "WhiteClock", WhiteClock },
846 { "BlackClock", BlackClock },
847 { "Iconify", Iconify },
848 { "ResetProc", ResetProc },
849 { "LoadGameProc", LoadGameProc },
850 { "LoadNextGameProc", LoadNextGameProc },
851 { "LoadPrevGameProc", LoadPrevGameProc },
852 { "LoadSelectedProc", LoadSelectedProc },
853 { "ReloadGameProc", ReloadGameProc },
854 { "LoadPositionProc", LoadPositionProc },
855 { "LoadNextPositionProc", LoadNextPositionProc },
856 { "LoadPrevPositionProc", LoadPrevPositionProc },
857 { "ReloadPositionProc", ReloadPositionProc },
858 { "CopyPositionProc", CopyPositionProc },
859 { "PastePositionProc", PastePositionProc },
860 { "CopyGameProc", CopyGameProc },
861 { "PasteGameProc", PasteGameProc },
862 { "SaveGameProc", SaveGameProc },
863 { "SavePositionProc", SavePositionProc },
864 { "MailMoveProc", MailMoveProc },
865 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
866 { "QuitProc", QuitProc },
867 { "MachineWhiteProc", MachineWhiteProc },
868 { "MachineBlackProc", MachineBlackProc },
869 { "AnalysisModeProc", AnalyzeModeProc },
870 { "AnalyzeFileProc", AnalyzeFileProc },
871 { "TwoMachinesProc", TwoMachinesProc },
872 { "IcsClientProc", IcsClientProc },
873 { "EditGameProc", EditGameProc },
874 { "EditPositionProc", EditPositionProc },
875 { "TrainingProc", EditPositionProc },
876 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
877 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
878 { "ShowGameListProc", ShowGameListProc },
879 { "ShowMoveListProc", HistoryShowProc},
880 { "EditTagsProc", EditCommentProc },
881 { "EditCommentProc", EditCommentProc },
882 { "IcsAlarmProc", IcsAlarmProc },
883 { "IcsInputBoxProc", IcsInputBoxProc },
884 { "PauseProc", PauseProc },
885 { "AcceptProc", AcceptProc },
886 { "DeclineProc", DeclineProc },
887 { "RematchProc", RematchProc },
888 { "CallFlagProc", CallFlagProc },
889 { "DrawProc", DrawProc },
890 { "AdjournProc", AdjournProc },
891 { "AbortProc", AbortProc },
892 { "ResignProc", ResignProc },
893 { "AdjuWhiteProc", AdjuWhiteProc },
894 { "AdjuBlackProc", AdjuBlackProc },
895 { "AdjuDrawProc", AdjuDrawProc },
896 { "EnterKeyProc", EnterKeyProc },
897 { "StopObservingProc", StopObservingProc },
898 { "StopExaminingProc", StopExaminingProc },
899 { "BackwardProc", BackwardProc },
900 { "ForwardProc", ForwardProc },
901 { "ToStartProc", ToStartProc },
902 { "ToEndProc", ToEndProc },
903 { "RevertProc", RevertProc },
904 { "TruncateGameProc", TruncateGameProc },
905 { "MoveNowProc", MoveNowProc },
906 { "RetractMoveProc", RetractMoveProc },
907 { "AlwaysQueenProc", AlwaysQueenProc },
908 { "AnimateDraggingProc", AnimateDraggingProc },
909 { "AnimateMovingProc", AnimateMovingProc },
910 { "AutoflagProc", AutoflagProc },
911 { "AutoflipProc", AutoflipProc },
912 { "AutobsProc", AutobsProc },
913 { "AutoraiseProc", AutoraiseProc },
914 { "AutosaveProc", AutosaveProc },
915 { "BlindfoldProc", BlindfoldProc },
916 { "FlashMovesProc", FlashMovesProc },
917 { "FlipViewProc", FlipViewProc },
918 { "GetMoveListProc", GetMoveListProc },
920 { "HighlightDraggingProc", HighlightDraggingProc },
922 { "HighlightLastMoveProc", HighlightLastMoveProc },
923 { "IcsAlarmProc", IcsAlarmProc },
924 { "MoveSoundProc", MoveSoundProc },
925 { "OldSaveStyleProc", OldSaveStyleProc },
926 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
927 { "PonderNextMoveProc", PonderNextMoveProc },
928 { "PopupExitMessageProc", PopupExitMessageProc },
929 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
930 { "PremoveProc", PremoveProc },
931 { "QuietPlayProc", QuietPlayProc },
932 { "ShowCoordsProc", ShowCoordsProc },
933 { "ShowThinkingProc", ShowThinkingProc },
934 { "HideThinkingProc", HideThinkingProc },
935 { "TestLegalityProc", TestLegalityProc },
936 { "SaveSettingsProc", SaveSettingsProc },
937 { "SaveOnExitProc", SaveOnExitProc },
938 { "InfoProc", InfoProc },
939 { "ManProc", ManProc },
940 { "HintProc", HintProc },
941 { "BookProc", BookProc },
942 { "AboutGameProc", AboutGameProc },
943 { "AboutProc", AboutProc },
944 { "DebugProc", DebugProc },
945 { "NothingProc", NothingProc },
946 { "CommentPopDown", (XtActionProc) CommentPopDown },
947 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
948 { "TagsPopDown", (XtActionProc) TagsPopDown },
949 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
950 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
951 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
952 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
953 { "GameListPopDown", (XtActionProc) GameListPopDown },
954 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
955 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
956 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
957 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
958 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
959 { "EnginePopDown", (XtActionProc) EnginePopDown },
960 { "UciPopDown", (XtActionProc) UciPopDown },
961 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
962 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
963 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
964 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
967 char globalTranslations[] =
968 ":<Key>R: ResignProc() \n \
969 :<Key>r: ResetProc() \n \
970 :<Key>g: LoadGameProc() \n \
971 :<Key>N: LoadNextGameProc() \n \
972 :<Key>P: LoadPrevGameProc() \n \
973 :<Key>Q: QuitProc() \n \
974 :<Key>F: ToEndProc() \n \
975 :<Key>f: ForwardProc() \n \
976 :<Key>B: ToStartProc() \n \
977 :<Key>b: BackwardProc() \n \
978 :<Key>p: PauseProc() \n \
979 :<Key>d: DrawProc() \n \
980 :<Key>t: CallFlagProc() \n \
981 :<Key>i: Iconify() \n \
982 :<Key>c: Iconify() \n \
983 :<Key>v: FlipViewProc() \n \
984 <KeyDown>Control_L: BackwardProc() \n \
985 <KeyUp>Control_L: ForwardProc() \n \
986 <KeyDown>Control_R: BackwardProc() \n \
987 <KeyUp>Control_R: ForwardProc() \n \
988 Shift<Key>1: AskQuestionProc(\"Direct command\",\
989 \"Send to chess program:\",,1) \n \
990 Shift<Key>2: AskQuestionProc(\"Direct command\",\
991 \"Send to second chess program:\",,2) \n";
993 char boardTranslations[] =
994 "<Btn1Down>: HandleUserMove() \n \
995 <Btn1Up>: HandleUserMove() \n \
996 <Btn1Motion>: AnimateUserMove() \n \
997 <Btn3Motion>: HandlePV() \n \
998 <Btn3Up>: UnLoadPV() \n \
999 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1000 PieceMenuPopup(menuB) \n \
1001 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1002 PieceMenuPopup(menuW) \n \
1003 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1004 PieceMenuPopup(menuW) \n \
1005 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1006 PieceMenuPopup(menuB) \n";
1008 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1009 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1011 char ICSInputTranslations[] =
1012 "<Key>Return: EnterKeyProc() \n";
1014 String xboardResources[] = {
1015 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1016 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1017 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1022 /* Max possible square size */
1023 #define MAXSQSIZE 256
1025 static int xpm_avail[MAXSQSIZE];
1027 #ifdef HAVE_DIR_STRUCT
1029 /* Extract piece size from filename */
1031 xpm_getsize(name, len, ext)
1042 if ((p=strchr(name, '.')) == NULL ||
1043 StrCaseCmp(p+1, ext) != 0)
1049 while (*p && isdigit(*p))
1056 /* Setup xpm_avail */
1058 xpm_getavail(dirname, ext)
1066 for (i=0; i<MAXSQSIZE; ++i)
1069 if (appData.debugMode)
1070 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1072 dir = opendir(dirname);
1075 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1076 programName, dirname);
1080 while ((ent=readdir(dir)) != NULL) {
1081 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1082 if (i > 0 && i < MAXSQSIZE)
1092 xpm_print_avail(fp, ext)
1098 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1099 for (i=1; i<MAXSQSIZE; ++i) {
1105 /* Return XPM piecesize closest to size */
1107 xpm_closest_to(dirname, size, ext)
1113 int sm_diff = MAXSQSIZE;
1117 xpm_getavail(dirname, ext);
1119 if (appData.debugMode)
1120 xpm_print_avail(stderr, ext);
1122 for (i=1; i<MAXSQSIZE; ++i) {
1125 diff = (diff<0) ? -diff : diff;
1126 if (diff < sm_diff) {
1134 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1140 #else /* !HAVE_DIR_STRUCT */
1141 /* If we are on a system without a DIR struct, we can't
1142 read the directory, so we can't collect a list of
1143 filenames, etc., so we can't do any size-fitting. */
1145 xpm_closest_to(dirname, size, ext)
1150 fprintf(stderr, _("\
1151 Warning: No DIR structure found on this system --\n\
1152 Unable to autosize for XPM/XIM pieces.\n\
1153 Please report this error to frankm@hiwaay.net.\n\
1154 Include system type & operating system in message.\n"));
1157 #endif /* HAVE_DIR_STRUCT */
1159 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1160 "magenta", "cyan", "white" };
1164 TextColors textColors[(int)NColorClasses];
1166 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1168 parse_color(str, which)
1172 char *p, buf[100], *d;
1175 if (strlen(str) > 99) /* watch bounds on buf */
1180 for (i=0; i<which; ++i) {
1187 /* Could be looking at something like:
1189 .. in which case we want to stop on a comma also */
1190 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1194 return -1; /* Use default for empty field */
1197 if (which == 2 || isdigit(*p))
1200 while (*p && isalpha(*p))
1205 for (i=0; i<8; ++i) {
1206 if (!StrCaseCmp(buf, cnames[i]))
1207 return which? (i+40) : (i+30);
1209 if (!StrCaseCmp(buf, "default")) return -1;
1211 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1216 parse_cpair(cc, str)
1220 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1221 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1226 /* bg and attr are optional */
1227 textColors[(int)cc].bg = parse_color(str, 1);
1228 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1229 textColors[(int)cc].attr = 0;
1235 /* Arrange to catch delete-window events */
1236 Atom wm_delete_window;
1238 CatchDeleteWindow(Widget w, String procname)
1241 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1242 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1243 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1250 XtSetArg(args[0], XtNiconic, False);
1251 XtSetValues(shellWidget, args, 1);
1253 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1256 //---------------------------------------------------------------------------------------------------------
1257 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1260 #define CW_USEDEFAULT (1<<31)
1261 #define ICS_TEXT_MENU_SIZE 90
1262 #define DEBUG_FILE "xboard.debug"
1263 #define SetCurrentDirectory chdir
1264 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1268 // these two must some day move to frontend.h, when they are implemented
1269 Boolean GameListIsUp();
1271 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1274 // front-end part of option handling
1276 // [HGM] This platform-dependent table provides the location for storing the color info
1277 extern char *crWhite, * crBlack;
1281 &appData.whitePieceColor,
1282 &appData.blackPieceColor,
1283 &appData.lightSquareColor,
1284 &appData.darkSquareColor,
1285 &appData.highlightSquareColor,
1286 &appData.premoveHighlightColor,
1287 &appData.lowTimeWarningColor,
1299 ParseFont(char *name, int number)
1300 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1302 case 0: // CLOCK_FONT
1303 appData.clockFont = strdup(name);
1305 case 1: // MESSAGE_FONT
1306 appData.font = strdup(name);
1308 case 2: // COORD_FONT
1309 appData.coordFont = strdup(name);
1318 { // only 2 fonts currently
1319 appData.clockFont = CLOCK_FONT_NAME;
1320 appData.coordFont = COORD_FONT_NAME;
1321 appData.font = DEFAULT_FONT_NAME;
1326 { // no-op, until we identify the code for this already in XBoard and move it here
1330 ParseColor(int n, char *name)
1331 { // in XBoard, just copy the color-name string
1332 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1336 ParseTextAttribs(ColorClass cc, char *s)
1338 (&appData.colorShout)[cc] = strdup(s);
1342 ParseBoardSize(void *addr, char *name)
1344 appData.boardSize = strdup(name);
1349 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1353 SetCommPortDefaults()
1354 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1357 // [HGM] args: these three cases taken out to stay in front-end
1359 SaveFontArg(FILE *f, ArgDescriptor *ad)
1362 switch((int)ad->argLoc) {
1363 case 0: // CLOCK_FONT
1364 name = appData.clockFont;
1366 case 1: // MESSAGE_FONT
1367 name = appData.font;
1369 case 2: // COORD_FONT
1370 name = appData.coordFont;
1375 // Do not save fonts for now, as the saved font would be board-size specific
1376 // and not suitable for a re-start at another board size
1377 // fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, name);
1382 { // nothing to do, as the sounds are at all times represented by their text-string names already
1386 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1387 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1388 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1392 SaveColor(FILE *f, ArgDescriptor *ad)
1393 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1394 if(colorVariable[(int)ad->argLoc])
1395 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1399 SaveBoardSize(FILE *f, char *name, void *addr)
1400 { // wrapper to shield back-end from BoardSize & sizeInfo
1401 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1405 ParseCommPortSettings(char *s)
1406 { // no such option in XBoard (yet)
1409 extern Widget engineOutputShell;
1410 extern Widget tagsShell, editTagsShell;
1412 GetActualPlacement(Widget wg, WindowPlacement *wp)
1422 XtSetArg(args[i], XtNx, &x); i++;
1423 XtSetArg(args[i], XtNy, &y); i++;
1424 XtSetArg(args[i], XtNwidth, &w); i++;
1425 XtSetArg(args[i], XtNheight, &h); i++;
1426 XtGetValues(wg, args, i);
1435 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1436 // In XBoard this will have to wait until awareness of window parameters is implemented
1437 GetActualPlacement(shellWidget, &wpMain);
1438 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1439 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1440 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1441 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1442 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1443 else GetActualPlacement(editShell, &wpComment);
1444 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1445 else GetActualPlacement(editTagsShell, &wpTags);
1449 PrintCommPortSettings(FILE *f, char *name)
1450 { // This option does not exist in XBoard
1454 MySearchPath(char *installDir, char *name, char *fullname)
1455 { // just append installDir and name. Perhaps ExpandPath should be used here?
1456 name = ExpandPathName(name);
1457 if(name && name[0] == '/') strcpy(fullname, name); else {
1458 sprintf(fullname, "%s%c%s", installDir, '/', name);
1464 MyGetFullPathName(char *name, char *fullname)
1465 { // should use ExpandPath?
1466 name = ExpandPathName(name);
1467 strcpy(fullname, name);
1472 EnsureOnScreen(int *x, int *y, int minX, int minY)
1479 { // [HGM] args: allows testing if main window is realized from back-end
1480 return xBoardWindow != 0;
1484 PopUpStartupDialog()
1485 { // start menu not implemented in XBoard
1488 ConvertToLine(int argc, char **argv)
1490 static char line[128*1024], buf[1024];
1494 for(i=1; i<argc; i++) {
1495 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1496 && argv[i][0] != '{' )
1497 sprintf(buf, "{%s} ", argv[i]);
1498 else sprintf(buf, "%s ", argv[i]);
1501 line[strlen(line)-1] = NULLCHAR;
1505 //--------------------------------------------------------------------------------------------
1508 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1510 #define BoardSize int
1511 void InitDrawingSizes(BoardSize boardSize, int flags)
1512 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1513 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1515 XtGeometryResult gres;
1518 if(!formWidget) return;
1521 * Enable shell resizing.
1523 shellArgs[0].value = (XtArgVal) &w;
1524 shellArgs[1].value = (XtArgVal) &h;
1525 XtGetValues(shellWidget, shellArgs, 2);
1527 shellArgs[4].value = 2*w; shellArgs[2].value = 10;
1528 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1529 XtSetValues(shellWidget, &shellArgs[2], 4);
1531 XtSetArg(args[0], XtNdefaultDistance, &sep);
1532 XtGetValues(formWidget, args, 1);
1534 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1535 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1538 XtSetArg(args[0], XtNwidth, boardWidth);
1539 XtSetArg(args[1], XtNheight, boardHeight);
1540 XtSetValues(boardWidget, args, 2);
1542 timerWidth = (boardWidth - sep) / 2;
1543 XtSetArg(args[0], XtNwidth, timerWidth);
1544 XtSetValues(whiteTimerWidget, args, 1);
1545 XtSetValues(blackTimerWidget, args, 1);
1547 XawFormDoLayout(formWidget, False);
1549 if (appData.titleInWindow) {
1551 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1552 XtSetArg(args[i], XtNheight, &h); i++;
1553 XtGetValues(titleWidget, args, i);
1555 w = boardWidth - 2*bor;
1557 XtSetArg(args[0], XtNwidth, &w);
1558 XtGetValues(menuBarWidget, args, 1);
1559 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1562 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1563 if (gres != XtGeometryYes && appData.debugMode) {
1565 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1566 programName, gres, w, h, wr, hr);
1570 XawFormDoLayout(formWidget, True);
1573 * Inhibit shell resizing.
1575 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW;
1576 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1577 shellArgs[4].value = shellArgs[2].value = w;
1578 shellArgs[5].value = shellArgs[3].value = h;
1579 XtSetValues(shellWidget, &shellArgs[0], 6);
1581 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1584 for(i=0; i<4; i++) {
1586 for(p=0; p<=(int)WhiteKing; p++)
1587 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1588 if(gameInfo.variant == VariantShogi) {
1589 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1590 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1591 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1592 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1593 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1596 if(gameInfo.variant == VariantGothic) {
1597 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1601 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1602 for(p=0; p<=(int)WhiteKing; p++)
1603 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1604 if(gameInfo.variant == VariantShogi) {
1605 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1606 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1607 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1608 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1609 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1612 if(gameInfo.variant == VariantGothic) {
1613 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1619 for(i=0; i<2; i++) {
1621 for(p=0; p<=(int)WhiteKing; p++)
1622 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1623 if(gameInfo.variant == VariantShogi) {
1624 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1625 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1626 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1627 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1628 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1631 if(gameInfo.variant == VariantGothic) {
1632 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1643 void EscapeExpand(char *p, char *q)
1644 { // [HGM] initstring: routine to shape up string arguments
1645 while(*p++ = *q++) if(p[-1] == '\\')
1647 case 'n': p[-1] = '\n'; break;
1648 case 'r': p[-1] = '\r'; break;
1649 case 't': p[-1] = '\t'; break;
1650 case '\\': p[-1] = '\\'; break;
1651 case 0: *p = 0; return;
1652 default: p[-1] = q[-1]; break;
1661 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1662 XSetWindowAttributes window_attributes;
1664 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1665 XrmValue vFrom, vTo;
1666 XtGeometryResult gres;
1669 int forceMono = False;
1671 srandom(time(0)); // [HGM] book: make random truly random
1673 setbuf(stdout, NULL);
1674 setbuf(stderr, NULL);
1677 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1678 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1682 programName = strrchr(argv[0], '/');
1683 if (programName == NULL)
1684 programName = argv[0];
1689 XtSetLanguageProc(NULL, NULL, NULL);
1690 bindtextdomain(PACKAGE, LOCALEDIR);
1691 textdomain(PACKAGE);
1695 XtAppInitialize(&appContext, "XBoard", shellOptions,
1696 XtNumber(shellOptions),
1697 &argc, argv, xboardResources, NULL, 0);
1698 appData.boardSize = "";
1699 InitAppData(ConvertToLine(argc, argv));
1701 if (p == NULL) p = "/tmp";
1702 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1703 gameCopyFilename = (char*) malloc(i);
1704 gamePasteFilename = (char*) malloc(i);
1705 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1706 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1708 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1709 clientResources, XtNumber(clientResources),
1712 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1713 static char buf[MSG_SIZ];
1714 EscapeExpand(buf, appData.initString);
1715 appData.initString = strdup(buf);
1716 EscapeExpand(buf, appData.secondInitString);
1717 appData.secondInitString = strdup(buf);
1718 EscapeExpand(buf, appData.firstComputerString);
1719 appData.firstComputerString = strdup(buf);
1720 EscapeExpand(buf, appData.secondComputerString);
1721 appData.secondComputerString = strdup(buf);
1724 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1727 if (chdir(chessDir) != 0) {
1728 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1734 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1735 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1736 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1737 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1740 setbuf(debugFP, NULL);
1743 /* [HGM,HR] make sure board size is acceptable */
1744 if(appData.NrFiles > BOARD_FILES ||
1745 appData.NrRanks > BOARD_RANKS )
1746 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1749 /* This feature does not work; animation needs a rewrite */
1750 appData.highlightDragging = FALSE;
1754 xDisplay = XtDisplay(shellWidget);
1755 xScreen = DefaultScreen(xDisplay);
1756 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1758 gameInfo.variant = StringToVariant(appData.variant);
1759 InitPosition(FALSE);
1762 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1764 if (isdigit(appData.boardSize[0])) {
1765 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1766 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1767 &fontPxlSize, &smallLayout, &tinyLayout);
1769 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1770 programName, appData.boardSize);
1774 /* Find some defaults; use the nearest known size */
1775 SizeDefaults *szd, *nearest;
1776 int distance = 99999;
1777 nearest = szd = sizeDefaults;
1778 while (szd->name != NULL) {
1779 if (abs(szd->squareSize - squareSize) < distance) {
1781 distance = abs(szd->squareSize - squareSize);
1782 if (distance == 0) break;
1786 if (i < 2) lineGap = nearest->lineGap;
1787 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1788 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1789 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1790 if (i < 6) smallLayout = nearest->smallLayout;
1791 if (i < 7) tinyLayout = nearest->tinyLayout;
1794 SizeDefaults *szd = sizeDefaults;
1795 if (*appData.boardSize == NULLCHAR) {
1796 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1797 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1800 if (szd->name == NULL) szd--;
1801 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1803 while (szd->name != NULL &&
1804 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1805 if (szd->name == NULL) {
1806 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1807 programName, appData.boardSize);
1811 squareSize = szd->squareSize;
1812 lineGap = szd->lineGap;
1813 clockFontPxlSize = szd->clockFontPxlSize;
1814 coordFontPxlSize = szd->coordFontPxlSize;
1815 fontPxlSize = szd->fontPxlSize;
1816 smallLayout = szd->smallLayout;
1817 tinyLayout = szd->tinyLayout;
1820 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1821 if (strlen(appData.pixmapDirectory) > 0) {
1822 p = ExpandPathName(appData.pixmapDirectory);
1824 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1825 appData.pixmapDirectory);
1828 if (appData.debugMode) {
1829 fprintf(stderr, _("\
1830 XBoard square size (hint): %d\n\
1831 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1833 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1834 if (appData.debugMode) {
1835 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1839 /* [HR] height treated separately (hacked) */
1840 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1841 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1842 if (appData.showJail == 1) {
1843 /* Jail on top and bottom */
1844 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1845 XtSetArg(boardArgs[2], XtNheight,
1846 boardHeight + 2*(lineGap + squareSize));
1847 } else if (appData.showJail == 2) {
1849 XtSetArg(boardArgs[1], XtNwidth,
1850 boardWidth + 2*(lineGap + squareSize));
1851 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1854 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1855 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1859 * Determine what fonts to use.
1861 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1862 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1863 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1864 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1865 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1866 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1867 appData.font = FindFont(appData.font, fontPxlSize);
1868 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1869 countFontStruct = XQueryFont(xDisplay, countFontID);
1870 // appData.font = FindFont(appData.font, fontPxlSize);
1872 xdb = XtDatabase(xDisplay);
1873 XrmPutStringResource(&xdb, "*font", appData.font);
1876 * Detect if there are not enough colors available and adapt.
1878 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1879 appData.monoMode = True;
1882 if (!appData.monoMode) {
1883 vFrom.addr = (caddr_t) appData.lightSquareColor;
1884 vFrom.size = strlen(appData.lightSquareColor);
1885 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1886 if (vTo.addr == NULL) {
1887 appData.monoMode = True;
1890 lightSquareColor = *(Pixel *) vTo.addr;
1893 if (!appData.monoMode) {
1894 vFrom.addr = (caddr_t) appData.darkSquareColor;
1895 vFrom.size = strlen(appData.darkSquareColor);
1896 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1897 if (vTo.addr == NULL) {
1898 appData.monoMode = True;
1901 darkSquareColor = *(Pixel *) vTo.addr;
1904 if (!appData.monoMode) {
1905 vFrom.addr = (caddr_t) appData.whitePieceColor;
1906 vFrom.size = strlen(appData.whitePieceColor);
1907 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1908 if (vTo.addr == NULL) {
1909 appData.monoMode = True;
1912 whitePieceColor = *(Pixel *) vTo.addr;
1915 if (!appData.monoMode) {
1916 vFrom.addr = (caddr_t) appData.blackPieceColor;
1917 vFrom.size = strlen(appData.blackPieceColor);
1918 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1919 if (vTo.addr == NULL) {
1920 appData.monoMode = True;
1923 blackPieceColor = *(Pixel *) vTo.addr;
1927 if (!appData.monoMode) {
1928 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1929 vFrom.size = strlen(appData.highlightSquareColor);
1930 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1931 if (vTo.addr == NULL) {
1932 appData.monoMode = True;
1935 highlightSquareColor = *(Pixel *) vTo.addr;
1939 if (!appData.monoMode) {
1940 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1941 vFrom.size = strlen(appData.premoveHighlightColor);
1942 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1943 if (vTo.addr == NULL) {
1944 appData.monoMode = True;
1947 premoveHighlightColor = *(Pixel *) vTo.addr;
1952 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1955 if (appData.bitmapDirectory == NULL ||
1956 appData.bitmapDirectory[0] == NULLCHAR)
1957 appData.bitmapDirectory = DEF_BITMAP_DIR;
1960 if (appData.lowTimeWarning && !appData.monoMode) {
1961 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
1962 vFrom.size = strlen(appData.lowTimeWarningColor);
1963 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1964 if (vTo.addr == NULL)
1965 appData.monoMode = True;
1967 lowTimeWarningColor = *(Pixel *) vTo.addr;
1970 if (appData.monoMode && appData.debugMode) {
1971 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1972 (unsigned long) XWhitePixel(xDisplay, xScreen),
1973 (unsigned long) XBlackPixel(xDisplay, xScreen));
1976 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1977 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1978 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1979 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1980 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1981 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1982 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1983 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1984 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1985 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1987 if (appData.colorize) {
1989 _("%s: can't parse color names; disabling colorization\n"),
1992 appData.colorize = FALSE;
1994 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
1995 textColors[ColorNone].attr = 0;
1997 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2003 layoutName = "tinyLayout";
2004 } else if (smallLayout) {
2005 layoutName = "smallLayout";
2007 layoutName = "normalLayout";
2009 /* Outer layoutWidget is there only to provide a name for use in
2010 resources that depend on the layout style */
2012 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2013 layoutArgs, XtNumber(layoutArgs));
2015 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2016 formArgs, XtNumber(formArgs));
2017 XtSetArg(args[0], XtNdefaultDistance, &sep);
2018 XtGetValues(formWidget, args, 1);
2021 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2022 XtSetArg(args[0], XtNtop, XtChainTop);
2023 XtSetArg(args[1], XtNbottom, XtChainTop);
2024 XtSetArg(args[2], XtNright, XtChainLeft);
2025 XtSetValues(menuBarWidget, args, 3);
2027 widgetList[j++] = whiteTimerWidget =
2028 XtCreateWidget("whiteTime", labelWidgetClass,
2029 formWidget, timerArgs, XtNumber(timerArgs));
2030 XtSetArg(args[0], XtNfont, clockFontStruct);
2031 XtSetArg(args[1], XtNtop, XtChainTop);
2032 XtSetArg(args[2], XtNbottom, XtChainTop);
2033 XtSetValues(whiteTimerWidget, args, 3);
2035 widgetList[j++] = blackTimerWidget =
2036 XtCreateWidget("blackTime", labelWidgetClass,
2037 formWidget, timerArgs, XtNumber(timerArgs));
2038 XtSetArg(args[0], XtNfont, clockFontStruct);
2039 XtSetArg(args[1], XtNtop, XtChainTop);
2040 XtSetArg(args[2], XtNbottom, XtChainTop);
2041 XtSetValues(blackTimerWidget, args, 3);
2043 if (appData.titleInWindow) {
2044 widgetList[j++] = titleWidget =
2045 XtCreateWidget("title", labelWidgetClass, formWidget,
2046 titleArgs, XtNumber(titleArgs));
2047 XtSetArg(args[0], XtNtop, XtChainTop);
2048 XtSetArg(args[1], XtNbottom, XtChainTop);
2049 XtSetValues(titleWidget, args, 2);
2052 if (appData.showButtonBar) {
2053 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2054 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2055 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2056 XtSetArg(args[2], XtNtop, XtChainTop);
2057 XtSetArg(args[3], XtNbottom, XtChainTop);
2058 XtSetValues(buttonBarWidget, args, 4);
2061 widgetList[j++] = messageWidget =
2062 XtCreateWidget("message", labelWidgetClass, formWidget,
2063 messageArgs, XtNumber(messageArgs));
2064 XtSetArg(args[0], XtNtop, XtChainTop);
2065 XtSetArg(args[1], XtNbottom, XtChainTop);
2066 XtSetValues(messageWidget, args, 2);
2068 widgetList[j++] = boardWidget =
2069 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2070 XtNumber(boardArgs));
2072 XtManageChildren(widgetList, j);
2074 timerWidth = (boardWidth - sep) / 2;
2075 XtSetArg(args[0], XtNwidth, timerWidth);
2076 XtSetValues(whiteTimerWidget, args, 1);
2077 XtSetValues(blackTimerWidget, args, 1);
2079 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2080 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2081 XtGetValues(whiteTimerWidget, args, 2);
2083 if (appData.showButtonBar) {
2084 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2085 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2086 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2090 * formWidget uses these constraints but they are stored
2094 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2095 XtSetValues(menuBarWidget, args, i);
2096 if (appData.titleInWindow) {
2099 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2100 XtSetValues(whiteTimerWidget, args, i);
2102 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2103 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2104 XtSetValues(blackTimerWidget, args, i);
2106 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2107 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2108 XtSetValues(titleWidget, args, i);
2110 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2111 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2112 XtSetValues(messageWidget, args, i);
2113 if (appData.showButtonBar) {
2115 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2116 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2117 XtSetValues(buttonBarWidget, args, i);
2121 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2122 XtSetValues(whiteTimerWidget, args, i);
2124 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2125 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2126 XtSetValues(blackTimerWidget, args, i);
2128 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2129 XtSetValues(titleWidget, args, i);
2131 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2132 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2133 XtSetValues(messageWidget, args, i);
2134 if (appData.showButtonBar) {
2136 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2137 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2138 XtSetValues(buttonBarWidget, args, i);
2143 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2144 XtSetValues(whiteTimerWidget, args, i);
2146 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2147 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2148 XtSetValues(blackTimerWidget, args, i);
2150 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2151 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2152 XtSetValues(messageWidget, args, i);
2153 if (appData.showButtonBar) {
2155 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2156 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2157 XtSetValues(buttonBarWidget, args, i);
2161 XtSetArg(args[0], XtNfromVert, messageWidget);
2162 XtSetArg(args[1], XtNtop, XtChainTop);
2163 XtSetArg(args[2], XtNbottom, XtChainBottom);
2164 XtSetArg(args[3], XtNleft, XtChainLeft);
2165 XtSetArg(args[4], XtNright, XtChainRight);
2166 XtSetValues(boardWidget, args, 5);
2168 XtRealizeWidget(shellWidget);
2171 XtSetArg(args[0], XtNx, wpMain.x);
2172 XtSetArg(args[1], XtNy, wpMain.y);
2173 XtSetValues(shellWidget, args, 2);
2177 * Correct the width of the message and title widgets.
2178 * It is not known why some systems need the extra fudge term.
2179 * The value "2" is probably larger than needed.
2181 XawFormDoLayout(formWidget, False);
2183 #define WIDTH_FUDGE 2
2185 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2186 XtSetArg(args[i], XtNheight, &h); i++;
2187 XtGetValues(messageWidget, args, i);
2188 if (appData.showButtonBar) {
2190 XtSetArg(args[i], XtNwidth, &w); i++;
2191 XtGetValues(buttonBarWidget, args, i);
2192 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2194 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2197 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2198 if (gres != XtGeometryYes && appData.debugMode) {
2199 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2200 programName, gres, w, h, wr, hr);
2203 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2204 /* The size used for the child widget in layout lags one resize behind
2205 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2207 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2208 if (gres != XtGeometryYes && appData.debugMode) {
2209 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2210 programName, gres, w, h, wr, hr);
2213 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2214 XtSetArg(args[1], XtNright, XtChainRight);
2215 XtSetValues(messageWidget, args, 2);
2217 if (appData.titleInWindow) {
2219 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2220 XtSetArg(args[i], XtNheight, &h); i++;
2221 XtGetValues(titleWidget, args, i);
2223 w = boardWidth - 2*bor;
2225 XtSetArg(args[0], XtNwidth, &w);
2226 XtGetValues(menuBarWidget, args, 1);
2227 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2230 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2231 if (gres != XtGeometryYes && appData.debugMode) {
2233 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2234 programName, gres, w, h, wr, hr);
2237 XawFormDoLayout(formWidget, True);
2239 xBoardWindow = XtWindow(boardWidget);
2241 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2242 // not need to go into InitDrawingSizes().
2246 * Create X checkmark bitmap and initialize option menu checks.
2248 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2249 checkmark_bits, checkmark_width, checkmark_height);
2250 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2251 if (appData.alwaysPromoteToQueen) {
2252 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2255 if (appData.animateDragging) {
2256 XtSetValues(XtNameToWidget(menuBarWidget,
2257 "menuOptions.Animate Dragging"),
2260 if (appData.animate) {
2261 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2264 if (appData.autoComment) {
2265 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2268 if (appData.autoCallFlag) {
2269 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2272 if (appData.autoFlipView) {
2273 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2276 if (appData.autoObserve) {
2277 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2280 if (appData.autoRaiseBoard) {
2281 XtSetValues(XtNameToWidget(menuBarWidget,
2282 "menuOptions.Auto Raise Board"), args, 1);
2284 if (appData.autoSaveGames) {
2285 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2288 if (appData.saveGameFile[0] != NULLCHAR) {
2289 /* Can't turn this off from menu */
2290 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2292 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2296 if (appData.blindfold) {
2297 XtSetValues(XtNameToWidget(menuBarWidget,
2298 "menuOptions.Blindfold"), args, 1);
2300 if (appData.flashCount > 0) {
2301 XtSetValues(XtNameToWidget(menuBarWidget,
2302 "menuOptions.Flash Moves"),
2305 if (appData.getMoveList) {
2306 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2310 if (appData.highlightDragging) {
2311 XtSetValues(XtNameToWidget(menuBarWidget,
2312 "menuOptions.Highlight Dragging"),
2316 if (appData.highlightLastMove) {
2317 XtSetValues(XtNameToWidget(menuBarWidget,
2318 "menuOptions.Highlight Last Move"),
2321 if (appData.icsAlarm) {
2322 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2325 if (appData.ringBellAfterMoves) {
2326 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2329 if (appData.oldSaveStyle) {
2330 XtSetValues(XtNameToWidget(menuBarWidget,
2331 "menuOptions.Old Save Style"), args, 1);
2333 if (appData.periodicUpdates) {
2334 XtSetValues(XtNameToWidget(menuBarWidget,
2335 "menuOptions.Periodic Updates"), args, 1);
2337 if (appData.ponderNextMove) {
2338 XtSetValues(XtNameToWidget(menuBarWidget,
2339 "menuOptions.Ponder Next Move"), args, 1);
2341 if (appData.popupExitMessage) {
2342 XtSetValues(XtNameToWidget(menuBarWidget,
2343 "menuOptions.Popup Exit Message"), args, 1);
2345 if (appData.popupMoveErrors) {
2346 XtSetValues(XtNameToWidget(menuBarWidget,
2347 "menuOptions.Popup Move Errors"), args, 1);
2349 if (appData.premove) {
2350 XtSetValues(XtNameToWidget(menuBarWidget,
2351 "menuOptions.Premove"), args, 1);
2353 if (appData.quietPlay) {
2354 XtSetValues(XtNameToWidget(menuBarWidget,
2355 "menuOptions.Quiet Play"), args, 1);
2357 if (appData.showCoords) {
2358 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2361 if (appData.hideThinkingFromHuman) {
2362 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2365 if (appData.testLegality) {
2366 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2369 if (saveSettingsOnExit) {
2370 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2377 ReadBitmap(&wIconPixmap, "icon_white.bm",
2378 icon_white_bits, icon_white_width, icon_white_height);
2379 ReadBitmap(&bIconPixmap, "icon_black.bm",
2380 icon_black_bits, icon_black_width, icon_black_height);
2381 iconPixmap = wIconPixmap;
2383 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2384 XtSetValues(shellWidget, args, i);
2387 * Create a cursor for the board widget.
2389 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2390 XChangeWindowAttributes(xDisplay, xBoardWindow,
2391 CWCursor, &window_attributes);
2394 * Inhibit shell resizing.
2396 shellArgs[0].value = (XtArgVal) &w;
2397 shellArgs[1].value = (XtArgVal) &h;
2398 XtGetValues(shellWidget, shellArgs, 2);
2399 shellArgs[4].value = shellArgs[2].value = w;
2400 shellArgs[5].value = shellArgs[3].value = h;
2401 XtSetValues(shellWidget, &shellArgs[2], 4);
2402 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2403 marginH = h - boardHeight;
2405 CatchDeleteWindow(shellWidget, "QuitProc");
2410 if (appData.bitmapDirectory[0] != NULLCHAR) {
2417 /* Create regular pieces */
2418 if (!useImages) CreatePieces();
2423 if (appData.animate || appData.animateDragging)
2426 XtAugmentTranslations(formWidget,
2427 XtParseTranslationTable(globalTranslations));
2428 XtAugmentTranslations(boardWidget,
2429 XtParseTranslationTable(boardTranslations));
2430 XtAugmentTranslations(whiteTimerWidget,
2431 XtParseTranslationTable(whiteTranslations));
2432 XtAugmentTranslations(blackTimerWidget,
2433 XtParseTranslationTable(blackTranslations));
2435 /* Why is the following needed on some versions of X instead
2436 * of a translation? */
2437 XtAddEventHandler(boardWidget, ExposureMask, False,
2438 (XtEventHandler) EventProc, NULL);
2441 /* [AS] Restore layout */
2442 if( wpMoveHistory.visible ) {
2446 if( wpEvalGraph.visible )
2451 if( wpEngineOutput.visible ) {
2452 EngineOutputPopUp();
2457 if (errorExitStatus == -1) {
2458 if (appData.icsActive) {
2459 /* We now wait until we see "login:" from the ICS before
2460 sending the logon script (problems with timestamp otherwise) */
2461 /*ICSInitScript();*/
2462 if (appData.icsInputBox) ICSInputBoxPopUp();
2466 signal(SIGWINCH, TermSizeSigHandler);
2468 signal(SIGINT, IntSigHandler);
2469 signal(SIGTERM, IntSigHandler);
2470 if (*appData.cmailGameName != NULLCHAR) {
2471 signal(SIGUSR1, CmailSigHandler);
2474 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2477 XtAppMainLoop(appContext);
2478 if (appData.debugMode) fclose(debugFP); // [DM] debug
2485 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2486 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2488 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2489 unlink(gameCopyFilename);
2490 unlink(gamePasteFilename);
2493 RETSIGTYPE TermSizeSigHandler(int sig)
2506 CmailSigHandler(sig)
2512 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2514 /* Activate call-back function CmailSigHandlerCallBack() */
2515 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2517 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2521 CmailSigHandlerCallBack(isr, closure, message, count, error)
2529 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2531 /**** end signal code ****/
2541 f = fopen(appData.icsLogon, "r");
2547 strcat(buf, appData.icsLogon);
2548 f = fopen(buf, "r");
2552 ProcessICSInitScript(f);
2559 EditCommentPopDown();
2574 if (!menuBarWidget) return;
2575 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2577 DisplayError("menuStep.Revert", 0);
2579 XtSetSensitive(w, !grey);
2584 SetMenuEnables(enab)
2588 if (!menuBarWidget) return;
2589 while (enab->name != NULL) {
2590 w = XtNameToWidget(menuBarWidget, enab->name);
2592 DisplayError(enab->name, 0);
2594 XtSetSensitive(w, enab->value);
2600 Enables icsEnables[] = {
2601 { "menuFile.Mail Move", False },
2602 { "menuFile.Reload CMail Message", False },
2603 { "menuMode.Machine Black", False },
2604 { "menuMode.Machine White", False },
2605 { "menuMode.Analysis Mode", False },
2606 { "menuMode.Analyze File", False },
2607 { "menuMode.Two Machines", False },
2609 { "menuHelp.Hint", False },
2610 { "menuHelp.Book", False },
2611 { "menuStep.Move Now", False },
2612 { "menuOptions.Periodic Updates", False },
2613 { "menuOptions.Hide Thinking", False },
2614 { "menuOptions.Ponder Next Move", False },
2619 Enables ncpEnables[] = {
2620 { "menuFile.Mail Move", False },
2621 { "menuFile.Reload CMail Message", False },
2622 { "menuMode.Machine White", False },
2623 { "menuMode.Machine Black", False },
2624 { "menuMode.Analysis Mode", False },
2625 { "menuMode.Analyze File", False },
2626 { "menuMode.Two Machines", False },
2627 { "menuMode.ICS Client", False },
2628 { "menuMode.ICS Input Box", False },
2629 { "Action", False },
2630 { "menuStep.Revert", False },
2631 { "menuStep.Move Now", False },
2632 { "menuStep.Retract Move", False },
2633 { "menuOptions.Auto Comment", False },
2634 { "menuOptions.Auto Flag", False },
2635 { "menuOptions.Auto Flip View", False },
2636 { "menuOptions.Auto Observe", False },
2637 { "menuOptions.Auto Raise Board", False },
2638 { "menuOptions.Get Move List", False },
2639 { "menuOptions.ICS Alarm", False },
2640 { "menuOptions.Move Sound", False },
2641 { "menuOptions.Quiet Play", False },
2642 { "menuOptions.Hide Thinking", False },
2643 { "menuOptions.Periodic Updates", False },
2644 { "menuOptions.Ponder Next Move", False },
2645 { "menuHelp.Hint", False },
2646 { "menuHelp.Book", False },
2650 Enables gnuEnables[] = {
2651 { "menuMode.ICS Client", False },
2652 { "menuMode.ICS Input Box", False },
2653 { "menuAction.Accept", False },
2654 { "menuAction.Decline", False },
2655 { "menuAction.Rematch", False },
2656 { "menuAction.Adjourn", False },
2657 { "menuAction.Stop Examining", False },
2658 { "menuAction.Stop Observing", False },
2659 { "menuStep.Revert", False },
2660 { "menuOptions.Auto Comment", False },
2661 { "menuOptions.Auto Observe", False },
2662 { "menuOptions.Auto Raise Board", False },
2663 { "menuOptions.Get Move List", False },
2664 { "menuOptions.Premove", False },
2665 { "menuOptions.Quiet Play", False },
2667 /* The next two options rely on SetCmailMode being called *after* */
2668 /* SetGNUMode so that when GNU is being used to give hints these */
2669 /* menu options are still available */
2671 { "menuFile.Mail Move", False },
2672 { "menuFile.Reload CMail Message", False },
2676 Enables cmailEnables[] = {
2678 { "menuAction.Call Flag", False },
2679 { "menuAction.Draw", True },
2680 { "menuAction.Adjourn", False },
2681 { "menuAction.Abort", False },
2682 { "menuAction.Stop Observing", False },
2683 { "menuAction.Stop Examining", False },
2684 { "menuFile.Mail Move", True },
2685 { "menuFile.Reload CMail Message", True },
2689 Enables trainingOnEnables[] = {
2690 { "menuMode.Edit Comment", False },
2691 { "menuMode.Pause", False },
2692 { "menuStep.Forward", False },
2693 { "menuStep.Backward", False },
2694 { "menuStep.Forward to End", False },
2695 { "menuStep.Back to Start", False },
2696 { "menuStep.Move Now", False },
2697 { "menuStep.Truncate Game", False },
2701 Enables trainingOffEnables[] = {
2702 { "menuMode.Edit Comment", True },
2703 { "menuMode.Pause", True },
2704 { "menuStep.Forward", True },
2705 { "menuStep.Backward", True },
2706 { "menuStep.Forward to End", True },
2707 { "menuStep.Back to Start", True },
2708 { "menuStep.Move Now", True },
2709 { "menuStep.Truncate Game", True },
2713 Enables machineThinkingEnables[] = {
2714 { "menuFile.Load Game", False },
2715 { "menuFile.Load Next Game", False },
2716 { "menuFile.Load Previous Game", False },
2717 { "menuFile.Reload Same Game", False },
2718 { "menuFile.Paste Game", False },
2719 { "menuFile.Load Position", False },
2720 { "menuFile.Load Next Position", False },
2721 { "menuFile.Load Previous Position", False },
2722 { "menuFile.Reload Same Position", False },
2723 { "menuFile.Paste Position", False },
2724 { "menuMode.Machine White", False },
2725 { "menuMode.Machine Black", False },
2726 { "menuMode.Two Machines", False },
2727 { "menuStep.Retract Move", False },
2731 Enables userThinkingEnables[] = {
2732 { "menuFile.Load Game", True },
2733 { "menuFile.Load Next Game", True },
2734 { "menuFile.Load Previous Game", True },
2735 { "menuFile.Reload Same Game", True },
2736 { "menuFile.Paste Game", True },
2737 { "menuFile.Load Position", True },
2738 { "menuFile.Load Next Position", True },
2739 { "menuFile.Load Previous Position", True },
2740 { "menuFile.Reload Same Position", True },
2741 { "menuFile.Paste Position", True },
2742 { "menuMode.Machine White", True },
2743 { "menuMode.Machine Black", True },
2744 { "menuMode.Two Machines", True },
2745 { "menuStep.Retract Move", True },
2751 SetMenuEnables(icsEnables);
2754 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2755 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2762 SetMenuEnables(ncpEnables);
2768 SetMenuEnables(gnuEnables);
2774 SetMenuEnables(cmailEnables);
2780 SetMenuEnables(trainingOnEnables);
2781 if (appData.showButtonBar) {
2782 XtSetSensitive(buttonBarWidget, False);
2788 SetTrainingModeOff()
2790 SetMenuEnables(trainingOffEnables);
2791 if (appData.showButtonBar) {
2792 XtSetSensitive(buttonBarWidget, True);
2797 SetUserThinkingEnables()
2799 if (appData.noChessProgram) return;
2800 SetMenuEnables(userThinkingEnables);
2804 SetMachineThinkingEnables()
2806 if (appData.noChessProgram) return;
2807 SetMenuEnables(machineThinkingEnables);
2809 case MachinePlaysBlack:
2810 case MachinePlaysWhite:
2811 case TwoMachinesPlay:
2812 XtSetSensitive(XtNameToWidget(menuBarWidget,
2813 ModeToWidgetName(gameMode)), True);
2820 #define Abs(n) ((n)<0 ? -(n) : (n))
2823 * Find a font that matches "pattern" that is as close as
2824 * possible to the targetPxlSize. Prefer fonts that are k
2825 * pixels smaller to fonts that are k pixels larger. The
2826 * pattern must be in the X Consortium standard format,
2827 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2828 * The return value should be freed with XtFree when no
2831 char *FindFont(pattern, targetPxlSize)
2835 char **fonts, *p, *best, *scalable, *scalableTail;
2836 int i, j, nfonts, minerr, err, pxlSize;
2839 char **missing_list;
2841 char *def_string, *base_fnt_lst, strInt[3];
2843 XFontStruct **fnt_list;
2845 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2846 sprintf(strInt, "%d", targetPxlSize);
2847 p = strstr(pattern, "--");
2848 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2849 strcat(base_fnt_lst, strInt);
2850 strcat(base_fnt_lst, strchr(p + 2, '-'));
2852 if ((fntSet = XCreateFontSet(xDisplay,
2856 &def_string)) == NULL) {
2858 fprintf(stderr, _("Unable to create font set.\n"));
2862 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2864 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2866 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2867 programName, pattern);
2875 for (i=0; i<nfonts; i++) {
2878 if (*p != '-') continue;
2880 if (*p == NULLCHAR) break;
2881 if (*p++ == '-') j++;
2883 if (j < 7) continue;
2886 scalable = fonts[i];
2889 err = pxlSize - targetPxlSize;
2890 if (Abs(err) < Abs(minerr) ||
2891 (minerr > 0 && err < 0 && -err == minerr)) {
2897 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
2898 /* If the error is too big and there is a scalable font,
2899 use the scalable font. */
2900 int headlen = scalableTail - scalable;
2901 p = (char *) XtMalloc(strlen(scalable) + 10);
2902 while (isdigit(*scalableTail)) scalableTail++;
2903 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
2905 p = (char *) XtMalloc(strlen(best) + 1);
2908 if (appData.debugMode) {
2909 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
2910 pattern, targetPxlSize, p);
2913 if (missing_count > 0)
2914 XFreeStringList(missing_list);
2915 XFreeFontSet(xDisplay, fntSet);
2917 XFreeFontNames(fonts);
2924 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
2925 | GCBackground | GCFunction | GCPlaneMask;
2926 XGCValues gc_values;
2929 gc_values.plane_mask = AllPlanes;
2930 gc_values.line_width = lineGap;
2931 gc_values.line_style = LineSolid;
2932 gc_values.function = GXcopy;
2934 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2935 gc_values.background = XBlackPixel(xDisplay, xScreen);
2936 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2938 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2939 gc_values.background = XWhitePixel(xDisplay, xScreen);
2940 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
2941 XSetFont(xDisplay, coordGC, coordFontID);
2943 // [HGM] make font for holdings counts (white on black0
2944 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2945 gc_values.background = XBlackPixel(xDisplay, xScreen);
2946 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
2947 XSetFont(xDisplay, countGC, countFontID);
2949 if (appData.monoMode) {
2950 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2951 gc_values.background = XWhitePixel(xDisplay, xScreen);
2952 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2954 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2955 gc_values.background = XBlackPixel(xDisplay, xScreen);
2956 lightSquareGC = wbPieceGC
2957 = XtGetGC(shellWidget, value_mask, &gc_values);
2959 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2960 gc_values.background = XWhitePixel(xDisplay, xScreen);
2961 darkSquareGC = bwPieceGC
2962 = XtGetGC(shellWidget, value_mask, &gc_values);
2964 if (DefaultDepth(xDisplay, xScreen) == 1) {
2965 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
2966 gc_values.function = GXcopyInverted;
2967 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
2968 gc_values.function = GXcopy;
2969 if (XBlackPixel(xDisplay, xScreen) == 1) {
2970 bwPieceGC = darkSquareGC;
2971 wbPieceGC = copyInvertedGC;
2973 bwPieceGC = copyInvertedGC;
2974 wbPieceGC = lightSquareGC;
2978 gc_values.foreground = highlightSquareColor;
2979 gc_values.background = highlightSquareColor;
2980 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2982 gc_values.foreground = premoveHighlightColor;
2983 gc_values.background = premoveHighlightColor;
2984 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2986 gc_values.foreground = lightSquareColor;
2987 gc_values.background = darkSquareColor;
2988 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2990 gc_values.foreground = darkSquareColor;
2991 gc_values.background = lightSquareColor;
2992 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2994 gc_values.foreground = jailSquareColor;
2995 gc_values.background = jailSquareColor;
2996 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2998 gc_values.foreground = whitePieceColor;
2999 gc_values.background = darkSquareColor;
3000 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3002 gc_values.foreground = whitePieceColor;
3003 gc_values.background = lightSquareColor;
3004 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3006 gc_values.foreground = whitePieceColor;
3007 gc_values.background = jailSquareColor;
3008 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3010 gc_values.foreground = blackPieceColor;
3011 gc_values.background = darkSquareColor;
3012 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3014 gc_values.foreground = blackPieceColor;
3015 gc_values.background = lightSquareColor;
3016 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3018 gc_values.foreground = blackPieceColor;
3019 gc_values.background = jailSquareColor;
3020 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3024 void loadXIM(xim, xmask, filename, dest, mask)
3037 fp = fopen(filename, "rb");
3039 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3046 for (y=0; y<h; ++y) {
3047 for (x=0; x<h; ++x) {
3052 XPutPixel(xim, x, y, blackPieceColor);
3054 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3057 XPutPixel(xim, x, y, darkSquareColor);
3059 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3062 XPutPixel(xim, x, y, whitePieceColor);
3064 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3067 XPutPixel(xim, x, y, lightSquareColor);
3069 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3075 /* create Pixmap of piece */
3076 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3078 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3081 /* create Pixmap of clipmask
3082 Note: We assume the white/black pieces have the same
3083 outline, so we make only 6 masks. This is okay
3084 since the XPM clipmask routines do the same. */
3086 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3088 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3091 /* now create the 1-bit version */
3092 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3095 values.foreground = 1;
3096 values.background = 0;
3098 /* Don't use XtGetGC, not read only */
3099 maskGC = XCreateGC(xDisplay, *mask,
3100 GCForeground | GCBackground, &values);
3101 XCopyPlane(xDisplay, temp, *mask, maskGC,
3102 0, 0, squareSize, squareSize, 0, 0, 1);
3103 XFreePixmap(xDisplay, temp);
3108 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3110 void CreateXIMPieces()
3115 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3120 /* The XSynchronize calls were copied from CreatePieces.
3121 Not sure if needed, but can't hurt */
3122 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3125 /* temp needed by loadXIM() */
3126 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3127 0, 0, ss, ss, AllPlanes, XYPixmap);
3129 if (strlen(appData.pixmapDirectory) == 0) {
3133 if (appData.monoMode) {
3134 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3138 fprintf(stderr, _("\nLoading XIMs...\n"));
3140 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3141 fprintf(stderr, "%d", piece+1);
3142 for (kind=0; kind<4; kind++) {
3143 fprintf(stderr, ".");
3144 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3145 ExpandPathName(appData.pixmapDirectory),
3146 piece <= (int) WhiteKing ? "" : "w",
3147 pieceBitmapNames[piece],
3149 ximPieceBitmap[kind][piece] =
3150 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3151 0, 0, ss, ss, AllPlanes, XYPixmap);
3152 if (appData.debugMode)
3153 fprintf(stderr, _("(File:%s:) "), buf);
3154 loadXIM(ximPieceBitmap[kind][piece],
3156 &(xpmPieceBitmap2[kind][piece]),
3157 &(ximMaskPm2[piece]));
3158 if(piece <= (int)WhiteKing)
3159 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3161 fprintf(stderr," ");
3163 /* Load light and dark squares */
3164 /* If the LSQ and DSQ pieces don't exist, we will
3165 draw them with solid squares. */
3166 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3167 if (access(buf, 0) != 0) {
3171 fprintf(stderr, _("light square "));
3173 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3174 0, 0, ss, ss, AllPlanes, XYPixmap);
3175 if (appData.debugMode)
3176 fprintf(stderr, _("(File:%s:) "), buf);
3178 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3179 fprintf(stderr, _("dark square "));
3180 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3181 ExpandPathName(appData.pixmapDirectory), ss);
3182 if (appData.debugMode)
3183 fprintf(stderr, _("(File:%s:) "), buf);
3185 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3186 0, 0, ss, ss, AllPlanes, XYPixmap);
3187 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3188 xpmJailSquare = xpmLightSquare;
3190 fprintf(stderr, _("Done.\n"));
3192 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3196 void CreateXPMPieces()
3200 u_int ss = squareSize;
3202 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3203 XpmColorSymbol symbols[4];
3205 /* The XSynchronize calls were copied from CreatePieces.
3206 Not sure if needed, but can't hurt */
3207 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3209 /* Setup translations so piece colors match square colors */
3210 symbols[0].name = "light_piece";
3211 symbols[0].value = appData.whitePieceColor;
3212 symbols[1].name = "dark_piece";
3213 symbols[1].value = appData.blackPieceColor;
3214 symbols[2].name = "light_square";
3215 symbols[2].value = appData.lightSquareColor;
3216 symbols[3].name = "dark_square";
3217 symbols[3].value = appData.darkSquareColor;
3219 attr.valuemask = XpmColorSymbols;
3220 attr.colorsymbols = symbols;
3221 attr.numsymbols = 4;
3223 if (appData.monoMode) {
3224 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3228 if (strlen(appData.pixmapDirectory) == 0) {
3229 XpmPieces* pieces = builtInXpms;
3232 while (pieces->size != squareSize && pieces->size) pieces++;
3233 if (!pieces->size) {
3234 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3237 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3238 for (kind=0; kind<4; kind++) {
3240 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3241 pieces->xpm[piece][kind],
3242 &(xpmPieceBitmap2[kind][piece]),
3243 NULL, &attr)) != 0) {
3244 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3248 if(piece <= (int) WhiteKing)
3249 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3253 xpmJailSquare = xpmLightSquare;
3257 fprintf(stderr, _("\nLoading XPMs...\n"));
3260 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3261 fprintf(stderr, "%d ", piece+1);
3262 for (kind=0; kind<4; kind++) {
3263 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3264 ExpandPathName(appData.pixmapDirectory),
3265 piece > (int) WhiteKing ? "w" : "",
3266 pieceBitmapNames[piece],
3268 if (appData.debugMode) {
3269 fprintf(stderr, _("(File:%s:) "), buf);
3271 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3272 &(xpmPieceBitmap2[kind][piece]),
3273 NULL, &attr)) != 0) {
3274 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3275 // [HGM] missing: read of unorthodox piece failed; substitute King.
3276 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3277 ExpandPathName(appData.pixmapDirectory),
3279 if (appData.debugMode) {
3280 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3282 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3283 &(xpmPieceBitmap2[kind][piece]),
3287 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3292 if(piece <= (int) WhiteKing)
3293 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3296 /* Load light and dark squares */
3297 /* If the LSQ and DSQ pieces don't exist, we will
3298 draw them with solid squares. */
3299 fprintf(stderr, _("light square "));
3300 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3301 if (access(buf, 0) != 0) {
3305 if (appData.debugMode)
3306 fprintf(stderr, _("(File:%s:) "), buf);
3308 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3309 &xpmLightSquare, NULL, &attr)) != 0) {
3310 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3313 fprintf(stderr, _("dark square "));
3314 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3315 ExpandPathName(appData.pixmapDirectory), ss);
3316 if (appData.debugMode) {
3317 fprintf(stderr, _("(File:%s:) "), buf);
3319 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3320 &xpmDarkSquare, NULL, &attr)) != 0) {
3321 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3325 xpmJailSquare = xpmLightSquare;
3326 fprintf(stderr, _("Done.\n"));
3328 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3331 #endif /* HAVE_LIBXPM */
3334 /* No built-in bitmaps */
3339 u_int ss = squareSize;
3341 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3344 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3345 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3346 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3347 pieceBitmapNames[piece],
3348 ss, kind == SOLID ? 's' : 'o');
3349 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3350 if(piece <= (int)WhiteKing)
3351 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3355 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3359 /* With built-in bitmaps */
3362 BuiltInBits* bib = builtInBits;
3365 u_int ss = squareSize;
3367 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3370 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3372 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3373 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3374 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3375 pieceBitmapNames[piece],
3376 ss, kind == SOLID ? 's' : 'o');
3377 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3378 bib->bits[kind][piece], ss, ss);
3379 if(piece <= (int)WhiteKing)
3380 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3384 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3389 void ReadBitmap(pm, name, bits, wreq, hreq)
3392 unsigned char bits[];
3398 char msg[MSG_SIZ], fullname[MSG_SIZ];
3400 if (*appData.bitmapDirectory != NULLCHAR) {
3401 strcpy(fullname, appData.bitmapDirectory);
3402 strcat(fullname, "/");
3403 strcat(fullname, name);
3404 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3405 &w, &h, pm, &x_hot, &y_hot);
3406 fprintf(stderr, "load %s\n", name);
3407 if (errcode != BitmapSuccess) {
3409 case BitmapOpenFailed:
3410 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3412 case BitmapFileInvalid:
3413 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3415 case BitmapNoMemory:
3416 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3420 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3424 fprintf(stderr, _("%s: %s...using built-in\n"),
3426 } else if (w != wreq || h != hreq) {
3428 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3429 programName, fullname, w, h, wreq, hreq);
3435 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3444 if (lineGap == 0) return;
3446 /* [HR] Split this into 2 loops for non-square boards. */
3448 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3449 gridSegments[i].x1 = 0;
3450 gridSegments[i].x2 =
3451 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3452 gridSegments[i].y1 = gridSegments[i].y2
3453 = lineGap / 2 + (i * (squareSize + lineGap));
3456 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3457 gridSegments[j + i].y1 = 0;
3458 gridSegments[j + i].y2 =
3459 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3460 gridSegments[j + i].x1 = gridSegments[j + i].x2
3461 = lineGap / 2 + (j * (squareSize + lineGap));
3465 static void MenuBarSelect(w, addr, index)
3470 XtActionProc proc = (XtActionProc) addr;
3472 (proc)(NULL, NULL, NULL, NULL);
3475 void CreateMenuBarPopup(parent, name, mb)
3485 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3488 XtSetArg(args[j], XtNleftMargin, 20); j++;
3489 XtSetArg(args[j], XtNrightMargin, 20); j++;
3491 while (mi->string != NULL) {
3492 if (strcmp(mi->string, "----") == 0) {
3493 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3496 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3497 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3499 XtAddCallback(entry, XtNcallback,
3500 (XtCallbackProc) MenuBarSelect,
3501 (caddr_t) mi->proc);
3507 Widget CreateMenuBar(mb)
3511 Widget anchor, menuBar;
3513 char menuName[MSG_SIZ];
3516 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3517 XtSetArg(args[j], XtNvSpace, 0); j++;
3518 XtSetArg(args[j], XtNborderWidth, 0); j++;
3519 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3520 formWidget, args, j);
3522 while (mb->name != NULL) {
3523 strcpy(menuName, "menu");
3524 strcat(menuName, mb->name);
3526 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3529 shortName[0] = _(mb->name)[0];
3530 shortName[1] = NULLCHAR;
3531 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3534 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3537 XtSetArg(args[j], XtNborderWidth, 0); j++;
3538 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3540 CreateMenuBarPopup(menuBar, menuName, mb);
3546 Widget CreateButtonBar(mi)
3550 Widget button, buttonBar;
3554 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3556 XtSetArg(args[j], XtNhSpace, 0); j++;
3558 XtSetArg(args[j], XtNborderWidth, 0); j++;
3559 XtSetArg(args[j], XtNvSpace, 0); j++;
3560 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3561 formWidget, args, j);
3563 while (mi->string != NULL) {
3566 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3567 XtSetArg(args[j], XtNborderWidth, 0); j++;
3569 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3570 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3571 buttonBar, args, j);
3572 XtAddCallback(button, XtNcallback,
3573 (XtCallbackProc) MenuBarSelect,
3574 (caddr_t) mi->proc);
3581 CreatePieceMenu(name, color)
3588 ChessSquare selection;
3590 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3591 boardWidget, args, 0);
3593 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3594 String item = pieceMenuStrings[color][i];
3596 if (strcmp(item, "----") == 0) {
3597 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3600 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3601 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3603 selection = pieceMenuTranslation[color][i];
3604 XtAddCallback(entry, XtNcallback,
3605 (XtCallbackProc) PieceMenuSelect,
3606 (caddr_t) selection);
3607 if (selection == WhitePawn || selection == BlackPawn) {
3608 XtSetArg(args[0], XtNpopupOnEntry, entry);
3609 XtSetValues(menu, args, 1);
3622 ChessSquare selection;
3624 whitePieceMenu = CreatePieceMenu("menuW", 0);
3625 blackPieceMenu = CreatePieceMenu("menuB", 1);
3627 XtRegisterGrabAction(PieceMenuPopup, True,
3628 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3629 GrabModeAsync, GrabModeAsync);
3631 XtSetArg(args[0], XtNlabel, _("Drop"));
3632 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3633 boardWidget, args, 1);
3634 for (i = 0; i < DROP_MENU_SIZE; i++) {
3635 String item = dropMenuStrings[i];
3637 if (strcmp(item, "----") == 0) {
3638 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3641 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3642 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3644 selection = dropMenuTranslation[i];
3645 XtAddCallback(entry, XtNcallback,
3646 (XtCallbackProc) DropMenuSelect,
3647 (caddr_t) selection);
3652 void SetupDropMenu()
3660 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3661 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3662 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3663 dmEnables[i].piece);
3664 XtSetSensitive(entry, p != NULL || !appData.testLegality
3665 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3666 && !appData.icsActive));
3668 while (p && *p++ == dmEnables[i].piece) count++;
3669 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3671 XtSetArg(args[j], XtNlabel, label); j++;
3672 XtSetValues(entry, args, j);
3676 void PieceMenuPopup(w, event, params, num_params)
3680 Cardinal *num_params;
3684 if (event->type == ButtonRelease) UnLoadPV(); // [HGM] pv
3685 if (event->type != ButtonPress) return;
3686 if (errorUp) ErrorPopDown();
3690 whichMenu = params[0];
3693 if(!appData.icsEngineAnalyze) return;
3694 case IcsPlayingWhite:
3695 case IcsPlayingBlack:
3696 if(!appData.zippyPlay) goto noZip;
3699 case MachinePlaysWhite:
3700 case MachinePlaysBlack:
3701 case TwoMachinesPlay: // [HGM] pv: use for showing PV
3702 if (!appData.dropMenu) {
3703 LoadPV(event->xbutton.x, event->xbutton.y);
3706 if(gameMode == TwoMachinesPlay || gameMode == AnalyzeMode ||
3707 gameMode == AnalyzeFile || gameMode == IcsObserving) return;
3710 if (!appData.dropMenu || appData.testLegality &&
3711 gameInfo.variant != VariantBughouse &&
3712 gameInfo.variant != VariantCrazyhouse) return;
3714 whichMenu = "menuD";
3720 if (((pmFromX = EventToSquare(event->xbutton.x, BOARD_WIDTH)) < 0) ||
3721 ((pmFromY = EventToSquare(event->xbutton.y, BOARD_HEIGHT)) < 0)) {
3722 pmFromX = pmFromY = -1;
3726 pmFromX = BOARD_WIDTH - 1 - pmFromX;
3728 pmFromY = BOARD_HEIGHT - 1 - pmFromY;
3730 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3733 static void PieceMenuSelect(w, piece, junk)
3738 if (pmFromX < 0 || pmFromY < 0) return;
3739 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3742 static void DropMenuSelect(w, piece, junk)
3747 if (pmFromX < 0 || pmFromY < 0) return;
3748 DropMenuEvent(piece, pmFromX, pmFromY);
3751 void WhiteClock(w, event, prms, nprms)
3757 if (gameMode == EditPosition || gameMode == IcsExamining) {
3758 SetWhiteToPlayEvent();
3759 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3764 void BlackClock(w, event, prms, nprms)
3770 if (gameMode == EditPosition || gameMode == IcsExamining) {
3771 SetBlackToPlayEvent();
3772 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3779 * If the user selects on a border boundary, return -1; if off the board,
3780 * return -2. Otherwise map the event coordinate to the square.
3782 int EventToSquare(x, limit)
3790 if ((x % (squareSize + lineGap)) >= squareSize)
3792 x /= (squareSize + lineGap);
3798 static void do_flash_delay(msec)
3804 static void drawHighlight(file, rank, gc)
3810 if (lineGap == 0 || appData.blindfold) return;
3813 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3814 (squareSize + lineGap);
3815 y = lineGap/2 + rank * (squareSize + lineGap);
3817 x = lineGap/2 + file * (squareSize + lineGap);
3818 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3819 (squareSize + lineGap);
3822 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3823 squareSize+lineGap, squareSize+lineGap);
3826 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3827 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3830 SetHighlights(fromX, fromY, toX, toY)
3831 int fromX, fromY, toX, toY;
3833 if (hi1X != fromX || hi1Y != fromY) {
3834 if (hi1X >= 0 && hi1Y >= 0) {
3835 drawHighlight(hi1X, hi1Y, lineGC);
3837 if (fromX >= 0 && fromY >= 0) {
3838 drawHighlight(fromX, fromY, highlineGC);
3841 if (hi2X != toX || hi2Y != toY) {
3842 if (hi2X >= 0 && hi2Y >= 0) {
3843 drawHighlight(hi2X, hi2Y, lineGC);
3845 if (toX >= 0 && toY >= 0) {
3846 drawHighlight(toX, toY, highlineGC);
3858 SetHighlights(-1, -1, -1, -1);
3863 SetPremoveHighlights(fromX, fromY, toX, toY)
3864 int fromX, fromY, toX, toY;
3866 if (pm1X != fromX || pm1Y != fromY) {
3867 if (pm1X >= 0 && pm1Y >= 0) {
3868 drawHighlight(pm1X, pm1Y, lineGC);
3870 if (fromX >= 0 && fromY >= 0) {
3871 drawHighlight(fromX, fromY, prelineGC);
3874 if (pm2X != toX || pm2Y != toY) {
3875 if (pm2X >= 0 && pm2Y >= 0) {
3876 drawHighlight(pm2X, pm2Y, lineGC);
3878 if (toX >= 0 && toY >= 0) {
3879 drawHighlight(toX, toY, prelineGC);
3889 ClearPremoveHighlights()
3891 SetPremoveHighlights(-1, -1, -1, -1);
3894 static void BlankSquare(x, y, color, piece, dest)
3899 if (useImages && useImageSqs) {
3903 pm = xpmLightSquare;
3908 case 2: /* neutral */
3913 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
3914 squareSize, squareSize, x, y);
3924 case 2: /* neutral */
3929 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
3934 I split out the routines to draw a piece so that I could
3935 make a generic flash routine.
3937 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
3939 int square_color, x, y;
3942 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3943 switch (square_color) {
3945 case 2: /* neutral */
3947 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3948 ? *pieceToOutline(piece)
3949 : *pieceToSolid(piece),
3950 dest, bwPieceGC, 0, 0,
3951 squareSize, squareSize, x, y);
3954 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3955 ? *pieceToSolid(piece)
3956 : *pieceToOutline(piece),
3957 dest, wbPieceGC, 0, 0,
3958 squareSize, squareSize, x, y);
3963 static void monoDrawPiece(piece, square_color, x, y, dest)
3965 int square_color, x, y;
3968 switch (square_color) {
3970 case 2: /* neutral */
3972 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3973 ? *pieceToOutline(piece)
3974 : *pieceToSolid(piece),
3975 dest, bwPieceGC, 0, 0,
3976 squareSize, squareSize, x, y, 1);
3979 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3980 ? *pieceToSolid(piece)
3981 : *pieceToOutline(piece),
3982 dest, wbPieceGC, 0, 0,
3983 squareSize, squareSize, x, y, 1);
3988 static void colorDrawPiece(piece, square_color, x, y, dest)
3990 int square_color, x, y;
3993 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
3994 switch (square_color) {
3996 XCopyPlane(xDisplay, *pieceToSolid(piece),
3997 dest, (int) piece < (int) BlackPawn
3998 ? wlPieceGC : blPieceGC, 0, 0,
3999 squareSize, squareSize, x, y, 1);
4002 XCopyPlane(xDisplay, *pieceToSolid(piece),
4003 dest, (int) piece < (int) BlackPawn
4004 ? wdPieceGC : bdPieceGC, 0, 0,
4005 squareSize, squareSize, x, y, 1);
4007 case 2: /* neutral */
4009 XCopyPlane(xDisplay, *pieceToSolid(piece),
4010 dest, (int) piece < (int) BlackPawn
4011 ? wjPieceGC : bjPieceGC, 0, 0,
4012 squareSize, squareSize, x, y, 1);
4017 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4019 int square_color, x, y;
4024 switch (square_color) {
4026 case 2: /* neutral */
4028 if ((int)piece < (int) BlackPawn) {
4036 if ((int)piece < (int) BlackPawn) {
4044 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4045 dest, wlPieceGC, 0, 0,
4046 squareSize, squareSize, x, y);
4049 typedef void (*DrawFunc)();
4051 DrawFunc ChooseDrawFunc()
4053 if (appData.monoMode) {
4054 if (DefaultDepth(xDisplay, xScreen) == 1) {
4055 return monoDrawPiece_1bit;
4057 return monoDrawPiece;
4061 return colorDrawPieceImage;
4063 return colorDrawPiece;
4067 /* [HR] determine square color depending on chess variant. */
4068 static int SquareColor(row, column)
4073 if (gameInfo.variant == VariantXiangqi) {
4074 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4076 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4078 } else if (row <= 4) {
4084 square_color = ((column + row) % 2) == 1;
4087 /* [hgm] holdings: next line makes all holdings squares light */
4088 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4090 return square_color;
4093 void DrawSquare(row, column, piece, do_flash)
4094 int row, column, do_flash;
4097 int square_color, x, y, direction, font_ascent, font_descent;
4100 XCharStruct overall;
4104 /* Calculate delay in milliseconds (2-delays per complete flash) */
4105 flash_delay = 500 / appData.flashRate;
4108 x = lineGap + ((BOARD_WIDTH-1)-column) *
4109 (squareSize + lineGap);
4110 y = lineGap + row * (squareSize + lineGap);
4112 x = lineGap + column * (squareSize + lineGap);
4113 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4114 (squareSize + lineGap);
4117 square_color = SquareColor(row, column);
4119 if ( // [HGM] holdings: blank out area between board and holdings
4120 column == BOARD_LEFT-1 || column == BOARD_RGHT
4121 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4122 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4123 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4125 // [HGM] print piece counts next to holdings
4126 string[1] = NULLCHAR;
4127 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4128 string[0] = '0' + piece;
4129 XTextExtents(countFontStruct, string, 1, &direction,
4130 &font_ascent, &font_descent, &overall);
4131 if (appData.monoMode) {
4132 XDrawImageString(xDisplay, xBoardWindow, countGC,
4133 x + squareSize - overall.width - 2,
4134 y + font_ascent + 1, string, 1);
4136 XDrawString(xDisplay, xBoardWindow, countGC,
4137 x + squareSize - overall.width - 2,
4138 y + font_ascent + 1, string, 1);
4141 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4142 string[0] = '0' + piece;
4143 XTextExtents(countFontStruct, string, 1, &direction,
4144 &font_ascent, &font_descent, &overall);
4145 if (appData.monoMode) {
4146 XDrawImageString(xDisplay, xBoardWindow, countGC,
4147 x + 2, y + font_ascent + 1, string, 1);
4149 XDrawString(xDisplay, xBoardWindow, countGC,
4150 x + 2, y + font_ascent + 1, string, 1);
4154 if (piece == EmptySquare || appData.blindfold) {
4155 BlankSquare(x, y, square_color, piece, xBoardWindow);
4157 drawfunc = ChooseDrawFunc();
4158 if (do_flash && appData.flashCount > 0) {
4159 for (i=0; i<appData.flashCount; ++i) {
4161 drawfunc(piece, square_color, x, y, xBoardWindow);
4162 XSync(xDisplay, False);
4163 do_flash_delay(flash_delay);
4165 BlankSquare(x, y, square_color, piece, xBoardWindow);
4166 XSync(xDisplay, False);
4167 do_flash_delay(flash_delay);
4170 drawfunc(piece, square_color, x, y, xBoardWindow);
4174 string[1] = NULLCHAR;
4175 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4176 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4177 string[0] = 'a' + column - BOARD_LEFT;
4178 XTextExtents(coordFontStruct, string, 1, &direction,
4179 &font_ascent, &font_descent, &overall);
4180 if (appData.monoMode) {
4181 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4182 x + squareSize - overall.width - 2,
4183 y + squareSize - font_descent - 1, string, 1);
4185 XDrawString(xDisplay, xBoardWindow, coordGC,
4186 x + squareSize - overall.width - 2,
4187 y + squareSize - font_descent - 1, string, 1);
4190 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4191 string[0] = ONE + row;
4192 XTextExtents(coordFontStruct, string, 1, &direction,
4193 &font_ascent, &font_descent, &overall);
4194 if (appData.monoMode) {
4195 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4196 x + 2, y + font_ascent + 1, string, 1);
4198 XDrawString(xDisplay, xBoardWindow, coordGC,
4199 x + 2, y + font_ascent + 1, string, 1);
4202 if(marker[row][column]) {
4203 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4204 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4209 /* Why is this needed on some versions of X? */
4210 void EventProc(widget, unused, event)
4215 if (!XtIsRealized(widget))
4218 switch (event->type) {
4220 if (event->xexpose.count > 0) return; /* no clipping is done */
4221 XDrawPosition(widget, True, NULL);
4229 void DrawPosition(fullRedraw, board)
4230 /*Boolean*/int fullRedraw;
4233 XDrawPosition(boardWidget, fullRedraw, board);
4236 /* Returns 1 if there are "too many" differences between b1 and b2
4237 (i.e. more than 1 move was made) */
4238 static int too_many_diffs(b1, b2)
4244 for (i=0; i<BOARD_HEIGHT; ++i) {
4245 for (j=0; j<BOARD_WIDTH; ++j) {
4246 if (b1[i][j] != b2[i][j]) {
4247 if (++c > 4) /* Castling causes 4 diffs */