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 { "SetFilterProc", SetFilterProc },
854 { "ReloadGameProc", ReloadGameProc },
855 { "LoadPositionProc", LoadPositionProc },
856 { "LoadNextPositionProc", LoadNextPositionProc },
857 { "LoadPrevPositionProc", LoadPrevPositionProc },
858 { "ReloadPositionProc", ReloadPositionProc },
859 { "CopyPositionProc", CopyPositionProc },
860 { "PastePositionProc", PastePositionProc },
861 { "CopyGameProc", CopyGameProc },
862 { "PasteGameProc", PasteGameProc },
863 { "SaveGameProc", SaveGameProc },
864 { "SavePositionProc", SavePositionProc },
865 { "MailMoveProc", MailMoveProc },
866 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
867 { "QuitProc", QuitProc },
868 { "MachineWhiteProc", MachineWhiteProc },
869 { "MachineBlackProc", MachineBlackProc },
870 { "AnalysisModeProc", AnalyzeModeProc },
871 { "AnalyzeFileProc", AnalyzeFileProc },
872 { "TwoMachinesProc", TwoMachinesProc },
873 { "IcsClientProc", IcsClientProc },
874 { "EditGameProc", EditGameProc },
875 { "EditPositionProc", EditPositionProc },
876 { "TrainingProc", EditPositionProc },
877 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
878 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
879 { "ShowGameListProc", ShowGameListProc },
880 { "ShowMoveListProc", HistoryShowProc},
881 { "EditTagsProc", EditCommentProc },
882 { "EditCommentProc", EditCommentProc },
883 { "IcsAlarmProc", IcsAlarmProc },
884 { "IcsInputBoxProc", IcsInputBoxProc },
885 { "PauseProc", PauseProc },
886 { "AcceptProc", AcceptProc },
887 { "DeclineProc", DeclineProc },
888 { "RematchProc", RematchProc },
889 { "CallFlagProc", CallFlagProc },
890 { "DrawProc", DrawProc },
891 { "AdjournProc", AdjournProc },
892 { "AbortProc", AbortProc },
893 { "ResignProc", ResignProc },
894 { "AdjuWhiteProc", AdjuWhiteProc },
895 { "AdjuBlackProc", AdjuBlackProc },
896 { "AdjuDrawProc", AdjuDrawProc },
897 { "EnterKeyProc", EnterKeyProc },
898 { "StopObservingProc", StopObservingProc },
899 { "StopExaminingProc", StopExaminingProc },
900 { "BackwardProc", BackwardProc },
901 { "ForwardProc", ForwardProc },
902 { "ToStartProc", ToStartProc },
903 { "ToEndProc", ToEndProc },
904 { "RevertProc", RevertProc },
905 { "TruncateGameProc", TruncateGameProc },
906 { "MoveNowProc", MoveNowProc },
907 { "RetractMoveProc", RetractMoveProc },
908 { "AlwaysQueenProc", AlwaysQueenProc },
909 { "AnimateDraggingProc", AnimateDraggingProc },
910 { "AnimateMovingProc", AnimateMovingProc },
911 { "AutoflagProc", AutoflagProc },
912 { "AutoflipProc", AutoflipProc },
913 { "AutobsProc", AutobsProc },
914 { "AutoraiseProc", AutoraiseProc },
915 { "AutosaveProc", AutosaveProc },
916 { "BlindfoldProc", BlindfoldProc },
917 { "FlashMovesProc", FlashMovesProc },
918 { "FlipViewProc", FlipViewProc },
919 { "GetMoveListProc", GetMoveListProc },
921 { "HighlightDraggingProc", HighlightDraggingProc },
923 { "HighlightLastMoveProc", HighlightLastMoveProc },
924 { "IcsAlarmProc", IcsAlarmProc },
925 { "MoveSoundProc", MoveSoundProc },
926 { "OldSaveStyleProc", OldSaveStyleProc },
927 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
928 { "PonderNextMoveProc", PonderNextMoveProc },
929 { "PopupExitMessageProc", PopupExitMessageProc },
930 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
931 { "PremoveProc", PremoveProc },
932 { "QuietPlayProc", QuietPlayProc },
933 { "ShowCoordsProc", ShowCoordsProc },
934 { "ShowThinkingProc", ShowThinkingProc },
935 { "HideThinkingProc", HideThinkingProc },
936 { "TestLegalityProc", TestLegalityProc },
937 { "SaveSettingsProc", SaveSettingsProc },
938 { "SaveOnExitProc", SaveOnExitProc },
939 { "InfoProc", InfoProc },
940 { "ManProc", ManProc },
941 { "HintProc", HintProc },
942 { "BookProc", BookProc },
943 { "AboutGameProc", AboutGameProc },
944 { "AboutProc", AboutProc },
945 { "DebugProc", DebugProc },
946 { "NothingProc", NothingProc },
947 { "CommentPopDown", (XtActionProc) CommentPopDown },
948 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
949 { "TagsPopDown", (XtActionProc) TagsPopDown },
950 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
951 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
952 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
953 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
954 { "GameListPopDown", (XtActionProc) GameListPopDown },
955 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
956 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
957 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
958 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
959 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
960 { "EnginePopDown", (XtActionProc) EnginePopDown },
961 { "UciPopDown", (XtActionProc) UciPopDown },
962 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
963 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
964 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
965 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
968 char globalTranslations[] =
969 ":<Key>R: ResignProc() \n \
970 :<Key>r: ResetProc() \n \
971 :<Key>g: LoadGameProc() \n \
972 :<Key>N: LoadNextGameProc() \n \
973 :<Key>P: LoadPrevGameProc() \n \
974 :<Key>Q: QuitProc() \n \
975 :<Key>F: ToEndProc() \n \
976 :<Key>f: ForwardProc() \n \
977 :<Key>B: ToStartProc() \n \
978 :<Key>b: BackwardProc() \n \
979 :<Key>p: PauseProc() \n \
980 :<Key>d: DrawProc() \n \
981 :<Key>t: CallFlagProc() \n \
982 :<Key>i: Iconify() \n \
983 :<Key>c: Iconify() \n \
984 :<Key>v: FlipViewProc() \n \
985 <KeyDown>Control_L: BackwardProc() \n \
986 <KeyUp>Control_L: ForwardProc() \n \
987 <KeyDown>Control_R: BackwardProc() \n \
988 <KeyUp>Control_R: ForwardProc() \n \
989 Shift<Key>1: AskQuestionProc(\"Direct command\",\
990 \"Send to chess program:\",,1) \n \
991 Shift<Key>2: AskQuestionProc(\"Direct command\",\
992 \"Send to second chess program:\",,2) \n";
994 char boardTranslations[] =
995 "<Btn1Down>: HandleUserMove() \n \
996 <Btn1Up>: HandleUserMove() \n \
997 <Btn1Motion>: AnimateUserMove() \n \
998 <Btn3Motion>: HandlePV() \n \
999 <Btn3Up>: UnLoadPV() \n \
1000 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1001 PieceMenuPopup(menuB) \n \
1002 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1003 PieceMenuPopup(menuW) \n \
1004 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1005 PieceMenuPopup(menuW) \n \
1006 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1007 PieceMenuPopup(menuB) \n";
1009 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1010 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1012 char ICSInputTranslations[] =
1013 "<Key>Return: EnterKeyProc() \n";
1015 String xboardResources[] = {
1016 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1017 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1018 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1023 /* Max possible square size */
1024 #define MAXSQSIZE 256
1026 static int xpm_avail[MAXSQSIZE];
1028 #ifdef HAVE_DIR_STRUCT
1030 /* Extract piece size from filename */
1032 xpm_getsize(name, len, ext)
1043 if ((p=strchr(name, '.')) == NULL ||
1044 StrCaseCmp(p+1, ext) != 0)
1050 while (*p && isdigit(*p))
1057 /* Setup xpm_avail */
1059 xpm_getavail(dirname, ext)
1067 for (i=0; i<MAXSQSIZE; ++i)
1070 if (appData.debugMode)
1071 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1073 dir = opendir(dirname);
1076 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1077 programName, dirname);
1081 while ((ent=readdir(dir)) != NULL) {
1082 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1083 if (i > 0 && i < MAXSQSIZE)
1093 xpm_print_avail(fp, ext)
1099 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1100 for (i=1; i<MAXSQSIZE; ++i) {
1106 /* Return XPM piecesize closest to size */
1108 xpm_closest_to(dirname, size, ext)
1114 int sm_diff = MAXSQSIZE;
1118 xpm_getavail(dirname, ext);
1120 if (appData.debugMode)
1121 xpm_print_avail(stderr, ext);
1123 for (i=1; i<MAXSQSIZE; ++i) {
1126 diff = (diff<0) ? -diff : diff;
1127 if (diff < sm_diff) {
1135 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1141 #else /* !HAVE_DIR_STRUCT */
1142 /* If we are on a system without a DIR struct, we can't
1143 read the directory, so we can't collect a list of
1144 filenames, etc., so we can't do any size-fitting. */
1146 xpm_closest_to(dirname, size, ext)
1151 fprintf(stderr, _("\
1152 Warning: No DIR structure found on this system --\n\
1153 Unable to autosize for XPM/XIM pieces.\n\
1154 Please report this error to frankm@hiwaay.net.\n\
1155 Include system type & operating system in message.\n"));
1158 #endif /* HAVE_DIR_STRUCT */
1160 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1161 "magenta", "cyan", "white" };
1165 TextColors textColors[(int)NColorClasses];
1167 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1169 parse_color(str, which)
1173 char *p, buf[100], *d;
1176 if (strlen(str) > 99) /* watch bounds on buf */
1181 for (i=0; i<which; ++i) {
1188 /* Could be looking at something like:
1190 .. in which case we want to stop on a comma also */
1191 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1195 return -1; /* Use default for empty field */
1198 if (which == 2 || isdigit(*p))
1201 while (*p && isalpha(*p))
1206 for (i=0; i<8; ++i) {
1207 if (!StrCaseCmp(buf, cnames[i]))
1208 return which? (i+40) : (i+30);
1210 if (!StrCaseCmp(buf, "default")) return -1;
1212 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1217 parse_cpair(cc, str)
1221 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1222 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1227 /* bg and attr are optional */
1228 textColors[(int)cc].bg = parse_color(str, 1);
1229 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1230 textColors[(int)cc].attr = 0;
1236 /* Arrange to catch delete-window events */
1237 Atom wm_delete_window;
1239 CatchDeleteWindow(Widget w, String procname)
1242 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1243 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1244 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1251 XtSetArg(args[0], XtNiconic, False);
1252 XtSetValues(shellWidget, args, 1);
1254 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1257 //---------------------------------------------------------------------------------------------------------
1258 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1261 #define CW_USEDEFAULT (1<<31)
1262 #define ICS_TEXT_MENU_SIZE 90
1263 #define DEBUG_FILE "xboard.debug"
1264 #define SetCurrentDirectory chdir
1265 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1269 // these two must some day move to frontend.h, when they are implemented
1270 Boolean GameListIsUp();
1272 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1275 // front-end part of option handling
1277 // [HGM] This platform-dependent table provides the location for storing the color info
1278 extern char *crWhite, * crBlack;
1282 &appData.whitePieceColor,
1283 &appData.blackPieceColor,
1284 &appData.lightSquareColor,
1285 &appData.darkSquareColor,
1286 &appData.highlightSquareColor,
1287 &appData.premoveHighlightColor,
1288 &appData.lowTimeWarningColor,
1300 ParseFont(char *name, int number)
1301 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1303 case 0: // CLOCK_FONT
1304 appData.clockFont = strdup(name);
1306 case 1: // MESSAGE_FONT
1307 appData.font = strdup(name);
1309 case 2: // COORD_FONT
1310 appData.coordFont = strdup(name);
1319 { // only 2 fonts currently
1320 appData.clockFont = CLOCK_FONT_NAME;
1321 appData.coordFont = COORD_FONT_NAME;
1322 appData.font = DEFAULT_FONT_NAME;
1327 { // no-op, until we identify the code for this already in XBoard and move it here
1331 ParseColor(int n, char *name)
1332 { // in XBoard, just copy the color-name string
1333 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1337 ParseTextAttribs(ColorClass cc, char *s)
1339 (&appData.colorShout)[cc] = strdup(s);
1343 ParseBoardSize(void *addr, char *name)
1345 appData.boardSize = strdup(name);
1350 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1354 SetCommPortDefaults()
1355 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1358 // [HGM] args: these three cases taken out to stay in front-end
1360 SaveFontArg(FILE *f, ArgDescriptor *ad)
1363 switch((int)ad->argLoc) {
1364 case 0: // CLOCK_FONT
1365 name = appData.clockFont;
1367 case 1: // MESSAGE_FONT
1368 name = appData.font;
1370 case 2: // COORD_FONT
1371 name = appData.coordFont;
1376 // Do not save fonts for now, as the saved font would be board-size specific
1377 // and not suitable for a re-start at another board size
1378 // fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, name);
1383 { // nothing to do, as the sounds are at all times represented by their text-string names already
1387 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1388 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1389 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1393 SaveColor(FILE *f, ArgDescriptor *ad)
1394 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1395 if(colorVariable[(int)ad->argLoc])
1396 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1400 SaveBoardSize(FILE *f, char *name, void *addr)
1401 { // wrapper to shield back-end from BoardSize & sizeInfo
1402 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1406 ParseCommPortSettings(char *s)
1407 { // no such option in XBoard (yet)
1410 extern Widget engineOutputShell;
1411 extern Widget tagsShell, editTagsShell;
1413 GetActualPlacement(Widget wg, WindowPlacement *wp)
1423 XtSetArg(args[i], XtNx, &x); i++;
1424 XtSetArg(args[i], XtNy, &y); i++;
1425 XtSetArg(args[i], XtNwidth, &w); i++;
1426 XtSetArg(args[i], XtNheight, &h); i++;
1427 XtGetValues(wg, args, i);
1436 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1437 // In XBoard this will have to wait until awareness of window parameters is implemented
1438 GetActualPlacement(shellWidget, &wpMain);
1439 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1440 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1441 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1442 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1443 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1444 else GetActualPlacement(editShell, &wpComment);
1445 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1446 else GetActualPlacement(editTagsShell, &wpTags);
1450 PrintCommPortSettings(FILE *f, char *name)
1451 { // This option does not exist in XBoard
1455 MySearchPath(char *installDir, char *name, char *fullname)
1456 { // just append installDir and name. Perhaps ExpandPath should be used here?
1457 name = ExpandPathName(name);
1458 if(name && name[0] == '/') strcpy(fullname, name); else {
1459 sprintf(fullname, "%s%c%s", installDir, '/', name);
1465 MyGetFullPathName(char *name, char *fullname)
1466 { // should use ExpandPath?
1467 name = ExpandPathName(name);
1468 strcpy(fullname, name);
1473 EnsureOnScreen(int *x, int *y, int minX, int minY)
1480 { // [HGM] args: allows testing if main window is realized from back-end
1481 return xBoardWindow != 0;
1485 PopUpStartupDialog()
1486 { // start menu not implemented in XBoard
1489 ConvertToLine(int argc, char **argv)
1491 static char line[128*1024], buf[1024];
1495 for(i=1; i<argc; i++) {
1496 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1497 && argv[i][0] != '{' )
1498 sprintf(buf, "{%s} ", argv[i]);
1499 else sprintf(buf, "%s ", argv[i]);
1502 line[strlen(line)-1] = NULLCHAR;
1506 //--------------------------------------------------------------------------------------------
1509 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1511 #define BoardSize int
1512 void InitDrawingSizes(BoardSize boardSize, int flags)
1513 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1514 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1516 XtGeometryResult gres;
1519 if(!formWidget) return;
1522 * Enable shell resizing.
1524 shellArgs[0].value = (XtArgVal) &w;
1525 shellArgs[1].value = (XtArgVal) &h;
1526 XtGetValues(shellWidget, shellArgs, 2);
1528 shellArgs[4].value = 2*w; shellArgs[2].value = 10;
1529 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1530 XtSetValues(shellWidget, &shellArgs[2], 4);
1532 XtSetArg(args[0], XtNdefaultDistance, &sep);
1533 XtGetValues(formWidget, args, 1);
1535 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1536 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1539 XtSetArg(args[0], XtNwidth, boardWidth);
1540 XtSetArg(args[1], XtNheight, boardHeight);
1541 XtSetValues(boardWidget, args, 2);
1543 timerWidth = (boardWidth - sep) / 2;
1544 XtSetArg(args[0], XtNwidth, timerWidth);
1545 XtSetValues(whiteTimerWidget, args, 1);
1546 XtSetValues(blackTimerWidget, args, 1);
1548 XawFormDoLayout(formWidget, False);
1550 if (appData.titleInWindow) {
1552 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1553 XtSetArg(args[i], XtNheight, &h); i++;
1554 XtGetValues(titleWidget, args, i);
1556 w = boardWidth - 2*bor;
1558 XtSetArg(args[0], XtNwidth, &w);
1559 XtGetValues(menuBarWidget, args, 1);
1560 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1563 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1564 if (gres != XtGeometryYes && appData.debugMode) {
1566 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1567 programName, gres, w, h, wr, hr);
1571 XawFormDoLayout(formWidget, True);
1574 * Inhibit shell resizing.
1576 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW;
1577 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1578 shellArgs[4].value = shellArgs[2].value = w;
1579 shellArgs[5].value = shellArgs[3].value = h;
1580 XtSetValues(shellWidget, &shellArgs[0], 6);
1582 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1585 for(i=0; i<4; i++) {
1587 for(p=0; p<=(int)WhiteKing; p++)
1588 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1589 if(gameInfo.variant == VariantShogi) {
1590 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1591 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1592 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1593 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1594 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1597 if(gameInfo.variant == VariantGothic) {
1598 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1602 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1603 for(p=0; p<=(int)WhiteKing; p++)
1604 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1605 if(gameInfo.variant == VariantShogi) {
1606 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1607 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1608 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1609 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1610 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1613 if(gameInfo.variant == VariantGothic) {
1614 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1620 for(i=0; i<2; i++) {
1622 for(p=0; p<=(int)WhiteKing; p++)
1623 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1624 if(gameInfo.variant == VariantShogi) {
1625 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1626 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1627 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1628 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1629 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1632 if(gameInfo.variant == VariantGothic) {
1633 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1644 void EscapeExpand(char *p, char *q)
1645 { // [HGM] initstring: routine to shape up string arguments
1646 while(*p++ = *q++) if(p[-1] == '\\')
1648 case 'n': p[-1] = '\n'; break;
1649 case 'r': p[-1] = '\r'; break;
1650 case 't': p[-1] = '\t'; break;
1651 case '\\': p[-1] = '\\'; break;
1652 case 0: *p = 0; return;
1653 default: p[-1] = q[-1]; break;
1662 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1663 XSetWindowAttributes window_attributes;
1665 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1666 XrmValue vFrom, vTo;
1667 XtGeometryResult gres;
1670 int forceMono = False;
1672 srandom(time(0)); // [HGM] book: make random truly random
1674 setbuf(stdout, NULL);
1675 setbuf(stderr, NULL);
1678 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1679 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1683 programName = strrchr(argv[0], '/');
1684 if (programName == NULL)
1685 programName = argv[0];
1690 XtSetLanguageProc(NULL, NULL, NULL);
1691 bindtextdomain(PACKAGE, LOCALEDIR);
1692 textdomain(PACKAGE);
1696 XtAppInitialize(&appContext, "XBoard", shellOptions,
1697 XtNumber(shellOptions),
1698 &argc, argv, xboardResources, NULL, 0);
1699 appData.boardSize = "";
1700 InitAppData(ConvertToLine(argc, argv));
1702 if (p == NULL) p = "/tmp";
1703 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1704 gameCopyFilename = (char*) malloc(i);
1705 gamePasteFilename = (char*) malloc(i);
1706 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1707 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1709 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1710 clientResources, XtNumber(clientResources),
1713 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1714 static char buf[MSG_SIZ];
1715 EscapeExpand(buf, appData.initString);
1716 appData.initString = strdup(buf);
1717 EscapeExpand(buf, appData.secondInitString);
1718 appData.secondInitString = strdup(buf);
1719 EscapeExpand(buf, appData.firstComputerString);
1720 appData.firstComputerString = strdup(buf);
1721 EscapeExpand(buf, appData.secondComputerString);
1722 appData.secondComputerString = strdup(buf);
1725 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1728 if (chdir(chessDir) != 0) {
1729 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1735 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1736 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1737 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1738 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1741 setbuf(debugFP, NULL);
1744 /* [HGM,HR] make sure board size is acceptable */
1745 if(appData.NrFiles > BOARD_FILES ||
1746 appData.NrRanks > BOARD_RANKS )
1747 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1750 /* This feature does not work; animation needs a rewrite */
1751 appData.highlightDragging = FALSE;
1755 xDisplay = XtDisplay(shellWidget);
1756 xScreen = DefaultScreen(xDisplay);
1757 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1759 gameInfo.variant = StringToVariant(appData.variant);
1760 InitPosition(FALSE);
1763 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1765 if (isdigit(appData.boardSize[0])) {
1766 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1767 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1768 &fontPxlSize, &smallLayout, &tinyLayout);
1770 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1771 programName, appData.boardSize);
1775 /* Find some defaults; use the nearest known size */
1776 SizeDefaults *szd, *nearest;
1777 int distance = 99999;
1778 nearest = szd = sizeDefaults;
1779 while (szd->name != NULL) {
1780 if (abs(szd->squareSize - squareSize) < distance) {
1782 distance = abs(szd->squareSize - squareSize);
1783 if (distance == 0) break;
1787 if (i < 2) lineGap = nearest->lineGap;
1788 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1789 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1790 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1791 if (i < 6) smallLayout = nearest->smallLayout;
1792 if (i < 7) tinyLayout = nearest->tinyLayout;
1795 SizeDefaults *szd = sizeDefaults;
1796 if (*appData.boardSize == NULLCHAR) {
1797 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1798 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1801 if (szd->name == NULL) szd--;
1802 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1804 while (szd->name != NULL &&
1805 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1806 if (szd->name == NULL) {
1807 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1808 programName, appData.boardSize);
1812 squareSize = szd->squareSize;
1813 lineGap = szd->lineGap;
1814 clockFontPxlSize = szd->clockFontPxlSize;
1815 coordFontPxlSize = szd->coordFontPxlSize;
1816 fontPxlSize = szd->fontPxlSize;
1817 smallLayout = szd->smallLayout;
1818 tinyLayout = szd->tinyLayout;
1821 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1822 if (strlen(appData.pixmapDirectory) > 0) {
1823 p = ExpandPathName(appData.pixmapDirectory);
1825 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1826 appData.pixmapDirectory);
1829 if (appData.debugMode) {
1830 fprintf(stderr, _("\
1831 XBoard square size (hint): %d\n\
1832 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1834 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1835 if (appData.debugMode) {
1836 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1840 /* [HR] height treated separately (hacked) */
1841 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1842 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1843 if (appData.showJail == 1) {
1844 /* Jail on top and bottom */
1845 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1846 XtSetArg(boardArgs[2], XtNheight,
1847 boardHeight + 2*(lineGap + squareSize));
1848 } else if (appData.showJail == 2) {
1850 XtSetArg(boardArgs[1], XtNwidth,
1851 boardWidth + 2*(lineGap + squareSize));
1852 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1855 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1856 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1860 * Determine what fonts to use.
1862 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1863 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1864 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1865 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1866 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1867 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1868 appData.font = FindFont(appData.font, fontPxlSize);
1869 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1870 countFontStruct = XQueryFont(xDisplay, countFontID);
1871 // appData.font = FindFont(appData.font, fontPxlSize);
1873 xdb = XtDatabase(xDisplay);
1874 XrmPutStringResource(&xdb, "*font", appData.font);
1877 * Detect if there are not enough colors available and adapt.
1879 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1880 appData.monoMode = True;
1883 if (!appData.monoMode) {
1884 vFrom.addr = (caddr_t) appData.lightSquareColor;
1885 vFrom.size = strlen(appData.lightSquareColor);
1886 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1887 if (vTo.addr == NULL) {
1888 appData.monoMode = True;
1891 lightSquareColor = *(Pixel *) vTo.addr;
1894 if (!appData.monoMode) {
1895 vFrom.addr = (caddr_t) appData.darkSquareColor;
1896 vFrom.size = strlen(appData.darkSquareColor);
1897 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1898 if (vTo.addr == NULL) {
1899 appData.monoMode = True;
1902 darkSquareColor = *(Pixel *) vTo.addr;
1905 if (!appData.monoMode) {
1906 vFrom.addr = (caddr_t) appData.whitePieceColor;
1907 vFrom.size = strlen(appData.whitePieceColor);
1908 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1909 if (vTo.addr == NULL) {
1910 appData.monoMode = True;
1913 whitePieceColor = *(Pixel *) vTo.addr;
1916 if (!appData.monoMode) {
1917 vFrom.addr = (caddr_t) appData.blackPieceColor;
1918 vFrom.size = strlen(appData.blackPieceColor);
1919 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1920 if (vTo.addr == NULL) {
1921 appData.monoMode = True;
1924 blackPieceColor = *(Pixel *) vTo.addr;
1928 if (!appData.monoMode) {
1929 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1930 vFrom.size = strlen(appData.highlightSquareColor);
1931 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1932 if (vTo.addr == NULL) {
1933 appData.monoMode = True;
1936 highlightSquareColor = *(Pixel *) vTo.addr;
1940 if (!appData.monoMode) {
1941 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1942 vFrom.size = strlen(appData.premoveHighlightColor);
1943 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1944 if (vTo.addr == NULL) {
1945 appData.monoMode = True;
1948 premoveHighlightColor = *(Pixel *) vTo.addr;
1953 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1956 if (appData.bitmapDirectory == NULL ||
1957 appData.bitmapDirectory[0] == NULLCHAR)
1958 appData.bitmapDirectory = DEF_BITMAP_DIR;
1961 if (appData.lowTimeWarning && !appData.monoMode) {
1962 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
1963 vFrom.size = strlen(appData.lowTimeWarningColor);
1964 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1965 if (vTo.addr == NULL)
1966 appData.monoMode = True;
1968 lowTimeWarningColor = *(Pixel *) vTo.addr;
1971 if (appData.monoMode && appData.debugMode) {
1972 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1973 (unsigned long) XWhitePixel(xDisplay, xScreen),
1974 (unsigned long) XBlackPixel(xDisplay, xScreen));
1977 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1978 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1979 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1980 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1981 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1982 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1983 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1984 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1985 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1986 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1988 if (appData.colorize) {
1990 _("%s: can't parse color names; disabling colorization\n"),
1993 appData.colorize = FALSE;
1995 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
1996 textColors[ColorNone].attr = 0;
1998 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2004 layoutName = "tinyLayout";
2005 } else if (smallLayout) {
2006 layoutName = "smallLayout";
2008 layoutName = "normalLayout";
2010 /* Outer layoutWidget is there only to provide a name for use in
2011 resources that depend on the layout style */
2013 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2014 layoutArgs, XtNumber(layoutArgs));
2016 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2017 formArgs, XtNumber(formArgs));
2018 XtSetArg(args[0], XtNdefaultDistance, &sep);
2019 XtGetValues(formWidget, args, 1);
2022 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2023 XtSetArg(args[0], XtNtop, XtChainTop);
2024 XtSetArg(args[1], XtNbottom, XtChainTop);
2025 XtSetArg(args[2], XtNright, XtChainLeft);
2026 XtSetValues(menuBarWidget, args, 3);
2028 widgetList[j++] = whiteTimerWidget =
2029 XtCreateWidget("whiteTime", labelWidgetClass,
2030 formWidget, timerArgs, XtNumber(timerArgs));
2031 XtSetArg(args[0], XtNfont, clockFontStruct);
2032 XtSetArg(args[1], XtNtop, XtChainTop);
2033 XtSetArg(args[2], XtNbottom, XtChainTop);
2034 XtSetValues(whiteTimerWidget, args, 3);
2036 widgetList[j++] = blackTimerWidget =
2037 XtCreateWidget("blackTime", labelWidgetClass,
2038 formWidget, timerArgs, XtNumber(timerArgs));
2039 XtSetArg(args[0], XtNfont, clockFontStruct);
2040 XtSetArg(args[1], XtNtop, XtChainTop);
2041 XtSetArg(args[2], XtNbottom, XtChainTop);
2042 XtSetValues(blackTimerWidget, args, 3);
2044 if (appData.titleInWindow) {
2045 widgetList[j++] = titleWidget =
2046 XtCreateWidget("title", labelWidgetClass, formWidget,
2047 titleArgs, XtNumber(titleArgs));
2048 XtSetArg(args[0], XtNtop, XtChainTop);
2049 XtSetArg(args[1], XtNbottom, XtChainTop);
2050 XtSetValues(titleWidget, args, 2);
2053 if (appData.showButtonBar) {
2054 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2055 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2056 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2057 XtSetArg(args[2], XtNtop, XtChainTop);
2058 XtSetArg(args[3], XtNbottom, XtChainTop);
2059 XtSetValues(buttonBarWidget, args, 4);
2062 widgetList[j++] = messageWidget =
2063 XtCreateWidget("message", labelWidgetClass, formWidget,
2064 messageArgs, XtNumber(messageArgs));
2065 XtSetArg(args[0], XtNtop, XtChainTop);
2066 XtSetArg(args[1], XtNbottom, XtChainTop);
2067 XtSetValues(messageWidget, args, 2);
2069 widgetList[j++] = boardWidget =
2070 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2071 XtNumber(boardArgs));
2073 XtManageChildren(widgetList, j);
2075 timerWidth = (boardWidth - sep) / 2;
2076 XtSetArg(args[0], XtNwidth, timerWidth);
2077 XtSetValues(whiteTimerWidget, args, 1);
2078 XtSetValues(blackTimerWidget, args, 1);
2080 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2081 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2082 XtGetValues(whiteTimerWidget, args, 2);
2084 if (appData.showButtonBar) {
2085 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2086 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2087 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2091 * formWidget uses these constraints but they are stored
2095 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2096 XtSetValues(menuBarWidget, args, i);
2097 if (appData.titleInWindow) {
2100 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2101 XtSetValues(whiteTimerWidget, args, i);
2103 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2104 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2105 XtSetValues(blackTimerWidget, args, i);
2107 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2108 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2109 XtSetValues(titleWidget, args, i);
2111 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2112 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2113 XtSetValues(messageWidget, args, i);
2114 if (appData.showButtonBar) {
2116 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2117 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2118 XtSetValues(buttonBarWidget, args, i);
2122 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2123 XtSetValues(whiteTimerWidget, args, i);
2125 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2126 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2127 XtSetValues(blackTimerWidget, args, i);
2129 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2130 XtSetValues(titleWidget, args, i);
2132 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2133 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2134 XtSetValues(messageWidget, args, i);
2135 if (appData.showButtonBar) {
2137 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2138 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2139 XtSetValues(buttonBarWidget, args, i);
2144 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2145 XtSetValues(whiteTimerWidget, args, i);
2147 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2148 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2149 XtSetValues(blackTimerWidget, args, i);
2151 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2152 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2153 XtSetValues(messageWidget, args, i);
2154 if (appData.showButtonBar) {
2156 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2157 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2158 XtSetValues(buttonBarWidget, args, i);
2162 XtSetArg(args[0], XtNfromVert, messageWidget);
2163 XtSetArg(args[1], XtNtop, XtChainTop);
2164 XtSetArg(args[2], XtNbottom, XtChainBottom);
2165 XtSetArg(args[3], XtNleft, XtChainLeft);
2166 XtSetArg(args[4], XtNright, XtChainRight);
2167 XtSetValues(boardWidget, args, 5);
2169 XtRealizeWidget(shellWidget);
2172 XtSetArg(args[0], XtNx, wpMain.x);
2173 XtSetArg(args[1], XtNy, wpMain.y);
2174 XtSetValues(shellWidget, args, 2);
2178 * Correct the width of the message and title widgets.
2179 * It is not known why some systems need the extra fudge term.
2180 * The value "2" is probably larger than needed.
2182 XawFormDoLayout(formWidget, False);
2184 #define WIDTH_FUDGE 2
2186 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2187 XtSetArg(args[i], XtNheight, &h); i++;
2188 XtGetValues(messageWidget, args, i);
2189 if (appData.showButtonBar) {
2191 XtSetArg(args[i], XtNwidth, &w); i++;
2192 XtGetValues(buttonBarWidget, args, i);
2193 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2195 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2198 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2199 if (gres != XtGeometryYes && appData.debugMode) {
2200 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2201 programName, gres, w, h, wr, hr);
2204 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2205 /* The size used for the child widget in layout lags one resize behind
2206 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2208 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2209 if (gres != XtGeometryYes && appData.debugMode) {
2210 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2211 programName, gres, w, h, wr, hr);
2214 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2215 XtSetArg(args[1], XtNright, XtChainRight);
2216 XtSetValues(messageWidget, args, 2);
2218 if (appData.titleInWindow) {
2220 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2221 XtSetArg(args[i], XtNheight, &h); i++;
2222 XtGetValues(titleWidget, args, i);
2224 w = boardWidth - 2*bor;
2226 XtSetArg(args[0], XtNwidth, &w);
2227 XtGetValues(menuBarWidget, args, 1);
2228 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2231 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2232 if (gres != XtGeometryYes && appData.debugMode) {
2234 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2235 programName, gres, w, h, wr, hr);
2238 XawFormDoLayout(formWidget, True);
2240 xBoardWindow = XtWindow(boardWidget);
2242 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2243 // not need to go into InitDrawingSizes().
2247 * Create X checkmark bitmap and initialize option menu checks.
2249 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2250 checkmark_bits, checkmark_width, checkmark_height);
2251 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2252 if (appData.alwaysPromoteToQueen) {
2253 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2256 if (appData.animateDragging) {
2257 XtSetValues(XtNameToWidget(menuBarWidget,
2258 "menuOptions.Animate Dragging"),
2261 if (appData.animate) {
2262 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2265 if (appData.autoComment) {
2266 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2269 if (appData.autoCallFlag) {
2270 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2273 if (appData.autoFlipView) {
2274 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2277 if (appData.autoObserve) {
2278 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2281 if (appData.autoRaiseBoard) {
2282 XtSetValues(XtNameToWidget(menuBarWidget,
2283 "menuOptions.Auto Raise Board"), args, 1);
2285 if (appData.autoSaveGames) {
2286 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2289 if (appData.saveGameFile[0] != NULLCHAR) {
2290 /* Can't turn this off from menu */
2291 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2293 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2297 if (appData.blindfold) {
2298 XtSetValues(XtNameToWidget(menuBarWidget,
2299 "menuOptions.Blindfold"), args, 1);
2301 if (appData.flashCount > 0) {
2302 XtSetValues(XtNameToWidget(menuBarWidget,
2303 "menuOptions.Flash Moves"),
2306 if (appData.getMoveList) {
2307 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2311 if (appData.highlightDragging) {
2312 XtSetValues(XtNameToWidget(menuBarWidget,
2313 "menuOptions.Highlight Dragging"),
2317 if (appData.highlightLastMove) {
2318 XtSetValues(XtNameToWidget(menuBarWidget,
2319 "menuOptions.Highlight Last Move"),
2322 if (appData.icsAlarm) {
2323 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2326 if (appData.ringBellAfterMoves) {
2327 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2330 if (appData.oldSaveStyle) {
2331 XtSetValues(XtNameToWidget(menuBarWidget,
2332 "menuOptions.Old Save Style"), args, 1);
2334 if (appData.periodicUpdates) {
2335 XtSetValues(XtNameToWidget(menuBarWidget,
2336 "menuOptions.Periodic Updates"), args, 1);
2338 if (appData.ponderNextMove) {
2339 XtSetValues(XtNameToWidget(menuBarWidget,
2340 "menuOptions.Ponder Next Move"), args, 1);
2342 if (appData.popupExitMessage) {
2343 XtSetValues(XtNameToWidget(menuBarWidget,
2344 "menuOptions.Popup Exit Message"), args, 1);
2346 if (appData.popupMoveErrors) {
2347 XtSetValues(XtNameToWidget(menuBarWidget,
2348 "menuOptions.Popup Move Errors"), args, 1);
2350 if (appData.premove) {
2351 XtSetValues(XtNameToWidget(menuBarWidget,
2352 "menuOptions.Premove"), args, 1);
2354 if (appData.quietPlay) {
2355 XtSetValues(XtNameToWidget(menuBarWidget,
2356 "menuOptions.Quiet Play"), args, 1);
2358 if (appData.showCoords) {
2359 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2362 if (appData.hideThinkingFromHuman) {
2363 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2366 if (appData.testLegality) {
2367 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2370 if (saveSettingsOnExit) {
2371 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2378 ReadBitmap(&wIconPixmap, "icon_white.bm",
2379 icon_white_bits, icon_white_width, icon_white_height);
2380 ReadBitmap(&bIconPixmap, "icon_black.bm",
2381 icon_black_bits, icon_black_width, icon_black_height);
2382 iconPixmap = wIconPixmap;
2384 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2385 XtSetValues(shellWidget, args, i);
2388 * Create a cursor for the board widget.
2390 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2391 XChangeWindowAttributes(xDisplay, xBoardWindow,
2392 CWCursor, &window_attributes);
2395 * Inhibit shell resizing.
2397 shellArgs[0].value = (XtArgVal) &w;
2398 shellArgs[1].value = (XtArgVal) &h;
2399 XtGetValues(shellWidget, shellArgs, 2);
2400 shellArgs[4].value = shellArgs[2].value = w;
2401 shellArgs[5].value = shellArgs[3].value = h;
2402 XtSetValues(shellWidget, &shellArgs[2], 4);
2403 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2404 marginH = h - boardHeight;
2406 CatchDeleteWindow(shellWidget, "QuitProc");
2411 if (appData.bitmapDirectory[0] != NULLCHAR) {
2418 /* Create regular pieces */
2419 if (!useImages) CreatePieces();
2424 if (appData.animate || appData.animateDragging)
2427 XtAugmentTranslations(formWidget,
2428 XtParseTranslationTable(globalTranslations));
2429 XtAugmentTranslations(boardWidget,
2430 XtParseTranslationTable(boardTranslations));
2431 XtAugmentTranslations(whiteTimerWidget,
2432 XtParseTranslationTable(whiteTranslations));
2433 XtAugmentTranslations(blackTimerWidget,
2434 XtParseTranslationTable(blackTranslations));
2436 /* Why is the following needed on some versions of X instead
2437 * of a translation? */
2438 XtAddEventHandler(boardWidget, ExposureMask, False,
2439 (XtEventHandler) EventProc, NULL);
2442 /* [AS] Restore layout */
2443 if( wpMoveHistory.visible ) {
2447 if( wpEvalGraph.visible )
2452 if( wpEngineOutput.visible ) {
2453 EngineOutputPopUp();
2458 if (errorExitStatus == -1) {
2459 if (appData.icsActive) {
2460 /* We now wait until we see "login:" from the ICS before
2461 sending the logon script (problems with timestamp otherwise) */
2462 /*ICSInitScript();*/
2463 if (appData.icsInputBox) ICSInputBoxPopUp();
2467 signal(SIGWINCH, TermSizeSigHandler);
2469 signal(SIGINT, IntSigHandler);
2470 signal(SIGTERM, IntSigHandler);
2471 if (*appData.cmailGameName != NULLCHAR) {
2472 signal(SIGUSR1, CmailSigHandler);
2475 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2478 XtAppMainLoop(appContext);
2479 if (appData.debugMode) fclose(debugFP); // [DM] debug
2486 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2487 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2489 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2490 unlink(gameCopyFilename);
2491 unlink(gamePasteFilename);
2494 RETSIGTYPE TermSizeSigHandler(int sig)
2507 CmailSigHandler(sig)
2513 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2515 /* Activate call-back function CmailSigHandlerCallBack() */
2516 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2518 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2522 CmailSigHandlerCallBack(isr, closure, message, count, error)
2530 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2532 /**** end signal code ****/
2542 f = fopen(appData.icsLogon, "r");
2548 strcat(buf, appData.icsLogon);
2549 f = fopen(buf, "r");
2553 ProcessICSInitScript(f);
2560 EditCommentPopDown();
2575 if (!menuBarWidget) return;
2576 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2578 DisplayError("menuStep.Revert", 0);
2580 XtSetSensitive(w, !grey);
2585 SetMenuEnables(enab)
2589 if (!menuBarWidget) return;
2590 while (enab->name != NULL) {
2591 w = XtNameToWidget(menuBarWidget, enab->name);
2593 DisplayError(enab->name, 0);
2595 XtSetSensitive(w, enab->value);
2601 Enables icsEnables[] = {
2602 { "menuFile.Mail Move", False },
2603 { "menuFile.Reload CMail Message", False },
2604 { "menuMode.Machine Black", False },
2605 { "menuMode.Machine White", False },
2606 { "menuMode.Analysis Mode", False },
2607 { "menuMode.Analyze File", False },
2608 { "menuMode.Two Machines", False },
2610 { "menuHelp.Hint", False },
2611 { "menuHelp.Book", False },
2612 { "menuStep.Move Now", False },
2613 { "menuOptions.Periodic Updates", False },
2614 { "menuOptions.Hide Thinking", False },
2615 { "menuOptions.Ponder Next Move", False },
2620 Enables ncpEnables[] = {
2621 { "menuFile.Mail Move", False },
2622 { "menuFile.Reload CMail Message", False },
2623 { "menuMode.Machine White", False },
2624 { "menuMode.Machine Black", False },
2625 { "menuMode.Analysis Mode", False },
2626 { "menuMode.Analyze File", False },
2627 { "menuMode.Two Machines", False },
2628 { "menuMode.ICS Client", False },
2629 { "menuMode.ICS Input Box", False },
2630 { "Action", False },
2631 { "menuStep.Revert", False },
2632 { "menuStep.Move Now", False },
2633 { "menuStep.Retract Move", False },
2634 { "menuOptions.Auto Comment", False },
2635 { "menuOptions.Auto Flag", False },
2636 { "menuOptions.Auto Flip View", False },
2637 { "menuOptions.Auto Observe", False },
2638 { "menuOptions.Auto Raise Board", False },
2639 { "menuOptions.Get Move List", False },
2640 { "menuOptions.ICS Alarm", False },
2641 { "menuOptions.Move Sound", False },
2642 { "menuOptions.Quiet Play", False },
2643 { "menuOptions.Hide Thinking", False },
2644 { "menuOptions.Periodic Updates", False },
2645 { "menuOptions.Ponder Next Move", False },
2646 { "menuHelp.Hint", False },
2647 { "menuHelp.Book", False },
2651 Enables gnuEnables[] = {
2652 { "menuMode.ICS Client", False },
2653 { "menuMode.ICS Input Box", False },
2654 { "menuAction.Accept", False },
2655 { "menuAction.Decline", False },
2656 { "menuAction.Rematch", False },
2657 { "menuAction.Adjourn", False },
2658 { "menuAction.Stop Examining", False },
2659 { "menuAction.Stop Observing", False },
2660 { "menuStep.Revert", False },
2661 { "menuOptions.Auto Comment", False },
2662 { "menuOptions.Auto Observe", False },
2663 { "menuOptions.Auto Raise Board", False },
2664 { "menuOptions.Get Move List", False },
2665 { "menuOptions.Premove", False },
2666 { "menuOptions.Quiet Play", False },
2668 /* The next two options rely on SetCmailMode being called *after* */
2669 /* SetGNUMode so that when GNU is being used to give hints these */
2670 /* menu options are still available */
2672 { "menuFile.Mail Move", False },
2673 { "menuFile.Reload CMail Message", False },
2677 Enables cmailEnables[] = {
2679 { "menuAction.Call Flag", False },
2680 { "menuAction.Draw", True },
2681 { "menuAction.Adjourn", False },
2682 { "menuAction.Abort", False },
2683 { "menuAction.Stop Observing", False },
2684 { "menuAction.Stop Examining", False },
2685 { "menuFile.Mail Move", True },
2686 { "menuFile.Reload CMail Message", True },
2690 Enables trainingOnEnables[] = {
2691 { "menuMode.Edit Comment", False },
2692 { "menuMode.Pause", False },
2693 { "menuStep.Forward", False },
2694 { "menuStep.Backward", False },
2695 { "menuStep.Forward to End", False },
2696 { "menuStep.Back to Start", False },
2697 { "menuStep.Move Now", False },
2698 { "menuStep.Truncate Game", False },
2702 Enables trainingOffEnables[] = {
2703 { "menuMode.Edit Comment", True },
2704 { "menuMode.Pause", True },
2705 { "menuStep.Forward", True },
2706 { "menuStep.Backward", True },
2707 { "menuStep.Forward to End", True },
2708 { "menuStep.Back to Start", True },
2709 { "menuStep.Move Now", True },
2710 { "menuStep.Truncate Game", True },
2714 Enables machineThinkingEnables[] = {
2715 { "menuFile.Load Game", False },
2716 { "menuFile.Load Next Game", False },
2717 { "menuFile.Load Previous Game", False },
2718 { "menuFile.Reload Same Game", False },
2719 { "menuFile.Paste Game", False },
2720 { "menuFile.Load Position", False },
2721 { "menuFile.Load Next Position", False },
2722 { "menuFile.Load Previous Position", False },
2723 { "menuFile.Reload Same Position", False },
2724 { "menuFile.Paste Position", False },
2725 { "menuMode.Machine White", False },
2726 { "menuMode.Machine Black", False },
2727 { "menuMode.Two Machines", False },
2728 { "menuStep.Retract Move", False },
2732 Enables userThinkingEnables[] = {
2733 { "menuFile.Load Game", True },
2734 { "menuFile.Load Next Game", True },
2735 { "menuFile.Load Previous Game", True },
2736 { "menuFile.Reload Same Game", True },
2737 { "menuFile.Paste Game", True },
2738 { "menuFile.Load Position", True },
2739 { "menuFile.Load Next Position", True },
2740 { "menuFile.Load Previous Position", True },
2741 { "menuFile.Reload Same Position", True },
2742 { "menuFile.Paste Position", True },
2743 { "menuMode.Machine White", True },
2744 { "menuMode.Machine Black", True },
2745 { "menuMode.Two Machines", True },
2746 { "menuStep.Retract Move", True },
2752 SetMenuEnables(icsEnables);
2755 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2756 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2763 SetMenuEnables(ncpEnables);
2769 SetMenuEnables(gnuEnables);
2775 SetMenuEnables(cmailEnables);
2781 SetMenuEnables(trainingOnEnables);
2782 if (appData.showButtonBar) {
2783 XtSetSensitive(buttonBarWidget, False);
2789 SetTrainingModeOff()
2791 SetMenuEnables(trainingOffEnables);
2792 if (appData.showButtonBar) {
2793 XtSetSensitive(buttonBarWidget, True);
2798 SetUserThinkingEnables()
2800 if (appData.noChessProgram) return;
2801 SetMenuEnables(userThinkingEnables);
2805 SetMachineThinkingEnables()
2807 if (appData.noChessProgram) return;
2808 SetMenuEnables(machineThinkingEnables);
2810 case MachinePlaysBlack:
2811 case MachinePlaysWhite:
2812 case TwoMachinesPlay:
2813 XtSetSensitive(XtNameToWidget(menuBarWidget,
2814 ModeToWidgetName(gameMode)), True);
2821 #define Abs(n) ((n)<0 ? -(n) : (n))
2824 * Find a font that matches "pattern" that is as close as
2825 * possible to the targetPxlSize. Prefer fonts that are k
2826 * pixels smaller to fonts that are k pixels larger. The
2827 * pattern must be in the X Consortium standard format,
2828 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2829 * The return value should be freed with XtFree when no
2832 char *FindFont(pattern, targetPxlSize)
2836 char **fonts, *p, *best, *scalable, *scalableTail;
2837 int i, j, nfonts, minerr, err, pxlSize;
2840 char **missing_list;
2842 char *def_string, *base_fnt_lst, strInt[3];
2844 XFontStruct **fnt_list;
2846 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2847 sprintf(strInt, "%d", targetPxlSize);
2848 p = strstr(pattern, "--");
2849 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2850 strcat(base_fnt_lst, strInt);
2851 strcat(base_fnt_lst, strchr(p + 2, '-'));
2853 if ((fntSet = XCreateFontSet(xDisplay,
2857 &def_string)) == NULL) {
2859 fprintf(stderr, _("Unable to create font set.\n"));
2863 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2865 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2867 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2868 programName, pattern);
2876 for (i=0; i<nfonts; i++) {
2879 if (*p != '-') continue;
2881 if (*p == NULLCHAR) break;
2882 if (*p++ == '-') j++;
2884 if (j < 7) continue;
2887 scalable = fonts[i];
2890 err = pxlSize - targetPxlSize;
2891 if (Abs(err) < Abs(minerr) ||
2892 (minerr > 0 && err < 0 && -err == minerr)) {
2898 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
2899 /* If the error is too big and there is a scalable font,
2900 use the scalable font. */
2901 int headlen = scalableTail - scalable;
2902 p = (char *) XtMalloc(strlen(scalable) + 10);
2903 while (isdigit(*scalableTail)) scalableTail++;
2904 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
2906 p = (char *) XtMalloc(strlen(best) + 1);
2909 if (appData.debugMode) {
2910 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
2911 pattern, targetPxlSize, p);
2914 if (missing_count > 0)
2915 XFreeStringList(missing_list);
2916 XFreeFontSet(xDisplay, fntSet);
2918 XFreeFontNames(fonts);
2925 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
2926 | GCBackground | GCFunction | GCPlaneMask;
2927 XGCValues gc_values;
2930 gc_values.plane_mask = AllPlanes;
2931 gc_values.line_width = lineGap;
2932 gc_values.line_style = LineSolid;
2933 gc_values.function = GXcopy;
2935 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2936 gc_values.background = XBlackPixel(xDisplay, xScreen);
2937 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2939 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2940 gc_values.background = XWhitePixel(xDisplay, xScreen);
2941 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
2942 XSetFont(xDisplay, coordGC, coordFontID);
2944 // [HGM] make font for holdings counts (white on black0
2945 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2946 gc_values.background = XBlackPixel(xDisplay, xScreen);
2947 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
2948 XSetFont(xDisplay, countGC, countFontID);
2950 if (appData.monoMode) {
2951 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2952 gc_values.background = XWhitePixel(xDisplay, xScreen);
2953 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2955 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2956 gc_values.background = XBlackPixel(xDisplay, xScreen);
2957 lightSquareGC = wbPieceGC
2958 = XtGetGC(shellWidget, value_mask, &gc_values);
2960 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2961 gc_values.background = XWhitePixel(xDisplay, xScreen);
2962 darkSquareGC = bwPieceGC
2963 = XtGetGC(shellWidget, value_mask, &gc_values);
2965 if (DefaultDepth(xDisplay, xScreen) == 1) {
2966 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
2967 gc_values.function = GXcopyInverted;
2968 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
2969 gc_values.function = GXcopy;
2970 if (XBlackPixel(xDisplay, xScreen) == 1) {
2971 bwPieceGC = darkSquareGC;
2972 wbPieceGC = copyInvertedGC;
2974 bwPieceGC = copyInvertedGC;
2975 wbPieceGC = lightSquareGC;
2979 gc_values.foreground = highlightSquareColor;
2980 gc_values.background = highlightSquareColor;
2981 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2983 gc_values.foreground = premoveHighlightColor;
2984 gc_values.background = premoveHighlightColor;
2985 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2987 gc_values.foreground = lightSquareColor;
2988 gc_values.background = darkSquareColor;
2989 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2991 gc_values.foreground = darkSquareColor;
2992 gc_values.background = lightSquareColor;
2993 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2995 gc_values.foreground = jailSquareColor;
2996 gc_values.background = jailSquareColor;
2997 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2999 gc_values.foreground = whitePieceColor;
3000 gc_values.background = darkSquareColor;
3001 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3003 gc_values.foreground = whitePieceColor;
3004 gc_values.background = lightSquareColor;
3005 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3007 gc_values.foreground = whitePieceColor;
3008 gc_values.background = jailSquareColor;
3009 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3011 gc_values.foreground = blackPieceColor;
3012 gc_values.background = darkSquareColor;
3013 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3015 gc_values.foreground = blackPieceColor;
3016 gc_values.background = lightSquareColor;
3017 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3019 gc_values.foreground = blackPieceColor;
3020 gc_values.background = jailSquareColor;
3021 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3025 void loadXIM(xim, xmask, filename, dest, mask)
3038 fp = fopen(filename, "rb");
3040 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3047 for (y=0; y<h; ++y) {
3048 for (x=0; x<h; ++x) {
3053 XPutPixel(xim, x, y, blackPieceColor);
3055 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3058 XPutPixel(xim, x, y, darkSquareColor);
3060 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3063 XPutPixel(xim, x, y, whitePieceColor);
3065 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3068 XPutPixel(xim, x, y, lightSquareColor);
3070 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3076 /* create Pixmap of piece */
3077 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3079 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3082 /* create Pixmap of clipmask
3083 Note: We assume the white/black pieces have the same
3084 outline, so we make only 6 masks. This is okay
3085 since the XPM clipmask routines do the same. */
3087 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3089 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3092 /* now create the 1-bit version */
3093 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3096 values.foreground = 1;
3097 values.background = 0;
3099 /* Don't use XtGetGC, not read only */
3100 maskGC = XCreateGC(xDisplay, *mask,
3101 GCForeground | GCBackground, &values);
3102 XCopyPlane(xDisplay, temp, *mask, maskGC,
3103 0, 0, squareSize, squareSize, 0, 0, 1);
3104 XFreePixmap(xDisplay, temp);
3109 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3111 void CreateXIMPieces()
3116 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3121 /* The XSynchronize calls were copied from CreatePieces.
3122 Not sure if needed, but can't hurt */
3123 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3126 /* temp needed by loadXIM() */
3127 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3128 0, 0, ss, ss, AllPlanes, XYPixmap);
3130 if (strlen(appData.pixmapDirectory) == 0) {
3134 if (appData.monoMode) {
3135 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3139 fprintf(stderr, _("\nLoading XIMs...\n"));
3141 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3142 fprintf(stderr, "%d", piece+1);
3143 for (kind=0; kind<4; kind++) {
3144 fprintf(stderr, ".");
3145 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3146 ExpandPathName(appData.pixmapDirectory),
3147 piece <= (int) WhiteKing ? "" : "w",
3148 pieceBitmapNames[piece],
3150 ximPieceBitmap[kind][piece] =
3151 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3152 0, 0, ss, ss, AllPlanes, XYPixmap);
3153 if (appData.debugMode)
3154 fprintf(stderr, _("(File:%s:) "), buf);
3155 loadXIM(ximPieceBitmap[kind][piece],
3157 &(xpmPieceBitmap2[kind][piece]),
3158 &(ximMaskPm2[piece]));
3159 if(piece <= (int)WhiteKing)
3160 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3162 fprintf(stderr," ");
3164 /* Load light and dark squares */
3165 /* If the LSQ and DSQ pieces don't exist, we will
3166 draw them with solid squares. */
3167 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3168 if (access(buf, 0) != 0) {
3172 fprintf(stderr, _("light square "));
3174 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3175 0, 0, ss, ss, AllPlanes, XYPixmap);
3176 if (appData.debugMode)
3177 fprintf(stderr, _("(File:%s:) "), buf);
3179 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3180 fprintf(stderr, _("dark square "));
3181 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3182 ExpandPathName(appData.pixmapDirectory), ss);
3183 if (appData.debugMode)
3184 fprintf(stderr, _("(File:%s:) "), buf);
3186 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3187 0, 0, ss, ss, AllPlanes, XYPixmap);
3188 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3189 xpmJailSquare = xpmLightSquare;
3191 fprintf(stderr, _("Done.\n"));
3193 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3197 void CreateXPMPieces()
3201 u_int ss = squareSize;
3203 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3204 XpmColorSymbol symbols[4];
3206 /* The XSynchronize calls were copied from CreatePieces.
3207 Not sure if needed, but can't hurt */
3208 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3210 /* Setup translations so piece colors match square colors */
3211 symbols[0].name = "light_piece";
3212 symbols[0].value = appData.whitePieceColor;
3213 symbols[1].name = "dark_piece";
3214 symbols[1].value = appData.blackPieceColor;
3215 symbols[2].name = "light_square";
3216 symbols[2].value = appData.lightSquareColor;
3217 symbols[3].name = "dark_square";
3218 symbols[3].value = appData.darkSquareColor;
3220 attr.valuemask = XpmColorSymbols;
3221 attr.colorsymbols = symbols;
3222 attr.numsymbols = 4;
3224 if (appData.monoMode) {
3225 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3229 if (strlen(appData.pixmapDirectory) == 0) {
3230 XpmPieces* pieces = builtInXpms;
3233 while (pieces->size != squareSize && pieces->size) pieces++;
3234 if (!pieces->size) {
3235 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3238 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3239 for (kind=0; kind<4; kind++) {
3241 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3242 pieces->xpm[piece][kind],
3243 &(xpmPieceBitmap2[kind][piece]),
3244 NULL, &attr)) != 0) {
3245 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3249 if(piece <= (int) WhiteKing)
3250 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3254 xpmJailSquare = xpmLightSquare;
3258 fprintf(stderr, _("\nLoading XPMs...\n"));
3261 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3262 fprintf(stderr, "%d ", piece+1);
3263 for (kind=0; kind<4; kind++) {
3264 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3265 ExpandPathName(appData.pixmapDirectory),
3266 piece > (int) WhiteKing ? "w" : "",
3267 pieceBitmapNames[piece],
3269 if (appData.debugMode) {
3270 fprintf(stderr, _("(File:%s:) "), buf);
3272 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3273 &(xpmPieceBitmap2[kind][piece]),
3274 NULL, &attr)) != 0) {
3275 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3276 // [HGM] missing: read of unorthodox piece failed; substitute King.
3277 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3278 ExpandPathName(appData.pixmapDirectory),
3280 if (appData.debugMode) {
3281 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3283 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3284 &(xpmPieceBitmap2[kind][piece]),
3288 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3293 if(piece <= (int) WhiteKing)
3294 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3297 /* Load light and dark squares */
3298 /* If the LSQ and DSQ pieces don't exist, we will
3299 draw them with solid squares. */
3300 fprintf(stderr, _("light square "));
3301 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3302 if (access(buf, 0) != 0) {
3306 if (appData.debugMode)
3307 fprintf(stderr, _("(File:%s:) "), buf);
3309 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3310 &xpmLightSquare, NULL, &attr)) != 0) {
3311 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3314 fprintf(stderr, _("dark square "));
3315 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3316 ExpandPathName(appData.pixmapDirectory), ss);
3317 if (appData.debugMode) {
3318 fprintf(stderr, _("(File:%s:) "), buf);
3320 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3321 &xpmDarkSquare, NULL, &attr)) != 0) {
3322 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3326 xpmJailSquare = xpmLightSquare;
3327 fprintf(stderr, _("Done.\n"));
3329 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3332 #endif /* HAVE_LIBXPM */
3335 /* No built-in bitmaps */
3340 u_int ss = squareSize;
3342 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3345 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3346 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3347 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3348 pieceBitmapNames[piece],
3349 ss, kind == SOLID ? 's' : 'o');
3350 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3351 if(piece <= (int)WhiteKing)
3352 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3356 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3360 /* With built-in bitmaps */
3363 BuiltInBits* bib = builtInBits;
3366 u_int ss = squareSize;
3368 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3371 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3373 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3374 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3375 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3376 pieceBitmapNames[piece],
3377 ss, kind == SOLID ? 's' : 'o');
3378 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3379 bib->bits[kind][piece], ss, ss);
3380 if(piece <= (int)WhiteKing)
3381 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3385 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3390 void ReadBitmap(pm, name, bits, wreq, hreq)
3393 unsigned char bits[];
3399 char msg[MSG_SIZ], fullname[MSG_SIZ];
3401 if (*appData.bitmapDirectory != NULLCHAR) {
3402 strcpy(fullname, appData.bitmapDirectory);
3403 strcat(fullname, "/");
3404 strcat(fullname, name);
3405 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3406 &w, &h, pm, &x_hot, &y_hot);
3407 fprintf(stderr, "load %s\n", name);
3408 if (errcode != BitmapSuccess) {
3410 case BitmapOpenFailed:
3411 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3413 case BitmapFileInvalid:
3414 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3416 case BitmapNoMemory:
3417 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3421 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3425 fprintf(stderr, _("%s: %s...using built-in\n"),
3427 } else if (w != wreq || h != hreq) {
3429 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3430 programName, fullname, w, h, wreq, hreq);
3436 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3445 if (lineGap == 0) return;
3447 /* [HR] Split this into 2 loops for non-square boards. */
3449 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3450 gridSegments[i].x1 = 0;
3451 gridSegments[i].x2 =
3452 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3453 gridSegments[i].y1 = gridSegments[i].y2
3454 = lineGap / 2 + (i * (squareSize + lineGap));
3457 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3458 gridSegments[j + i].y1 = 0;
3459 gridSegments[j + i].y2 =
3460 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3461 gridSegments[j + i].x1 = gridSegments[j + i].x2
3462 = lineGap / 2 + (j * (squareSize + lineGap));
3466 static void MenuBarSelect(w, addr, index)
3471 XtActionProc proc = (XtActionProc) addr;
3473 (proc)(NULL, NULL, NULL, NULL);
3476 void CreateMenuBarPopup(parent, name, mb)
3486 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3489 XtSetArg(args[j], XtNleftMargin, 20); j++;
3490 XtSetArg(args[j], XtNrightMargin, 20); j++;
3492 while (mi->string != NULL) {
3493 if (strcmp(mi->string, "----") == 0) {
3494 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3497 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3498 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3500 XtAddCallback(entry, XtNcallback,
3501 (XtCallbackProc) MenuBarSelect,
3502 (caddr_t) mi->proc);
3508 Widget CreateMenuBar(mb)
3512 Widget anchor, menuBar;
3514 char menuName[MSG_SIZ];
3517 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3518 XtSetArg(args[j], XtNvSpace, 0); j++;
3519 XtSetArg(args[j], XtNborderWidth, 0); j++;
3520 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3521 formWidget, args, j);
3523 while (mb->name != NULL) {
3524 strcpy(menuName, "menu");
3525 strcat(menuName, mb->name);
3527 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3530 shortName[0] = _(mb->name)[0];
3531 shortName[1] = NULLCHAR;
3532 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3535 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3538 XtSetArg(args[j], XtNborderWidth, 0); j++;
3539 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3541 CreateMenuBarPopup(menuBar, menuName, mb);
3547 Widget CreateButtonBar(mi)
3551 Widget button, buttonBar;
3555 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3557 XtSetArg(args[j], XtNhSpace, 0); j++;
3559 XtSetArg(args[j], XtNborderWidth, 0); j++;
3560 XtSetArg(args[j], XtNvSpace, 0); j++;
3561 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3562 formWidget, args, j);
3564 while (mi->string != NULL) {
3567 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3568 XtSetArg(args[j], XtNborderWidth, 0); j++;
3570 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3571 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3572 buttonBar, args, j);
3573 XtAddCallback(button, XtNcallback,
3574 (XtCallbackProc) MenuBarSelect,
3575 (caddr_t) mi->proc);
3582 CreatePieceMenu(name, color)
3589 ChessSquare selection;
3591 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3592 boardWidget, args, 0);
3594 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3595 String item = pieceMenuStrings[color][i];
3597 if (strcmp(item, "----") == 0) {
3598 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3601 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3602 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3604 selection = pieceMenuTranslation[color][i];
3605 XtAddCallback(entry, XtNcallback,
3606 (XtCallbackProc) PieceMenuSelect,
3607 (caddr_t) selection);
3608 if (selection == WhitePawn || selection == BlackPawn) {
3609 XtSetArg(args[0], XtNpopupOnEntry, entry);
3610 XtSetValues(menu, args, 1);
3623 ChessSquare selection;
3625 whitePieceMenu = CreatePieceMenu("menuW", 0);
3626 blackPieceMenu = CreatePieceMenu("menuB", 1);
3628 XtRegisterGrabAction(PieceMenuPopup, True,
3629 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3630 GrabModeAsync, GrabModeAsync);
3632 XtSetArg(args[0], XtNlabel, _("Drop"));
3633 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3634 boardWidget, args, 1);
3635 for (i = 0; i < DROP_MENU_SIZE; i++) {
3636 String item = dropMenuStrings[i];
3638 if (strcmp(item, "----") == 0) {
3639 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3642 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3643 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3645 selection = dropMenuTranslation[i];
3646 XtAddCallback(entry, XtNcallback,
3647 (XtCallbackProc) DropMenuSelect,
3648 (caddr_t) selection);
3653 void SetupDropMenu()
3661 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3662 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3663 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3664 dmEnables[i].piece);
3665 XtSetSensitive(entry, p != NULL || !appData.testLegality
3666 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3667 && !appData.icsActive));
3669 while (p && *p++ == dmEnables[i].piece) count++;
3670 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3672 XtSetArg(args[j], XtNlabel, label); j++;
3673 XtSetValues(entry, args, j);
3677 void PieceMenuPopup(w, event, params, num_params)
3681 Cardinal *num_params;
3685 if (event->type == ButtonRelease) UnLoadPV(); // [HGM] pv
3686 if (event->type != ButtonPress) return;
3687 if (errorUp) ErrorPopDown();
3691 whichMenu = params[0];
3694 if(!appData.icsEngineAnalyze) return;
3695 case IcsPlayingWhite:
3696 case IcsPlayingBlack:
3697 if(!appData.zippyPlay) goto noZip;
3700 case MachinePlaysWhite:
3701 case MachinePlaysBlack:
3702 case TwoMachinesPlay: // [HGM] pv: use for showing PV
3703 if (!appData.dropMenu) {
3704 LoadPV(event->xbutton.x, event->xbutton.y);
3707 if(gameMode == TwoMachinesPlay || gameMode == AnalyzeMode ||
3708 gameMode == AnalyzeFile || gameMode == IcsObserving) return;
3711 if (!appData.dropMenu || appData.testLegality &&
3712 gameInfo.variant != VariantBughouse &&
3713 gameInfo.variant != VariantCrazyhouse) return;
3715 whichMenu = "menuD";
3721 if (((pmFromX = EventToSquare(event->xbutton.x, BOARD_WIDTH)) < 0) ||
3722 ((pmFromY = EventToSquare(event->xbutton.y, BOARD_HEIGHT)) < 0)) {
3723 pmFromX = pmFromY = -1;
3727 pmFromX = BOARD_WIDTH - 1 - pmFromX;
3729 pmFromY = BOARD_HEIGHT - 1 - pmFromY;
3731 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3734 static void PieceMenuSelect(w, piece, junk)
3739 if (pmFromX < 0 || pmFromY < 0) return;
3740 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3743 static void DropMenuSelect(w, piece, junk)
3748 if (pmFromX < 0 || pmFromY < 0) return;
3749 DropMenuEvent(piece, pmFromX, pmFromY);
3752 void WhiteClock(w, event, prms, nprms)
3758 if (gameMode == EditPosition || gameMode == IcsExamining) {
3759 SetWhiteToPlayEvent();
3760 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3765 void BlackClock(w, event, prms, nprms)
3771 if (gameMode == EditPosition || gameMode == IcsExamining) {
3772 SetBlackToPlayEvent();
3773 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3780 * If the user selects on a border boundary, return -1; if off the board,
3781 * return -2. Otherwise map the event coordinate to the square.
3783 int EventToSquare(x, limit)
3791 if ((x % (squareSize + lineGap)) >= squareSize)
3793 x /= (squareSize + lineGap);
3799 static void do_flash_delay(msec)
3805 static void drawHighlight(file, rank, gc)
3811 if (lineGap == 0 || appData.blindfold) return;
3814 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3815 (squareSize + lineGap);
3816 y = lineGap/2 + rank * (squareSize + lineGap);
3818 x = lineGap/2 + file * (squareSize + lineGap);
3819 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3820 (squareSize + lineGap);
3823 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3824 squareSize+lineGap, squareSize+lineGap);
3827 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3828 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3831 SetHighlights(fromX, fromY, toX, toY)
3832 int fromX, fromY, toX, toY;
3834 if (hi1X != fromX || hi1Y != fromY) {
3835 if (hi1X >= 0 && hi1Y >= 0) {
3836 drawHighlight(hi1X, hi1Y, lineGC);
3838 if (fromX >= 0 && fromY >= 0) {
3839 drawHighlight(fromX, fromY, highlineGC);
3842 if (hi2X != toX || hi2Y != toY) {
3843 if (hi2X >= 0 && hi2Y >= 0) {
3844 drawHighlight(hi2X, hi2Y, lineGC);
3846 if (toX >= 0 && toY >= 0) {
3847 drawHighlight(toX, toY, highlineGC);
3859 SetHighlights(-1, -1, -1, -1);
3864 SetPremoveHighlights(fromX, fromY, toX, toY)
3865 int fromX, fromY, toX, toY;
3867 if (pm1X != fromX || pm1Y != fromY) {
3868 if (pm1X >= 0 && pm1Y >= 0) {
3869 drawHighlight(pm1X, pm1Y, lineGC);
3871 if (fromX >= 0 && fromY >= 0) {
3872 drawHighlight(fromX, fromY, prelineGC);
3875 if (pm2X != toX || pm2Y != toY) {
3876 if (pm2X >= 0 && pm2Y >= 0) {
3877 drawHighlight(pm2X, pm2Y, lineGC);
3879 if (toX >= 0 && toY >= 0) {
3880 drawHighlight(toX, toY, prelineGC);
3890 ClearPremoveHighlights()
3892 SetPremoveHighlights(-1, -1, -1, -1);
3895 static void BlankSquare(x, y, color, piece, dest)
3900 if (useImages && useImageSqs) {
3904 pm = xpmLightSquare;
3909 case 2: /* neutral */
3914 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
3915 squareSize, squareSize, x, y);
3925 case 2: /* neutral */
3930 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
3935 I split out the routines to draw a piece so that I could
3936 make a generic flash routine.
3938 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
3940 int square_color, x, y;
3943 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3944 switch (square_color) {
3946 case 2: /* neutral */
3948 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3949 ? *pieceToOutline(piece)
3950 : *pieceToSolid(piece),
3951 dest, bwPieceGC, 0, 0,
3952 squareSize, squareSize, x, y);
3955 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3956 ? *pieceToSolid(piece)
3957 : *pieceToOutline(piece),
3958 dest, wbPieceGC, 0, 0,
3959 squareSize, squareSize, x, y);
3964 static void monoDrawPiece(piece, square_color, x, y, dest)
3966 int square_color, x, y;
3969 switch (square_color) {
3971 case 2: /* neutral */
3973 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3974 ? *pieceToOutline(piece)
3975 : *pieceToSolid(piece),
3976 dest, bwPieceGC, 0, 0,
3977 squareSize, squareSize, x, y, 1);
3980 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3981 ? *pieceToSolid(piece)
3982 : *pieceToOutline(piece),
3983 dest, wbPieceGC, 0, 0,
3984 squareSize, squareSize, x, y, 1);
3989 static void colorDrawPiece(piece, square_color, x, y, dest)
3991 int square_color, x, y;
3994 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
3995 switch (square_color) {
3997 XCopyPlane(xDisplay, *pieceToSolid(piece),
3998 dest, (int) piece < (int) BlackPawn
3999 ? wlPieceGC : blPieceGC, 0, 0,
4000 squareSize, squareSize, x, y, 1);
4003 XCopyPlane(xDisplay, *pieceToSolid(piece),
4004 dest, (int) piece < (int) BlackPawn
4005 ? wdPieceGC : bdPieceGC, 0, 0,
4006 squareSize, squareSize, x, y, 1);
4008 case 2: /* neutral */
4010 XCopyPlane(xDisplay, *pieceToSolid(piece),
4011 dest, (int) piece < (int) BlackPawn
4012 ? wjPieceGC : bjPieceGC, 0, 0,
4013 squareSize, squareSize, x, y, 1);
4018 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4020 int square_color, x, y;
4025 switch (square_color) {
4027 case 2: /* neutral */
4029 if ((int)piece < (int) BlackPawn) {
4037 if ((int)piece < (int) BlackPawn) {
4045 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4046 dest, wlPieceGC, 0, 0,
4047 squareSize, squareSize, x, y);
4050 typedef void (*DrawFunc)();
4052 DrawFunc ChooseDrawFunc()
4054 if (appData.monoMode) {
4055 if (DefaultDepth(xDisplay, xScreen) == 1) {
4056 return monoDrawPiece_1bit;
4058 return monoDrawPiece;
4062 return colorDrawPieceImage;
4064 return colorDrawPiece;
4068 /* [HR] determine square color depending on chess variant. */
4069 static int SquareColor(row, column)
4074 if (gameInfo.variant == VariantXiangqi) {
4075 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4077 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4079 } else if (row <= 4) {
4085 square_color = ((column + row) % 2) == 1;
4088 /* [hgm] holdings: next line makes all holdings squares light */
4089 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4091 return square_color;
4094 void DrawSquare(row, column, piece, do_flash)
4095 int row, column, do_flash;
4098 int square_color, x, y, direction, font_ascent, font_descent;
4101 XCharStruct overall;
4105 /* Calculate delay in milliseconds (2-delays per complete flash) */
4106 flash_delay = 500 / appData.flashRate;
4109 x = lineGap + ((BOARD_WIDTH-1)-column) *
4110 (squareSize + lineGap);
4111 y = lineGap + row * (squareSize + lineGap);
4113 x = lineGap + column * (squareSize + lineGap);
4114 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4115 (squareSize + lineGap);
4118 square_color = SquareColor(row, column);
4120 if ( // [HGM] holdings: blank out area between board and holdings
4121 column == BOARD_LEFT-1 || column == BOARD_RGHT
4122 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4123 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4124 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4126 // [HGM] print piece counts next to holdings
4127 string[1] = NULLCHAR;
4128 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4129 string[0] = '0' + piece;
4130 XTextExtents(countFontStruct, string, 1, &direction,
4131 &font_ascent, &font_descent, &overall);
4132 if (appData.monoMode) {
4133 XDrawImageString(xDisplay, xBoardWindow, countGC,
4134 x + squareSize - overall.width - 2,
4135 y + font_ascent + 1, string, 1);
4137 XDrawString(xDisplay, xBoardWindow, countGC,
4138 x + squareSize - overall.width - 2,
4139 y + font_ascent + 1, string, 1);
4142 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4143 string[0] = '0' + piece;
4144 XTextExtents(countFontStruct, string, 1, &direction,
4145 &font_ascent, &font_descent, &overall);
4146 if (appData.monoMode) {
4147 XDrawImageString(xDisplay, xBoardWindow, countGC,
4148 x + 2, y + font_ascent + 1, string, 1);
4150 XDrawString(xDisplay, xBoardWindow, countGC,
4151 x + 2, y + font_ascent + 1, string, 1);
4155 if (piece == EmptySquare || appData.blindfold) {
4156 BlankSquare(x, y, square_color, piece, xBoardWindow);
4158 drawfunc = ChooseDrawFunc();
4159 if (do_flash && appData.flashCount > 0) {
4160 for (i=0; i<appData.flashCount; ++i) {
4162 drawfunc(piece, square_color, x, y, xBoardWindow);
4163 XSync(xDisplay, False);
4164 do_flash_delay(flash_delay);
4166 BlankSquare(x, y, square_color, piece, xBoardWindow);
4167 XSync(xDisplay, False);
4168 do_flash_delay(flash_delay);
4171 drawfunc(piece, square_color, x, y, xBoardWindow);
4175 string[1] = NULLCHAR;
4176 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4177 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4178 string[0] = 'a' + column - BOARD_LEFT;
4179 XTextExtents(coordFontStruct, string, 1, &direction,
4180 &font_ascent, &font_descent, &overall);
4181 if (appData.monoMode) {
4182 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4183 x + squareSize - overall.width - 2,
4184 y + squareSize - font_descent - 1, string, 1);
4186 XDrawString(xDisplay, xBoardWindow, coordGC,
4187 x + squareSize - overall.width - 2,
4188 y + squareSize - font_descent - 1, string, 1);
4191 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4192 string[0] = ONE + row;
4193 XTextExtents(coordFontStruct, string, 1, &direction,
4194 &font_ascent, &font_descent, &overall);
4195 if (appData.monoMode) {
4196 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4197 x + 2, y + font_ascent + 1, string, 1);
4199 XDrawString(xDisplay, xBoardWindow, coordGC,
4200 x + 2, y + font_ascent + 1, string, 1);
4203 if(marker[row][column]) {
4204 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4205 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4210 /* Why is this needed on some versions of X? */
4211 void EventProc(widget, unused, event)
4216 if (!XtIsRealized(widget))
4219 switch (event->type) {
4221 if (event->xexpose.count > 0) return; /* no clipping is done */
4222 XDrawPosition(widget, True, NULL);
4230 void DrawPosition(fullRedraw, board)
4231 /*Boolean*/int fullRedraw;
4234 XDrawPosition(boardWidget, fullRedraw, board);
4237 /* Returns 1 if there are "too many" differences between b1 and b2
4238 (i.e. more than 1 move was made) */
4239 static int too_many_diffs(b1, b2)
4245 for (i=0; i<BOARD_HEIGHT; ++i) {
4246 for (j=0; j<BOARD_WIDTH; ++j) {
4247 if (b1[i][j] != b2[i][j]) {
4248 if (++c > 4) /* Castling causes 4 diffs */