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. */
58 #include <sys/types.h>
63 # if HAVE_SYS_SOCKET_H
64 # include <sys/socket.h>
65 # include <netinet/in.h>
67 # else /* not HAVE_SYS_SOCKET_H */
68 # if HAVE_LAN_SOCKET_H
69 # include <lan/socket.h>
71 # include <lan/netdb.h>
72 # else /* not HAVE_LAN_SOCKET_H */
73 # define OMIT_SOCKETS 1
74 # endif /* not HAVE_LAN_SOCKET_H */
75 # endif /* not HAVE_SYS_SOCKET_H */
76 #endif /* !OMIT_SOCKETS */
81 #else /* not STDC_HEADERS */
82 extern char *getenv();
85 # else /* not HAVE_STRING_H */
87 # endif /* not HAVE_STRING_H */
88 #endif /* not STDC_HEADERS */
91 # include <sys/fcntl.h>
92 #else /* not HAVE_SYS_FCNTL_H */
95 # endif /* HAVE_FCNTL_H */
96 #endif /* not HAVE_SYS_FCNTL_H */
98 #if HAVE_SYS_SYSTEMINFO_H
99 # include <sys/systeminfo.h>
100 #endif /* HAVE_SYS_SYSTEMINFO_H */
102 #if TIME_WITH_SYS_TIME
103 # include <sys/time.h>
107 # include <sys/time.h>
118 # include <sys/wait.h>
123 # define NAMLEN(dirent) strlen((dirent)->d_name)
124 # define HAVE_DIR_STRUCT
126 # define dirent direct
127 # define NAMLEN(dirent) (dirent)->d_namlen
129 # include <sys/ndir.h>
130 # define HAVE_DIR_STRUCT
133 # include <sys/dir.h>
134 # define HAVE_DIR_STRUCT
138 # define HAVE_DIR_STRUCT
142 #include <X11/Intrinsic.h>
143 #include <X11/StringDefs.h>
144 #include <X11/Shell.h>
145 #include <X11/cursorfont.h>
146 #include <X11/Xatom.h>
147 #include <X11/Xmu/Atoms.h>
149 #include <X11/Xaw3d/Dialog.h>
150 #include <X11/Xaw3d/Form.h>
151 #include <X11/Xaw3d/List.h>
152 #include <X11/Xaw3d/Label.h>
153 #include <X11/Xaw3d/SimpleMenu.h>
154 #include <X11/Xaw3d/SmeBSB.h>
155 #include <X11/Xaw3d/SmeLine.h>
156 #include <X11/Xaw3d/Box.h>
157 #include <X11/Xaw3d/MenuButton.h>
158 #include <X11/Xaw3d/Text.h>
159 #include <X11/Xaw3d/AsciiText.h>
161 #include <X11/Xaw/Dialog.h>
162 #include <X11/Xaw/Form.h>
163 #include <X11/Xaw/List.h>
164 #include <X11/Xaw/Label.h>
165 #include <X11/Xaw/SimpleMenu.h>
166 #include <X11/Xaw/SmeBSB.h>
167 #include <X11/Xaw/SmeLine.h>
168 #include <X11/Xaw/Box.h>
169 #include <X11/Xaw/MenuButton.h>
170 #include <X11/Xaw/Text.h>
171 #include <X11/Xaw/AsciiText.h>
174 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
179 #include "pixmaps/pixmaps.h"
180 #define IMAGE_EXT "xpm"
182 #define IMAGE_EXT "xim"
183 #include "bitmaps/bitmaps.h"
186 #include "bitmaps/icon_white.bm"
187 #include "bitmaps/icon_black.bm"
188 #include "bitmaps/checkmark.bm"
190 #include "frontend.h"
195 #include "xgamelist.h"
196 #include "xhistory.h"
197 #include "xedittags.h"
200 // must be moved to xengineoutput.h
202 void EngineOutputProc P((Widget w, XEvent *event,
203 String *prms, Cardinal *nprms));
204 void EvalGraphProc P((Widget w, XEvent *event,
205 String *prms, Cardinal *nprms));
212 #define usleep(t) _sleep2(((t)+500)/1000)
216 # define _(s) gettext (s)
217 # define N_(s) gettext_noop (s)
233 int main P((int argc, char **argv));
234 RETSIGTYPE CmailSigHandler P((int sig));
235 RETSIGTYPE IntSigHandler P((int sig));
236 RETSIGTYPE TermSizeSigHandler P((int sig));
237 void CreateGCs P((void));
238 void CreateXIMPieces P((void));
239 void CreateXPMPieces P((void));
240 void CreatePieces P((void));
241 void CreatePieceMenus P((void));
242 Widget CreateMenuBar P((Menu *mb));
243 Widget CreateButtonBar P ((MenuItem *mi));
244 char *FindFont P((char *pattern, int targetPxlSize));
245 void PieceMenuPopup P((Widget w, XEvent *event,
246 String *params, Cardinal *num_params));
247 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
248 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
249 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
250 u_int wreq, u_int hreq));
251 void CreateGrid P((void));
252 int EventToSquare P((int x, int limit));
253 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
254 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
255 void HandleUserMove P((Widget w, XEvent *event,
256 String *prms, Cardinal *nprms));
257 void AnimateUserMove P((Widget w, XEvent * event,
258 String * params, Cardinal * nParams));
259 void WhiteClock P((Widget w, XEvent *event,
260 String *prms, Cardinal *nprms));
261 void BlackClock P((Widget w, XEvent *event,
262 String *prms, Cardinal *nprms));
263 void DrawPositionProc P((Widget w, XEvent *event,
264 String *prms, Cardinal *nprms));
265 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
267 void CommentPopUp P((char *title, char *label));
268 void CommentPopDown P((void));
269 void CommentCallback P((Widget w, XtPointer client_data,
270 XtPointer call_data));
271 void ICSInputBoxPopUp P((void));
272 void ICSInputBoxPopDown P((void));
273 void FileNamePopUp P((char *label, char *def,
274 FileProc proc, char *openMode));
275 void FileNamePopDown P((void));
276 void FileNameCallback P((Widget w, XtPointer client_data,
277 XtPointer call_data));
278 void FileNameAction P((Widget w, XEvent *event,
279 String *prms, Cardinal *nprms));
280 void AskQuestionReplyAction P((Widget w, XEvent *event,
281 String *prms, Cardinal *nprms));
282 void AskQuestionProc P((Widget w, XEvent *event,
283 String *prms, Cardinal *nprms));
284 void AskQuestionPopDown P((void));
285 void PromotionPopDown P((void));
286 void PromotionCallback P((Widget w, XtPointer client_data,
287 XtPointer call_data));
288 void EditCommentPopDown P((void));
289 void EditCommentCallback P((Widget w, XtPointer client_data,
290 XtPointer call_data));
291 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
292 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
293 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
294 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
296 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
298 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
300 void LoadPositionProc P((Widget w, XEvent *event,
301 String *prms, Cardinal *nprms));
302 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
304 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
306 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
308 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
310 void PastePositionProc P((Widget w, XEvent *event, String *prms,
312 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
313 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
314 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
315 void SavePositionProc P((Widget w, XEvent *event,
316 String *prms, Cardinal *nprms));
317 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
318 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
320 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
321 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
322 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
324 void MachineWhiteProc P((Widget w, XEvent *event,
325 String *prms, Cardinal *nprms));
326 void AnalyzeModeProc P((Widget w, XEvent *event,
327 String *prms, Cardinal *nprms));
328 void AnalyzeFileProc P((Widget w, XEvent *event,
329 String *prms, Cardinal *nprms));
330 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
332 void IcsClientProc P((Widget w, XEvent *event, String *prms,
334 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
335 void EditPositionProc P((Widget w, XEvent *event,
336 String *prms, Cardinal *nprms));
337 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
338 void EditCommentProc P((Widget w, XEvent *event,
339 String *prms, Cardinal *nprms));
340 void IcsInputBoxProc P((Widget w, XEvent *event,
341 String *prms, Cardinal *nprms));
342 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
343 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
344 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
345 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
346 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
347 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
348 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
349 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
350 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
351 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
352 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
353 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
354 void StopObservingProc P((Widget w, XEvent *event, String *prms,
356 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
358 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
365 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
367 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
370 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
372 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
374 void AutocommProc P((Widget w, XEvent *event, String *prms,
376 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
377 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void AutobsProc P((Widget w, XEvent *event, String *prms,
380 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
385 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
386 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
388 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
390 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
392 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
393 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
394 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
396 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
398 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
400 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
402 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
404 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
405 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
406 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
408 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
410 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
412 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
414 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
415 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
416 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
417 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
418 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
419 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
420 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
421 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
422 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
423 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
424 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
425 void DisplayMove P((int moveNumber));
426 void DisplayTitle P((char *title));
427 void ICSInitScript P((void));
428 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
429 void ErrorPopUp P((char *title, char *text, int modal));
430 void ErrorPopDown P((void));
431 static char *ExpandPathName P((char *path));
432 static void CreateAnimVars P((void));
433 static void DragPieceMove P((int x, int y));
434 static void DrawDragPiece P((void));
435 char *ModeToWidgetName P((GameMode mode));
436 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
442 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
443 void ShufflePopDown P(());
444 void EnginePopDown P(());
445 void UciPopDown P(());
446 void TimeControlPopDown P(());
447 void NewVariantPopDown P(());
448 void SettingsPopDown P(());
449 void update_ics_width P(());
450 int get_term_width P(());
452 * XBoard depends on Xt R4 or higher
454 int xtVersion = XtSpecificationRelease;
459 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
460 jailSquareColor, highlightSquareColor, premoveHighlightColor;
461 Pixel lowTimeWarningColor;
462 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
463 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
464 wjPieceGC, bjPieceGC, prelineGC, countGC;
465 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
466 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
467 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
468 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
469 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
470 ICSInputShell, fileNameShell, askQuestionShell;
471 Widget historyShell, evalGraphShell, gameListShell;
472 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
473 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
474 Font clockFontID, coordFontID, countFontID;
475 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
476 XtAppContext appContext;
478 char *oldICSInteractionTitle;
482 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
484 Position commentX = -1, commentY = -1;
485 Dimension commentW, commentH;
486 typedef unsigned int BoardSize;
488 Boolean chessProgram;
490 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
491 int squareSize, smallLayout = 0, tinyLayout = 0,
492 marginW, marginH, // [HGM] for run-time resizing
493 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
494 ICSInputBoxUp = False, askQuestionUp = False,
495 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
496 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
497 Pixel timerForegroundPixel, timerBackgroundPixel;
498 Pixel buttonForegroundPixel, buttonBackgroundPixel;
499 char *chessDir, *programName, *programVersion,
500 *gameCopyFilename, *gamePasteFilename;
501 Boolean alwaysOnTop = False;
502 Boolean saveSettingsOnExit;
503 char *settingsFileName;
504 char *icsTextMenuString;
506 char *firstChessProgramNames;
507 char *secondChessProgramNames;
509 WindowPlacement wpMain;
510 WindowPlacement wpConsole;
511 WindowPlacement wpComment;
512 WindowPlacement wpMoveHistory;
513 WindowPlacement wpEvalGraph;
514 WindowPlacement wpEngineOutput;
515 WindowPlacement wpGameList;
516 WindowPlacement wpTags;
520 Pixmap pieceBitmap[2][(int)BlackPawn];
521 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
522 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
523 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
524 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
525 int useImages, useImageSqs;
526 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
527 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
528 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
529 XImage *ximLightSquare, *ximDarkSquare;
532 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
533 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
535 #define White(piece) ((int)(piece) < (int)BlackPawn)
537 /* Variables for doing smooth animation. This whole thing
538 would be much easier if the board was double-buffered,
539 but that would require a fairly major rewrite. */
544 GC blitGC, pieceGC, outlineGC;
545 XPoint startSquare, prevFrame, mouseDelta;
549 int startBoardX, startBoardY;
552 /* There can be two pieces being animated at once: a player
553 can begin dragging a piece before the remote opponent has moved. */
555 static AnimState game, player;
557 /* Bitmaps for use as masks when drawing XPM pieces.
558 Need one for each black and white piece. */
559 static Pixmap xpmMask[BlackKing + 1];
561 /* This magic number is the number of intermediate frames used
562 in each half of the animation. For short moves it's reduced
563 by 1. The total number of frames will be factor * 2 + 1. */
566 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
568 MenuItem fileMenu[] = {
569 {N_("New Game"), ResetProc},
570 {N_("New Shuffle Game ..."), ShuffleMenuProc},
571 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
572 {"----", NothingProc},
573 {N_("Load Game"), LoadGameProc},
574 {N_("Load Next Game"), LoadNextGameProc},
575 {N_("Load Previous Game"), LoadPrevGameProc},
576 {N_("Reload Same Game"), ReloadGameProc},
577 {N_("Save Game"), SaveGameProc},
578 {"----", NothingProc},
579 {N_("Copy Game"), CopyGameProc},
580 {N_("Paste Game"), PasteGameProc},
581 {"----", NothingProc},
582 {N_("Load Position"), LoadPositionProc},
583 {N_("Load Next Position"), LoadNextPositionProc},
584 {N_("Load Previous Position"), LoadPrevPositionProc},
585 {N_("Reload Same Position"), ReloadPositionProc},
586 {N_("Save Position"), SavePositionProc},
587 {"----", NothingProc},
588 {N_("Copy Position"), CopyPositionProc},
589 {N_("Paste Position"), PastePositionProc},
590 {"----", NothingProc},
591 {N_("Mail Move"), MailMoveProc},
592 {N_("Reload CMail Message"), ReloadCmailMsgProc},
593 {"----", NothingProc},
594 {N_("Exit"), QuitProc},
598 MenuItem modeMenu[] = {
599 {N_("Machine White"), MachineWhiteProc},
600 {N_("Machine Black"), MachineBlackProc},
601 {N_("Two Machines"), TwoMachinesProc},
602 {N_("Analysis Mode"), AnalyzeModeProc},
603 {N_("Analyze File"), AnalyzeFileProc },
604 {N_("ICS Client"), IcsClientProc},
605 {N_("Edit Game"), EditGameProc},
606 {N_("Edit Position"), EditPositionProc},
607 {N_("Training"), TrainingProc},
608 {"----", NothingProc},
609 {N_("Show Engine Output"), EngineOutputProc},
610 {N_("Show Evaluation Graph"), EvalGraphProc},
611 {N_("Show Game List"), ShowGameListProc},
612 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
613 {"----", NothingProc},
614 {N_("Edit Tags"), EditTagsProc},
615 {N_("Edit Comment"), EditCommentProc},
616 {N_("ICS Input Box"), IcsInputBoxProc},
617 {N_("Pause"), PauseProc},
621 MenuItem actionMenu[] = {
622 {N_("Accept"), AcceptProc},
623 {N_("Decline"), DeclineProc},
624 {N_("Rematch"), RematchProc},
625 {"----", NothingProc},
626 {N_("Call Flag"), CallFlagProc},
627 {N_("Draw"), DrawProc},
628 {N_("Adjourn"), AdjournProc},
629 {N_("Abort"), AbortProc},
630 {N_("Resign"), ResignProc},
631 {"----", NothingProc},
632 {N_("Stop Observing"), StopObservingProc},
633 {N_("Stop Examining"), StopExaminingProc},
634 {"----", NothingProc},
635 {N_("Adjudicate to White"), AdjuWhiteProc},
636 {N_("Adjudicate to Black"), AdjuBlackProc},
637 {N_("Adjudicate Draw"), AdjuDrawProc},
641 MenuItem stepMenu[] = {
642 {N_("Backward"), BackwardProc},
643 {N_("Forward"), ForwardProc},
644 {N_("Back to Start"), ToStartProc},
645 {N_("Forward to End"), ToEndProc},
646 {N_("Revert"), RevertProc},
647 {N_("Truncate Game"), TruncateGameProc},
648 {"----", NothingProc},
649 {N_("Move Now"), MoveNowProc},
650 {N_("Retract Move"), RetractMoveProc},
654 MenuItem optionsMenu[] = {
655 {N_("Flip View"), FlipViewProc},
656 {"----", NothingProc},
657 {N_("Adjudications ..."), EngineMenuProc},
658 {N_("General Settings ..."), UciMenuProc},
659 {N_("Engine #1 Settings ..."), FirstSettingsProc},
660 {N_("Engine #2 Settings ..."), SecondSettingsProc},
661 {N_("Time Control ..."), TimeControlProc},
662 {"----", NothingProc},
663 {N_("Always Queen"), AlwaysQueenProc},
664 {N_("Animate Dragging"), AnimateDraggingProc},
665 {N_("Animate Moving"), AnimateMovingProc},
666 {N_("Auto Comment"), AutocommProc},
667 {N_("Auto Flag"), AutoflagProc},
668 {N_("Auto Flip View"), AutoflipProc},
669 {N_("Auto Observe"), AutobsProc},
670 {N_("Auto Raise Board"), AutoraiseProc},
671 {N_("Auto Save"), AutosaveProc},
672 {N_("Blindfold"), BlindfoldProc},
673 {N_("Flash Moves"), FlashMovesProc},
674 {N_("Get Move List"), GetMoveListProc},
676 {N_("Highlight Dragging"), HighlightDraggingProc},
678 {N_("Highlight Last Move"), HighlightLastMoveProc},
679 {N_("Move Sound"), MoveSoundProc},
680 {N_("ICS Alarm"), IcsAlarmProc},
681 {N_("Old Save Style"), OldSaveStyleProc},
682 {N_("Periodic Updates"), PeriodicUpdatesProc},
683 {N_("Ponder Next Move"), PonderNextMoveProc},
684 {N_("Popup Exit Message"), PopupExitMessageProc},
685 {N_("Popup Move Errors"), PopupMoveErrorsProc},
686 {N_("Premove"), PremoveProc},
687 {N_("Quiet Play"), QuietPlayProc},
688 {N_("Show Coords"), ShowCoordsProc},
689 {N_("Hide Thinking"), HideThinkingProc},
690 {N_("Test Legality"), TestLegalityProc},
691 {"----", NothingProc},
692 {N_("Save Settings Now"), SaveSettingsProc},
693 {N_("Save Settings on Exit"), SaveOnExitProc},
697 MenuItem helpMenu[] = {
698 {N_("Info XBoard"), InfoProc},
699 {N_("Man XBoard"), ManProc},
700 {"----", NothingProc},
701 {N_("Hint"), HintProc},
702 {N_("Book"), BookProc},
703 {"----", NothingProc},
704 {N_("About XBoard"), AboutProc},
709 {N_("File"), fileMenu},
710 {N_("Mode"), modeMenu},
711 {N_("Action"), actionMenu},
712 {N_("Step"), stepMenu},
713 {N_("Options"), optionsMenu},
714 {N_("Help"), helpMenu},
718 #define PAUSE_BUTTON N_("P")
719 MenuItem buttonBar[] = {
722 {PAUSE_BUTTON, PauseProc},
728 #define PIECE_MENU_SIZE 18
729 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
730 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
731 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
732 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
733 N_("Empty square"), N_("Clear board") },
734 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
735 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
736 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
737 N_("Empty square"), N_("Clear board") }
739 /* must be in same order as PieceMenuStrings! */
740 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
741 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
742 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
743 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
744 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
745 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
746 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
747 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
748 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
751 #define DROP_MENU_SIZE 6
752 String dropMenuStrings[DROP_MENU_SIZE] = {
753 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
755 /* must be in same order as PieceMenuStrings! */
756 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
757 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
758 WhiteRook, WhiteQueen
766 DropMenuEnables dmEnables[] = {
784 { XtNborderWidth, 0 },
785 { XtNdefaultDistance, 0 },
789 { XtNborderWidth, 0 },
790 { XtNresizable, (XtArgVal) True },
794 { XtNborderWidth, 0 },
800 { XtNjustify, (XtArgVal) XtJustifyRight },
801 { XtNlabel, (XtArgVal) "..." },
802 { XtNresizable, (XtArgVal) True },
803 { XtNresize, (XtArgVal) False }
806 Arg messageArgs[] = {
807 { XtNjustify, (XtArgVal) XtJustifyLeft },
808 { XtNlabel, (XtArgVal) "..." },
809 { XtNresizable, (XtArgVal) True },
810 { XtNresize, (XtArgVal) False }
814 { XtNborderWidth, 0 },
815 { XtNjustify, (XtArgVal) XtJustifyLeft }
818 XtResource clientResources[] = {
819 { "flashCount", "flashCount", XtRInt, sizeof(int),
820 XtOffset(AppDataPtr, flashCount), XtRImmediate,
821 (XtPointer) FLASH_COUNT },
824 XrmOptionDescRec shellOptions[] = {
825 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
826 { "-flash", "flashCount", XrmoptionNoArg, "3" },
827 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
830 XtActionsRec boardActions[] = {
831 { "DrawPosition", DrawPositionProc },
832 { "HandleUserMove", HandleUserMove },
833 { "AnimateUserMove", AnimateUserMove },
834 { "FileNameAction", FileNameAction },
835 { "AskQuestionProc", AskQuestionProc },
836 { "AskQuestionReplyAction", AskQuestionReplyAction },
837 { "PieceMenuPopup", PieceMenuPopup },
838 { "WhiteClock", WhiteClock },
839 { "BlackClock", BlackClock },
840 { "Iconify", Iconify },
841 { "ResetProc", ResetProc },
842 { "LoadGameProc", LoadGameProc },
843 { "LoadNextGameProc", LoadNextGameProc },
844 { "LoadPrevGameProc", LoadPrevGameProc },
845 { "LoadSelectedProc", LoadSelectedProc },
846 { "ReloadGameProc", ReloadGameProc },
847 { "LoadPositionProc", LoadPositionProc },
848 { "LoadNextPositionProc", LoadNextPositionProc },
849 { "LoadPrevPositionProc", LoadPrevPositionProc },
850 { "ReloadPositionProc", ReloadPositionProc },
851 { "CopyPositionProc", CopyPositionProc },
852 { "PastePositionProc", PastePositionProc },
853 { "CopyGameProc", CopyGameProc },
854 { "PasteGameProc", PasteGameProc },
855 { "SaveGameProc", SaveGameProc },
856 { "SavePositionProc", SavePositionProc },
857 { "MailMoveProc", MailMoveProc },
858 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
859 { "QuitProc", QuitProc },
860 { "MachineWhiteProc", MachineWhiteProc },
861 { "MachineBlackProc", MachineBlackProc },
862 { "AnalysisModeProc", AnalyzeModeProc },
863 { "AnalyzeFileProc", AnalyzeFileProc },
864 { "TwoMachinesProc", TwoMachinesProc },
865 { "IcsClientProc", IcsClientProc },
866 { "EditGameProc", EditGameProc },
867 { "EditPositionProc", EditPositionProc },
868 { "TrainingProc", EditPositionProc },
869 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
870 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
871 { "ShowGameListProc", ShowGameListProc },
872 { "ShowMoveListProc", HistoryShowProc},
873 { "EditTagsProc", EditCommentProc },
874 { "EditCommentProc", EditCommentProc },
875 { "IcsAlarmProc", IcsAlarmProc },
876 { "IcsInputBoxProc", IcsInputBoxProc },
877 { "PauseProc", PauseProc },
878 { "AcceptProc", AcceptProc },
879 { "DeclineProc", DeclineProc },
880 { "RematchProc", RematchProc },
881 { "CallFlagProc", CallFlagProc },
882 { "DrawProc", DrawProc },
883 { "AdjournProc", AdjournProc },
884 { "AbortProc", AbortProc },
885 { "ResignProc", ResignProc },
886 { "AdjuWhiteProc", AdjuWhiteProc },
887 { "AdjuBlackProc", AdjuBlackProc },
888 { "AdjuDrawProc", AdjuDrawProc },
889 { "EnterKeyProc", EnterKeyProc },
890 { "StopObservingProc", StopObservingProc },
891 { "StopExaminingProc", StopExaminingProc },
892 { "BackwardProc", BackwardProc },
893 { "ForwardProc", ForwardProc },
894 { "ToStartProc", ToStartProc },
895 { "ToEndProc", ToEndProc },
896 { "RevertProc", RevertProc },
897 { "TruncateGameProc", TruncateGameProc },
898 { "MoveNowProc", MoveNowProc },
899 { "RetractMoveProc", RetractMoveProc },
900 { "AlwaysQueenProc", AlwaysQueenProc },
901 { "AnimateDraggingProc", AnimateDraggingProc },
902 { "AnimateMovingProc", AnimateMovingProc },
903 { "AutoflagProc", AutoflagProc },
904 { "AutoflipProc", AutoflipProc },
905 { "AutobsProc", AutobsProc },
906 { "AutoraiseProc", AutoraiseProc },
907 { "AutosaveProc", AutosaveProc },
908 { "BlindfoldProc", BlindfoldProc },
909 { "FlashMovesProc", FlashMovesProc },
910 { "FlipViewProc", FlipViewProc },
911 { "GetMoveListProc", GetMoveListProc },
913 { "HighlightDraggingProc", HighlightDraggingProc },
915 { "HighlightLastMoveProc", HighlightLastMoveProc },
916 { "IcsAlarmProc", IcsAlarmProc },
917 { "MoveSoundProc", MoveSoundProc },
918 { "OldSaveStyleProc", OldSaveStyleProc },
919 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
920 { "PonderNextMoveProc", PonderNextMoveProc },
921 { "PopupExitMessageProc", PopupExitMessageProc },
922 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
923 { "PremoveProc", PremoveProc },
924 { "QuietPlayProc", QuietPlayProc },
925 { "ShowCoordsProc", ShowCoordsProc },
926 { "ShowThinkingProc", ShowThinkingProc },
927 { "HideThinkingProc", HideThinkingProc },
928 { "TestLegalityProc", TestLegalityProc },
929 { "SaveSettingsProc", SaveSettingsProc },
930 { "SaveOnExitProc", SaveOnExitProc },
931 { "InfoProc", InfoProc },
932 { "ManProc", ManProc },
933 { "HintProc", HintProc },
934 { "BookProc", BookProc },
935 { "AboutGameProc", AboutGameProc },
936 { "AboutProc", AboutProc },
937 { "DebugProc", DebugProc },
938 { "NothingProc", NothingProc },
939 { "CommentPopDown", (XtActionProc) CommentPopDown },
940 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
941 { "TagsPopDown", (XtActionProc) TagsPopDown },
942 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
943 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
944 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
945 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
946 { "GameListPopDown", (XtActionProc) GameListPopDown },
947 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
948 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
949 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
950 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
951 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
952 { "EnginePopDown", (XtActionProc) EnginePopDown },
953 { "UciPopDown", (XtActionProc) UciPopDown },
954 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
955 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
956 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
959 char globalTranslations[] =
960 ":<Key>R: ResignProc() \n \
961 :<Key>r: ResetProc() \n \
962 :<Key>g: LoadGameProc() \n \
963 :<Key>N: LoadNextGameProc() \n \
964 :<Key>P: LoadPrevGameProc() \n \
965 :<Key>Q: QuitProc() \n \
966 :<Key>F: ToEndProc() \n \
967 :<Key>f: ForwardProc() \n \
968 :<Key>B: ToStartProc() \n \
969 :<Key>b: BackwardProc() \n \
970 :<Key>p: PauseProc() \n \
971 :<Key>d: DrawProc() \n \
972 :<Key>t: CallFlagProc() \n \
973 :<Key>i: Iconify() \n \
974 :<Key>c: Iconify() \n \
975 :<Key>v: FlipViewProc() \n \
976 <KeyDown>Control_L: BackwardProc() \n \
977 <KeyUp>Control_L: ForwardProc() \n \
978 <KeyDown>Control_R: BackwardProc() \n \
979 <KeyUp>Control_R: ForwardProc() \n \
980 Shift<Key>1: AskQuestionProc(\"Direct command\",\
981 \"Send to chess program:\",,1) \n \
982 Shift<Key>2: AskQuestionProc(\"Direct command\",\
983 \"Send to second chess program:\",,2) \n";
985 char boardTranslations[] =
986 "<Btn1Down>: HandleUserMove() \n \
987 <Btn1Up>: HandleUserMove() \n \
988 <Btn1Motion>: AnimateUserMove() \n \
989 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
990 PieceMenuPopup(menuB) \n \
991 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
992 PieceMenuPopup(menuW) \n \
993 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
994 PieceMenuPopup(menuW) \n \
995 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
996 PieceMenuPopup(menuB) \n";
998 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
999 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1001 char ICSInputTranslations[] =
1002 "<Key>Return: EnterKeyProc() \n";
1004 String xboardResources[] = {
1005 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1006 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1007 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1012 /* Max possible square size */
1013 #define MAXSQSIZE 256
1015 static int xpm_avail[MAXSQSIZE];
1017 #ifdef HAVE_DIR_STRUCT
1019 /* Extract piece size from filename */
1021 xpm_getsize(name, len, ext)
1032 if ((p=strchr(name, '.')) == NULL ||
1033 StrCaseCmp(p+1, ext) != 0)
1039 while (*p && isdigit(*p))
1046 /* Setup xpm_avail */
1048 xpm_getavail(dirname, ext)
1056 for (i=0; i<MAXSQSIZE; ++i)
1059 if (appData.debugMode)
1060 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1062 dir = opendir(dirname);
1065 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1066 programName, dirname);
1070 while ((ent=readdir(dir)) != NULL) {
1071 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1072 if (i > 0 && i < MAXSQSIZE)
1082 xpm_print_avail(fp, ext)
1088 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1089 for (i=1; i<MAXSQSIZE; ++i) {
1095 /* Return XPM piecesize closest to size */
1097 xpm_closest_to(dirname, size, ext)
1103 int sm_diff = MAXSQSIZE;
1107 xpm_getavail(dirname, ext);
1109 if (appData.debugMode)
1110 xpm_print_avail(stderr, ext);
1112 for (i=1; i<MAXSQSIZE; ++i) {
1115 diff = (diff<0) ? -diff : diff;
1116 if (diff < sm_diff) {
1124 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1130 #else /* !HAVE_DIR_STRUCT */
1131 /* If we are on a system without a DIR struct, we can't
1132 read the directory, so we can't collect a list of
1133 filenames, etc., so we can't do any size-fitting. */
1135 xpm_closest_to(dirname, size, ext)
1140 fprintf(stderr, _("\
1141 Warning: No DIR structure found on this system --\n\
1142 Unable to autosize for XPM/XIM pieces.\n\
1143 Please report this error to frankm@hiwaay.net.\n\
1144 Include system type & operating system in message.\n"));
1147 #endif /* HAVE_DIR_STRUCT */
1149 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1150 "magenta", "cyan", "white" };
1154 TextColors textColors[(int)NColorClasses];
1156 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1158 parse_color(str, which)
1162 char *p, buf[100], *d;
1165 if (strlen(str) > 99) /* watch bounds on buf */
1170 for (i=0; i<which; ++i) {
1177 /* Could be looking at something like:
1179 .. in which case we want to stop on a comma also */
1180 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1184 return -1; /* Use default for empty field */
1187 if (which == 2 || isdigit(*p))
1190 while (*p && isalpha(*p))
1195 for (i=0; i<8; ++i) {
1196 if (!StrCaseCmp(buf, cnames[i]))
1197 return which? (i+40) : (i+30);
1199 if (!StrCaseCmp(buf, "default")) return -1;
1201 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1206 parse_cpair(cc, str)
1210 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1211 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1216 /* bg and attr are optional */
1217 textColors[(int)cc].bg = parse_color(str, 1);
1218 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1219 textColors[(int)cc].attr = 0;
1225 /* Arrange to catch delete-window events */
1226 Atom wm_delete_window;
1228 CatchDeleteWindow(Widget w, String procname)
1231 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1232 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1233 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1240 XtSetArg(args[0], XtNiconic, False);
1241 XtSetValues(shellWidget, args, 1);
1243 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1246 //---------------------------------------------------------------------------------------------------------
1247 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1250 #define CW_USEDEFAULT (1<<31)
1251 #define ICS_TEXT_MENU_SIZE 90
1252 #define DEBUG_FILE "xboard.debug"
1253 #define SetCurrentDirectory chdir
1254 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1258 // these two must some day move to frontend.h, when they are implemented
1259 Boolean MoveHistoryIsUp();
1260 Boolean GameListIsUp();
1262 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1265 // front-end part of option handling
1267 // [HGM] This platform-dependent table provides the location for storing the color info
1268 extern char *crWhite, * crBlack;
1272 &appData.whitePieceColor,
1273 &appData.blackPieceColor,
1274 &appData.lightSquareColor,
1275 &appData.darkSquareColor,
1276 &appData.highlightSquareColor,
1277 &appData.premoveHighlightColor,
1290 ParseFont(char *name, int number)
1291 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1293 case 0: // CLOCK_FONT
1294 appData.clockFont = strdup(name);
1296 case 1: // MESSAGE_FONT
1297 appData.font = strdup(name);
1299 case 2: // COORD_FONT
1300 appData.coordFont = strdup(name);
1309 { // only 2 fonts currently
1310 appData.clockFont = CLOCK_FONT_NAME;
1311 appData.coordFont = COORD_FONT_NAME;
1312 appData.font = DEFAULT_FONT_NAME;
1317 { // no-op, until we identify the code for this already in XBoard and move it here
1321 ParseColor(int n, char *name)
1322 { // in XBoard, just copy the color-name string
1323 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1327 ParseTextAttribs(ColorClass cc, char *s)
1329 (&appData.colorShout)[cc] = strdup(s);
1333 ParseBoardSize(void *addr, char *name)
1335 appData.boardSize = strdup(name);
1340 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1344 SetCommPortDefaults()
1345 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1348 // [HGM] args: these three cases taken out to stay in front-end
1350 SaveFontArg(FILE *f, ArgDescriptor *ad)
1353 switch((int)ad->argLoc) {
1354 case 0: // CLOCK_FONT
1355 name = appData.clockFont;
1357 case 1: // MESSAGE_FONT
1358 name = appData.font;
1360 case 2: // COORD_FONT
1361 name = appData.coordFont;
1366 // Do not save fonts for now, as the saved font would be board-size specific
1367 // and not suitable for a re-start at another board size
1368 // fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, name);
1373 { // nothing to do, as the sounds are at all times represented by their text-string names already
1377 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1378 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1379 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1383 SaveColor(FILE *f, ArgDescriptor *ad)
1384 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1385 if(colorVariable[(int)ad->argLoc])
1386 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1390 SaveBoardSize(FILE *f, char *name, void *addr)
1391 { // wrapper to shield back-end from BoardSize & sizeInfo
1392 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1396 ParseCommPortSettings(char *s)
1397 { // no such option in XBoard (yet)
1400 extern Widget engineOutputShell;
1401 extern Widget tagsShell, editTagsShell;
1403 GetActualPlacement(Widget wg, WindowPlacement *wp)
1413 XtSetArg(args[i], XtNx, &x); i++;
1414 XtSetArg(args[i], XtNy, &y); i++;
1415 XtSetArg(args[i], XtNwidth, &w); i++;
1416 XtSetArg(args[i], XtNheight, &h); i++;
1417 XtGetValues(wg, args, i);
1426 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1427 // In XBoard this will have to wait until awareness of window parameters is implemented
1428 GetActualPlacement(shellWidget, &wpMain);
1429 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1430 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1431 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1432 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1433 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1434 else GetActualPlacement(editShell, &wpComment);
1435 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1436 else GetActualPlacement(editTagsShell, &wpTags);
1440 PrintCommPortSettings(FILE *f, char *name)
1441 { // This option does not exist in XBoard
1445 MySearchPath(char *installDir, char *name, char *fullname)
1446 { // just append installDir and name. Perhaps ExpandPath should be used here?
1447 name = ExpandPathName(name);
1448 if(name && name[0] == '/') strcpy(fullname, name); else {
1449 sprintf(fullname, "%s%c%s", installDir, '/', name);
1455 MyGetFullPathName(char *name, char *fullname)
1456 { // should use ExpandPath?
1457 name = ExpandPathName(name);
1458 strcpy(fullname, name);
1463 EnsureOnScreen(int *x, int *y, int minX, int minY)
1470 { // [HGM] args: allows testing if main window is realized from back-end
1471 return xBoardWindow != 0;
1475 PopUpStartupDialog()
1476 { // start menu not implemented in XBoard
1479 ConvertToLine(int argc, char **argv)
1481 static char line[128*1024], buf[1024];
1485 for(i=1; i<argc; i++) {
1486 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1487 && argv[i][0] != '{' )
1488 sprintf(buf, "{%s} ", argv[i]);
1489 else sprintf(buf, "%s ", argv[i]);
1492 line[strlen(line)-1] = NULLCHAR;
1496 //--------------------------------------------------------------------------------------------
1499 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1501 #define BoardSize int
1502 void InitDrawingSizes(BoardSize boardSize, int flags)
1503 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1504 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1506 XtGeometryResult gres;
1509 if(!formWidget) return;
1512 * Enable shell resizing.
1514 shellArgs[0].value = (XtArgVal) &w;
1515 shellArgs[1].value = (XtArgVal) &h;
1516 XtGetValues(shellWidget, shellArgs, 2);
1518 shellArgs[4].value = 2*w; shellArgs[2].value = 10;
1519 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1520 XtSetValues(shellWidget, &shellArgs[2], 4);
1522 XtSetArg(args[0], XtNdefaultDistance, &sep);
1523 XtGetValues(formWidget, args, 1);
1525 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1526 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1529 XtSetArg(args[0], XtNwidth, boardWidth);
1530 XtSetArg(args[1], XtNheight, boardHeight);
1531 XtSetValues(boardWidget, args, 2);
1533 timerWidth = (boardWidth - sep) / 2;
1534 XtSetArg(args[0], XtNwidth, timerWidth);
1535 XtSetValues(whiteTimerWidget, args, 1);
1536 XtSetValues(blackTimerWidget, args, 1);
1538 XawFormDoLayout(formWidget, False);
1540 if (appData.titleInWindow) {
1542 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1543 XtSetArg(args[i], XtNheight, &h); i++;
1544 XtGetValues(titleWidget, args, i);
1546 w = boardWidth - 2*bor;
1548 XtSetArg(args[0], XtNwidth, &w);
1549 XtGetValues(menuBarWidget, args, 1);
1550 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1553 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1554 if (gres != XtGeometryYes && appData.debugMode) {
1556 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1557 programName, gres, w, h, wr, hr);
1561 XawFormDoLayout(formWidget, True);
1564 * Inhibit shell resizing.
1566 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW;
1567 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1568 shellArgs[4].value = shellArgs[2].value = w;
1569 shellArgs[5].value = shellArgs[3].value = h;
1570 XtSetValues(shellWidget, &shellArgs[0], 6);
1572 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1575 for(i=0; i<4; i++) {
1577 for(p=0; p<=(int)WhiteKing; p++)
1578 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1579 if(gameInfo.variant == VariantShogi) {
1580 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1581 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1582 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1583 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1584 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1587 if(gameInfo.variant == VariantGothic) {
1588 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1592 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1593 for(p=0; p<=(int)WhiteKing; p++)
1594 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1595 if(gameInfo.variant == VariantShogi) {
1596 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1597 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1598 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1599 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1600 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1603 if(gameInfo.variant == VariantGothic) {
1604 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1610 for(i=0; i<2; i++) {
1612 for(p=0; p<=(int)WhiteKing; p++)
1613 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1614 if(gameInfo.variant == VariantShogi) {
1615 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1616 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1617 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1618 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1619 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1622 if(gameInfo.variant == VariantGothic) {
1623 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1634 void EscapeExpand(char *p, char *q)
1635 { // [HGM] initstring: routine to shape up string arguments
1636 while(*p++ = *q++) if(p[-1] == '\\')
1638 case 'n': p[-1] = '\n'; break;
1639 case 'r': p[-1] = '\r'; break;
1640 case 't': p[-1] = '\t'; break;
1641 case '\\': p[-1] = '\\'; break;
1642 case 0: *p = 0; return;
1643 default: p[-1] = q[-1]; break;
1652 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1653 XSetWindowAttributes window_attributes;
1655 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1656 XrmValue vFrom, vTo;
1657 XtGeometryResult gres;
1660 int forceMono = False;
1662 srandom(time(0)); // [HGM] book: make random truly random
1664 setbuf(stdout, NULL);
1665 setbuf(stderr, NULL);
1668 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1669 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1673 programName = strrchr(argv[0], '/');
1674 if (programName == NULL)
1675 programName = argv[0];
1680 XtSetLanguageProc(NULL, NULL, NULL);
1681 bindtextdomain(PACKAGE, LOCALEDIR);
1682 textdomain(PACKAGE);
1686 XtAppInitialize(&appContext, "XBoard", shellOptions,
1687 XtNumber(shellOptions),
1688 &argc, argv, xboardResources, NULL, 0);
1689 appData.boardSize = "";
1690 InitAppData(ConvertToLine(argc, argv));
1692 if (p == NULL) p = "/tmp";
1693 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1694 gameCopyFilename = (char*) malloc(i);
1695 gamePasteFilename = (char*) malloc(i);
1696 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1697 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1699 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1700 clientResources, XtNumber(clientResources),
1703 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1704 static char buf[MSG_SIZ];
1705 EscapeExpand(buf, appData.initString);
1706 appData.initString = strdup(buf);
1707 EscapeExpand(buf, appData.secondInitString);
1708 appData.secondInitString = strdup(buf);
1709 EscapeExpand(buf, appData.firstComputerString);
1710 appData.firstComputerString = strdup(buf);
1711 EscapeExpand(buf, appData.secondComputerString);
1712 appData.secondComputerString = strdup(buf);
1715 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1718 if (chdir(chessDir) != 0) {
1719 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1725 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1726 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1727 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1728 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1731 setbuf(debugFP, NULL);
1734 /* [HGM,HR] make sure board size is acceptable */
1735 if(appData.NrFiles > BOARD_FILES ||
1736 appData.NrRanks > BOARD_RANKS )
1737 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1740 /* This feature does not work; animation needs a rewrite */
1741 appData.highlightDragging = FALSE;
1745 xDisplay = XtDisplay(shellWidget);
1746 xScreen = DefaultScreen(xDisplay);
1747 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1749 gameInfo.variant = StringToVariant(appData.variant);
1750 InitPosition(FALSE);
1753 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1755 if (isdigit(appData.boardSize[0])) {
1756 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1757 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1758 &fontPxlSize, &smallLayout, &tinyLayout);
1760 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1761 programName, appData.boardSize);
1765 /* Find some defaults; use the nearest known size */
1766 SizeDefaults *szd, *nearest;
1767 int distance = 99999;
1768 nearest = szd = sizeDefaults;
1769 while (szd->name != NULL) {
1770 if (abs(szd->squareSize - squareSize) < distance) {
1772 distance = abs(szd->squareSize - squareSize);
1773 if (distance == 0) break;
1777 if (i < 2) lineGap = nearest->lineGap;
1778 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1779 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1780 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1781 if (i < 6) smallLayout = nearest->smallLayout;
1782 if (i < 7) tinyLayout = nearest->tinyLayout;
1785 SizeDefaults *szd = sizeDefaults;
1786 if (*appData.boardSize == NULLCHAR) {
1787 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1788 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1791 if (szd->name == NULL) szd--;
1792 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1794 while (szd->name != NULL &&
1795 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1796 if (szd->name == NULL) {
1797 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1798 programName, appData.boardSize);
1802 squareSize = szd->squareSize;
1803 lineGap = szd->lineGap;
1804 clockFontPxlSize = szd->clockFontPxlSize;
1805 coordFontPxlSize = szd->coordFontPxlSize;
1806 fontPxlSize = szd->fontPxlSize;
1807 smallLayout = szd->smallLayout;
1808 tinyLayout = szd->tinyLayout;
1811 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1812 if (strlen(appData.pixmapDirectory) > 0) {
1813 p = ExpandPathName(appData.pixmapDirectory);
1815 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1816 appData.pixmapDirectory);
1819 if (appData.debugMode) {
1820 fprintf(stderr, _("\
1821 XBoard square size (hint): %d\n\
1822 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1824 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1825 if (appData.debugMode) {
1826 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1830 /* [HR] height treated separately (hacked) */
1831 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1832 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1833 if (appData.showJail == 1) {
1834 /* Jail on top and bottom */
1835 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1836 XtSetArg(boardArgs[2], XtNheight,
1837 boardHeight + 2*(lineGap + squareSize));
1838 } else if (appData.showJail == 2) {
1840 XtSetArg(boardArgs[1], XtNwidth,
1841 boardWidth + 2*(lineGap + squareSize));
1842 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1845 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1846 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1850 * Determine what fonts to use.
1852 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1853 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1854 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1855 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1856 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1857 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1858 appData.font = FindFont(appData.font, fontPxlSize);
1859 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1860 countFontStruct = XQueryFont(xDisplay, countFontID);
1861 // appData.font = FindFont(appData.font, fontPxlSize);
1863 xdb = XtDatabase(xDisplay);
1864 XrmPutStringResource(&xdb, "*font", appData.font);
1867 * Detect if there are not enough colors available and adapt.
1869 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1870 appData.monoMode = True;
1873 if (!appData.monoMode) {
1874 vFrom.addr = (caddr_t) appData.lightSquareColor;
1875 vFrom.size = strlen(appData.lightSquareColor);
1876 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1877 if (vTo.addr == NULL) {
1878 appData.monoMode = True;
1881 lightSquareColor = *(Pixel *) vTo.addr;
1884 if (!appData.monoMode) {
1885 vFrom.addr = (caddr_t) appData.darkSquareColor;
1886 vFrom.size = strlen(appData.darkSquareColor);
1887 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1888 if (vTo.addr == NULL) {
1889 appData.monoMode = True;
1892 darkSquareColor = *(Pixel *) vTo.addr;
1895 if (!appData.monoMode) {
1896 vFrom.addr = (caddr_t) appData.whitePieceColor;
1897 vFrom.size = strlen(appData.whitePieceColor);
1898 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1899 if (vTo.addr == NULL) {
1900 appData.monoMode = True;
1903 whitePieceColor = *(Pixel *) vTo.addr;
1906 if (!appData.monoMode) {
1907 vFrom.addr = (caddr_t) appData.blackPieceColor;
1908 vFrom.size = strlen(appData.blackPieceColor);
1909 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1910 if (vTo.addr == NULL) {
1911 appData.monoMode = True;
1914 blackPieceColor = *(Pixel *) vTo.addr;
1918 if (!appData.monoMode) {
1919 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1920 vFrom.size = strlen(appData.highlightSquareColor);
1921 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1922 if (vTo.addr == NULL) {
1923 appData.monoMode = True;
1926 highlightSquareColor = *(Pixel *) vTo.addr;
1930 if (!appData.monoMode) {
1931 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1932 vFrom.size = strlen(appData.premoveHighlightColor);
1933 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1934 if (vTo.addr == NULL) {
1935 appData.monoMode = True;
1938 premoveHighlightColor = *(Pixel *) vTo.addr;
1943 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1946 if (appData.bitmapDirectory == NULL ||
1947 appData.bitmapDirectory[0] == NULLCHAR)
1948 appData.bitmapDirectory = DEF_BITMAP_DIR;
1951 if (appData.lowTimeWarning && !appData.monoMode) {
1952 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
1953 vFrom.size = strlen(appData.lowTimeWarningColor);
1954 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1955 if (vTo.addr == NULL)
1956 appData.monoMode = True;
1958 lowTimeWarningColor = *(Pixel *) vTo.addr;
1961 if (appData.monoMode && appData.debugMode) {
1962 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1963 (unsigned long) XWhitePixel(xDisplay, xScreen),
1964 (unsigned long) XBlackPixel(xDisplay, xScreen));
1967 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1968 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1969 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1970 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1971 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1972 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1973 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1974 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1975 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1976 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1978 if (appData.colorize) {
1980 _("%s: can't parse color names; disabling colorization\n"),
1983 appData.colorize = FALSE;
1985 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
1986 textColors[ColorNone].attr = 0;
1988 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
1994 layoutName = "tinyLayout";
1995 } else if (smallLayout) {
1996 layoutName = "smallLayout";
1998 layoutName = "normalLayout";
2000 /* Outer layoutWidget is there only to provide a name for use in
2001 resources that depend on the layout style */
2003 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2004 layoutArgs, XtNumber(layoutArgs));
2006 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2007 formArgs, XtNumber(formArgs));
2008 XtSetArg(args[0], XtNdefaultDistance, &sep);
2009 XtGetValues(formWidget, args, 1);
2012 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2013 XtSetArg(args[0], XtNtop, XtChainTop);
2014 XtSetArg(args[1], XtNbottom, XtChainTop);
2015 XtSetArg(args[2], XtNright, XtChainLeft);
2016 XtSetValues(menuBarWidget, args, 3);
2018 widgetList[j++] = whiteTimerWidget =
2019 XtCreateWidget("whiteTime", labelWidgetClass,
2020 formWidget, timerArgs, XtNumber(timerArgs));
2021 XtSetArg(args[0], XtNfont, clockFontStruct);
2022 XtSetArg(args[1], XtNtop, XtChainTop);
2023 XtSetArg(args[2], XtNbottom, XtChainTop);
2024 XtSetValues(whiteTimerWidget, args, 3);
2026 widgetList[j++] = blackTimerWidget =
2027 XtCreateWidget("blackTime", labelWidgetClass,
2028 formWidget, timerArgs, XtNumber(timerArgs));
2029 XtSetArg(args[0], XtNfont, clockFontStruct);
2030 XtSetArg(args[1], XtNtop, XtChainTop);
2031 XtSetArg(args[2], XtNbottom, XtChainTop);
2032 XtSetValues(blackTimerWidget, args, 3);
2034 if (appData.titleInWindow) {
2035 widgetList[j++] = titleWidget =
2036 XtCreateWidget("title", labelWidgetClass, formWidget,
2037 titleArgs, XtNumber(titleArgs));
2038 XtSetArg(args[0], XtNtop, XtChainTop);
2039 XtSetArg(args[1], XtNbottom, XtChainTop);
2040 XtSetValues(titleWidget, args, 2);
2043 if (appData.showButtonBar) {
2044 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2045 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2046 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2047 XtSetArg(args[2], XtNtop, XtChainTop);
2048 XtSetArg(args[3], XtNbottom, XtChainTop);
2049 XtSetValues(buttonBarWidget, args, 4);
2052 widgetList[j++] = messageWidget =
2053 XtCreateWidget("message", labelWidgetClass, formWidget,
2054 messageArgs, XtNumber(messageArgs));
2055 XtSetArg(args[0], XtNtop, XtChainTop);
2056 XtSetArg(args[1], XtNbottom, XtChainTop);
2057 XtSetValues(messageWidget, args, 2);
2059 widgetList[j++] = boardWidget =
2060 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2061 XtNumber(boardArgs));
2063 XtManageChildren(widgetList, j);
2065 timerWidth = (boardWidth - sep) / 2;
2066 XtSetArg(args[0], XtNwidth, timerWidth);
2067 XtSetValues(whiteTimerWidget, args, 1);
2068 XtSetValues(blackTimerWidget, args, 1);
2070 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2071 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2072 XtGetValues(whiteTimerWidget, args, 2);
2074 if (appData.showButtonBar) {
2075 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2076 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2077 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2081 * formWidget uses these constraints but they are stored
2085 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2086 XtSetValues(menuBarWidget, args, i);
2087 if (appData.titleInWindow) {
2090 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2091 XtSetValues(whiteTimerWidget, args, i);
2093 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2094 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2095 XtSetValues(blackTimerWidget, args, i);
2097 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2098 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2099 XtSetValues(titleWidget, args, i);
2101 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2102 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2103 XtSetValues(messageWidget, args, i);
2104 if (appData.showButtonBar) {
2106 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2107 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2108 XtSetValues(buttonBarWidget, args, i);
2112 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2113 XtSetValues(whiteTimerWidget, args, i);
2115 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2116 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2117 XtSetValues(blackTimerWidget, args, i);
2119 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2120 XtSetValues(titleWidget, args, i);
2122 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2123 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2124 XtSetValues(messageWidget, args, i);
2125 if (appData.showButtonBar) {
2127 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2128 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2129 XtSetValues(buttonBarWidget, args, i);
2134 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2135 XtSetValues(whiteTimerWidget, args, i);
2137 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2138 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2139 XtSetValues(blackTimerWidget, args, i);
2141 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2142 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2143 XtSetValues(messageWidget, args, i);
2144 if (appData.showButtonBar) {
2146 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2147 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2148 XtSetValues(buttonBarWidget, args, i);
2152 XtSetArg(args[0], XtNfromVert, messageWidget);
2153 XtSetArg(args[1], XtNtop, XtChainTop);
2154 XtSetArg(args[2], XtNbottom, XtChainBottom);
2155 XtSetArg(args[3], XtNleft, XtChainLeft);
2156 XtSetArg(args[4], XtNright, XtChainRight);
2157 XtSetValues(boardWidget, args, 5);
2159 XtRealizeWidget(shellWidget);
2162 XtSetArg(args[0], XtNx, wpMain.x);
2163 XtSetArg(args[1], XtNy, wpMain.y);
2164 XtSetValues(shellWidget, args, 2);
2168 * Correct the width of the message and title widgets.
2169 * It is not known why some systems need the extra fudge term.
2170 * The value "2" is probably larger than needed.
2172 XawFormDoLayout(formWidget, False);
2174 #define WIDTH_FUDGE 2
2176 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2177 XtSetArg(args[i], XtNheight, &h); i++;
2178 XtGetValues(messageWidget, args, i);
2179 if (appData.showButtonBar) {
2181 XtSetArg(args[i], XtNwidth, &w); i++;
2182 XtGetValues(buttonBarWidget, args, i);
2183 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2185 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2188 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2189 if (gres != XtGeometryYes && appData.debugMode) {
2190 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2191 programName, gres, w, h, wr, hr);
2194 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2195 /* The size used for the child widget in layout lags one resize behind
2196 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
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 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2205 XtSetArg(args[1], XtNright, XtChainRight);
2206 XtSetValues(messageWidget, args, 2);
2208 if (appData.titleInWindow) {
2210 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2211 XtSetArg(args[i], XtNheight, &h); i++;
2212 XtGetValues(titleWidget, args, i);
2214 w = boardWidth - 2*bor;
2216 XtSetArg(args[0], XtNwidth, &w);
2217 XtGetValues(menuBarWidget, args, 1);
2218 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2221 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2222 if (gres != XtGeometryYes && appData.debugMode) {
2224 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2225 programName, gres, w, h, wr, hr);
2228 XawFormDoLayout(formWidget, True);
2230 xBoardWindow = XtWindow(boardWidget);
2232 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2233 // not need to go into InitDrawingSizes().
2237 * Create X checkmark bitmap and initialize option menu checks.
2239 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2240 checkmark_bits, checkmark_width, checkmark_height);
2241 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2242 if (appData.alwaysPromoteToQueen) {
2243 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2246 if (appData.animateDragging) {
2247 XtSetValues(XtNameToWidget(menuBarWidget,
2248 "menuOptions.Animate Dragging"),
2251 if (appData.animate) {
2252 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2255 if (appData.autoComment) {
2256 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2259 if (appData.autoCallFlag) {
2260 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2263 if (appData.autoFlipView) {
2264 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2267 if (appData.autoObserve) {
2268 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2271 if (appData.autoRaiseBoard) {
2272 XtSetValues(XtNameToWidget(menuBarWidget,
2273 "menuOptions.Auto Raise Board"), args, 1);
2275 if (appData.autoSaveGames) {
2276 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2279 if (appData.saveGameFile[0] != NULLCHAR) {
2280 /* Can't turn this off from menu */
2281 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2283 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2287 if (appData.blindfold) {
2288 XtSetValues(XtNameToWidget(menuBarWidget,
2289 "menuOptions.Blindfold"), args, 1);
2291 if (appData.flashCount > 0) {
2292 XtSetValues(XtNameToWidget(menuBarWidget,
2293 "menuOptions.Flash Moves"),
2296 if (appData.getMoveList) {
2297 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2301 if (appData.highlightDragging) {
2302 XtSetValues(XtNameToWidget(menuBarWidget,
2303 "menuOptions.Highlight Dragging"),
2307 if (appData.highlightLastMove) {
2308 XtSetValues(XtNameToWidget(menuBarWidget,
2309 "menuOptions.Highlight Last Move"),
2312 if (appData.icsAlarm) {
2313 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2316 if (appData.ringBellAfterMoves) {
2317 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2320 if (appData.oldSaveStyle) {
2321 XtSetValues(XtNameToWidget(menuBarWidget,
2322 "menuOptions.Old Save Style"), args, 1);
2324 if (appData.periodicUpdates) {
2325 XtSetValues(XtNameToWidget(menuBarWidget,
2326 "menuOptions.Periodic Updates"), args, 1);
2328 if (appData.ponderNextMove) {
2329 XtSetValues(XtNameToWidget(menuBarWidget,
2330 "menuOptions.Ponder Next Move"), args, 1);
2332 if (appData.popupExitMessage) {
2333 XtSetValues(XtNameToWidget(menuBarWidget,
2334 "menuOptions.Popup Exit Message"), args, 1);
2336 if (appData.popupMoveErrors) {
2337 XtSetValues(XtNameToWidget(menuBarWidget,
2338 "menuOptions.Popup Move Errors"), args, 1);
2340 if (appData.premove) {
2341 XtSetValues(XtNameToWidget(menuBarWidget,
2342 "menuOptions.Premove"), args, 1);
2344 if (appData.quietPlay) {
2345 XtSetValues(XtNameToWidget(menuBarWidget,
2346 "menuOptions.Quiet Play"), args, 1);
2348 if (appData.showCoords) {
2349 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2352 if (appData.hideThinkingFromHuman) {
2353 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2356 if (appData.testLegality) {
2357 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2360 if (saveSettingsOnExit) {
2361 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2368 ReadBitmap(&wIconPixmap, "icon_white.bm",
2369 icon_white_bits, icon_white_width, icon_white_height);
2370 ReadBitmap(&bIconPixmap, "icon_black.bm",
2371 icon_black_bits, icon_black_width, icon_black_height);
2372 iconPixmap = wIconPixmap;
2374 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2375 XtSetValues(shellWidget, args, i);
2378 * Create a cursor for the board widget.
2380 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2381 XChangeWindowAttributes(xDisplay, xBoardWindow,
2382 CWCursor, &window_attributes);
2385 * Inhibit shell resizing.
2387 shellArgs[0].value = (XtArgVal) &w;
2388 shellArgs[1].value = (XtArgVal) &h;
2389 XtGetValues(shellWidget, shellArgs, 2);
2390 shellArgs[4].value = shellArgs[2].value = w;
2391 shellArgs[5].value = shellArgs[3].value = h;
2392 XtSetValues(shellWidget, &shellArgs[2], 4);
2393 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2394 marginH = h - boardHeight;
2396 CatchDeleteWindow(shellWidget, "QuitProc");
2401 if (appData.bitmapDirectory[0] != NULLCHAR) {
2408 /* Create regular pieces */
2409 if (!useImages) CreatePieces();
2414 if (appData.animate || appData.animateDragging)
2417 XtAugmentTranslations(formWidget,
2418 XtParseTranslationTable(globalTranslations));
2419 XtAugmentTranslations(boardWidget,
2420 XtParseTranslationTable(boardTranslations));
2421 XtAugmentTranslations(whiteTimerWidget,
2422 XtParseTranslationTable(whiteTranslations));
2423 XtAugmentTranslations(blackTimerWidget,
2424 XtParseTranslationTable(blackTranslations));
2426 /* Why is the following needed on some versions of X instead
2427 * of a translation? */
2428 XtAddEventHandler(boardWidget, ExposureMask, False,
2429 (XtEventHandler) EventProc, NULL);
2432 /* [AS] Restore layout */
2433 if( wpMoveHistory.visible ) {
2437 if( wpEvalGraph.visible )
2442 if( wpEngineOutput.visible ) {
2443 EngineOutputPopUp();
2448 if (errorExitStatus == -1) {
2449 if (appData.icsActive) {
2450 /* We now wait until we see "login:" from the ICS before
2451 sending the logon script (problems with timestamp otherwise) */
2452 /*ICSInitScript();*/
2453 if (appData.icsInputBox) ICSInputBoxPopUp();
2457 signal(SIGWINCH, TermSizeSigHandler);
2459 signal(SIGINT, IntSigHandler);
2460 signal(SIGTERM, IntSigHandler);
2461 if (*appData.cmailGameName != NULLCHAR) {
2462 signal(SIGUSR1, CmailSigHandler);
2465 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2468 XtAppMainLoop(appContext);
2469 if (appData.debugMode) fclose(debugFP); // [DM] debug
2476 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2477 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2479 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2480 unlink(gameCopyFilename);
2481 unlink(gamePasteFilename);
2484 RETSIGTYPE TermSizeSigHandler(int sig)
2497 CmailSigHandler(sig)
2503 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2505 /* Activate call-back function CmailSigHandlerCallBack() */
2506 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2508 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2512 CmailSigHandlerCallBack(isr, closure, message, count, error)
2520 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2522 /**** end signal code ****/
2532 f = fopen(appData.icsLogon, "r");
2538 strcat(buf, appData.icsLogon);
2539 f = fopen(buf, "r");
2543 ProcessICSInitScript(f);
2550 EditCommentPopDown();
2565 if (!menuBarWidget) return;
2566 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2568 DisplayError("menuStep.Revert", 0);
2570 XtSetSensitive(w, !grey);
2575 SetMenuEnables(enab)
2579 if (!menuBarWidget) return;
2580 while (enab->name != NULL) {
2581 w = XtNameToWidget(menuBarWidget, enab->name);
2583 DisplayError(enab->name, 0);
2585 XtSetSensitive(w, enab->value);
2591 Enables icsEnables[] = {
2592 { "menuFile.Mail Move", False },
2593 { "menuFile.Reload CMail Message", False },
2594 { "menuMode.Machine Black", False },
2595 { "menuMode.Machine White", False },
2596 { "menuMode.Analysis Mode", False },
2597 { "menuMode.Analyze File", False },
2598 { "menuMode.Two Machines", False },
2600 { "menuHelp.Hint", False },
2601 { "menuHelp.Book", False },
2602 { "menuStep.Move Now", False },
2603 { "menuOptions.Periodic Updates", False },
2604 { "menuOptions.Hide Thinking", False },
2605 { "menuOptions.Ponder Next Move", False },
2610 Enables ncpEnables[] = {
2611 { "menuFile.Mail Move", False },
2612 { "menuFile.Reload CMail Message", False },
2613 { "menuMode.Machine White", False },
2614 { "menuMode.Machine Black", False },
2615 { "menuMode.Analysis Mode", False },
2616 { "menuMode.Analyze File", False },
2617 { "menuMode.Two Machines", False },
2618 { "menuMode.ICS Client", False },
2619 { "menuMode.ICS Input Box", False },
2620 { "Action", False },
2621 { "menuStep.Revert", False },
2622 { "menuStep.Move Now", False },
2623 { "menuStep.Retract Move", False },
2624 { "menuOptions.Auto Comment", False },
2625 { "menuOptions.Auto Flag", False },
2626 { "menuOptions.Auto Flip View", False },
2627 { "menuOptions.Auto Observe", False },
2628 { "menuOptions.Auto Raise Board", False },
2629 { "menuOptions.Get Move List", False },
2630 { "menuOptions.ICS Alarm", False },
2631 { "menuOptions.Move Sound", False },
2632 { "menuOptions.Quiet Play", False },
2633 { "menuOptions.Hide Thinking", False },
2634 { "menuOptions.Periodic Updates", False },
2635 { "menuOptions.Ponder Next Move", False },
2636 { "menuHelp.Hint", False },
2637 { "menuHelp.Book", False },
2641 Enables gnuEnables[] = {
2642 { "menuMode.ICS Client", False },
2643 { "menuMode.ICS Input Box", False },
2644 { "menuAction.Accept", False },
2645 { "menuAction.Decline", False },
2646 { "menuAction.Rematch", False },
2647 { "menuAction.Adjourn", False },
2648 { "menuAction.Stop Examining", False },
2649 { "menuAction.Stop Observing", False },
2650 { "menuStep.Revert", False },
2651 { "menuOptions.Auto Comment", False },
2652 { "menuOptions.Auto Observe", False },
2653 { "menuOptions.Auto Raise Board", False },
2654 { "menuOptions.Get Move List", False },
2655 { "menuOptions.Premove", False },
2656 { "menuOptions.Quiet Play", False },
2658 /* The next two options rely on SetCmailMode being called *after* */
2659 /* SetGNUMode so that when GNU is being used to give hints these */
2660 /* menu options are still available */
2662 { "menuFile.Mail Move", False },
2663 { "menuFile.Reload CMail Message", False },
2667 Enables cmailEnables[] = {
2669 { "menuAction.Call Flag", False },
2670 { "menuAction.Draw", True },
2671 { "menuAction.Adjourn", False },
2672 { "menuAction.Abort", False },
2673 { "menuAction.Stop Observing", False },
2674 { "menuAction.Stop Examining", False },
2675 { "menuFile.Mail Move", True },
2676 { "menuFile.Reload CMail Message", True },
2680 Enables trainingOnEnables[] = {
2681 { "menuMode.Edit Comment", False },
2682 { "menuMode.Pause", False },
2683 { "menuStep.Forward", False },
2684 { "menuStep.Backward", False },
2685 { "menuStep.Forward to End", False },
2686 { "menuStep.Back to Start", False },
2687 { "menuStep.Move Now", False },
2688 { "menuStep.Truncate Game", False },
2692 Enables trainingOffEnables[] = {
2693 { "menuMode.Edit Comment", True },
2694 { "menuMode.Pause", True },
2695 { "menuStep.Forward", True },
2696 { "menuStep.Backward", True },
2697 { "menuStep.Forward to End", True },
2698 { "menuStep.Back to Start", True },
2699 { "menuStep.Move Now", True },
2700 { "menuStep.Truncate Game", True },
2704 Enables machineThinkingEnables[] = {
2705 { "menuFile.Load Game", False },
2706 { "menuFile.Load Next Game", False },
2707 { "menuFile.Load Previous Game", False },
2708 { "menuFile.Reload Same Game", False },
2709 { "menuFile.Paste Game", False },
2710 { "menuFile.Load Position", False },
2711 { "menuFile.Load Next Position", False },
2712 { "menuFile.Load Previous Position", False },
2713 { "menuFile.Reload Same Position", False },
2714 { "menuFile.Paste Position", False },
2715 { "menuMode.Machine White", False },
2716 { "menuMode.Machine Black", False },
2717 { "menuMode.Two Machines", False },
2718 { "menuStep.Retract Move", False },
2722 Enables userThinkingEnables[] = {
2723 { "menuFile.Load Game", True },
2724 { "menuFile.Load Next Game", True },
2725 { "menuFile.Load Previous Game", True },
2726 { "menuFile.Reload Same Game", True },
2727 { "menuFile.Paste Game", True },
2728 { "menuFile.Load Position", True },
2729 { "menuFile.Load Next Position", True },
2730 { "menuFile.Load Previous Position", True },
2731 { "menuFile.Reload Same Position", True },
2732 { "menuFile.Paste Position", True },
2733 { "menuMode.Machine White", True },
2734 { "menuMode.Machine Black", True },
2735 { "menuMode.Two Machines", True },
2736 { "menuStep.Retract Move", True },
2742 SetMenuEnables(icsEnables);
2745 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2746 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2753 SetMenuEnables(ncpEnables);
2759 SetMenuEnables(gnuEnables);
2765 SetMenuEnables(cmailEnables);
2771 SetMenuEnables(trainingOnEnables);
2772 if (appData.showButtonBar) {
2773 XtSetSensitive(buttonBarWidget, False);
2779 SetTrainingModeOff()
2781 SetMenuEnables(trainingOffEnables);
2782 if (appData.showButtonBar) {
2783 XtSetSensitive(buttonBarWidget, True);
2788 SetUserThinkingEnables()
2790 if (appData.noChessProgram) return;
2791 SetMenuEnables(userThinkingEnables);
2795 SetMachineThinkingEnables()
2797 if (appData.noChessProgram) return;
2798 SetMenuEnables(machineThinkingEnables);
2800 case MachinePlaysBlack:
2801 case MachinePlaysWhite:
2802 case TwoMachinesPlay:
2803 XtSetSensitive(XtNameToWidget(menuBarWidget,
2804 ModeToWidgetName(gameMode)), True);
2811 #define Abs(n) ((n)<0 ? -(n) : (n))
2814 * Find a font that matches "pattern" that is as close as
2815 * possible to the targetPxlSize. Prefer fonts that are k
2816 * pixels smaller to fonts that are k pixels larger. The
2817 * pattern must be in the X Consortium standard format,
2818 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2819 * The return value should be freed with XtFree when no
2822 char *FindFont(pattern, targetPxlSize)
2826 char **fonts, *p, *best, *scalable, *scalableTail;
2827 int i, j, nfonts, minerr, err, pxlSize;
2830 char **missing_list;
2832 char *def_string, *base_fnt_lst, strInt[3];
2834 XFontStruct **fnt_list;
2836 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2837 sprintf(strInt, "%d", targetPxlSize);
2838 p = strstr(pattern, "--");
2839 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2840 strcat(base_fnt_lst, strInt);
2841 strcat(base_fnt_lst, strchr(p + 2, '-'));
2843 if ((fntSet = XCreateFontSet(xDisplay,
2847 &def_string)) == NULL) {
2849 fprintf(stderr, _("Unable to create font set.\n"));
2853 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2855 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2857 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2858 programName, pattern);
2866 for (i=0; i<nfonts; i++) {
2869 if (*p != '-') continue;
2871 if (*p == NULLCHAR) break;
2872 if (*p++ == '-') j++;
2874 if (j < 7) continue;
2877 scalable = fonts[i];
2880 err = pxlSize - targetPxlSize;
2881 if (Abs(err) < Abs(minerr) ||
2882 (minerr > 0 && err < 0 && -err == minerr)) {
2888 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
2889 /* If the error is too big and there is a scalable font,
2890 use the scalable font. */
2891 int headlen = scalableTail - scalable;
2892 p = (char *) XtMalloc(strlen(scalable) + 10);
2893 while (isdigit(*scalableTail)) scalableTail++;
2894 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
2896 p = (char *) XtMalloc(strlen(best) + 1);
2899 if (appData.debugMode) {
2900 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
2901 pattern, targetPxlSize, p);
2904 if (missing_count > 0)
2905 XFreeStringList(missing_list);
2906 XFreeFontSet(xDisplay, fntSet);
2908 XFreeFontNames(fonts);
2915 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
2916 | GCBackground | GCFunction | GCPlaneMask;
2917 XGCValues gc_values;
2920 gc_values.plane_mask = AllPlanes;
2921 gc_values.line_width = lineGap;
2922 gc_values.line_style = LineSolid;
2923 gc_values.function = GXcopy;
2925 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2926 gc_values.background = XBlackPixel(xDisplay, xScreen);
2927 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2929 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2930 gc_values.background = XWhitePixel(xDisplay, xScreen);
2931 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
2932 XSetFont(xDisplay, coordGC, coordFontID);
2934 // [HGM] make font for holdings counts (white on black0
2935 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2936 gc_values.background = XBlackPixel(xDisplay, xScreen);
2937 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
2938 XSetFont(xDisplay, countGC, countFontID);
2940 if (appData.monoMode) {
2941 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2942 gc_values.background = XWhitePixel(xDisplay, xScreen);
2943 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2945 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2946 gc_values.background = XBlackPixel(xDisplay, xScreen);
2947 lightSquareGC = wbPieceGC
2948 = XtGetGC(shellWidget, value_mask, &gc_values);
2950 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2951 gc_values.background = XWhitePixel(xDisplay, xScreen);
2952 darkSquareGC = bwPieceGC
2953 = XtGetGC(shellWidget, value_mask, &gc_values);
2955 if (DefaultDepth(xDisplay, xScreen) == 1) {
2956 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
2957 gc_values.function = GXcopyInverted;
2958 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
2959 gc_values.function = GXcopy;
2960 if (XBlackPixel(xDisplay, xScreen) == 1) {
2961 bwPieceGC = darkSquareGC;
2962 wbPieceGC = copyInvertedGC;
2964 bwPieceGC = copyInvertedGC;
2965 wbPieceGC = lightSquareGC;
2969 gc_values.foreground = highlightSquareColor;
2970 gc_values.background = highlightSquareColor;
2971 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2973 gc_values.foreground = premoveHighlightColor;
2974 gc_values.background = premoveHighlightColor;
2975 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2977 gc_values.foreground = lightSquareColor;
2978 gc_values.background = darkSquareColor;
2979 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2981 gc_values.foreground = darkSquareColor;
2982 gc_values.background = lightSquareColor;
2983 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2985 gc_values.foreground = jailSquareColor;
2986 gc_values.background = jailSquareColor;
2987 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2989 gc_values.foreground = whitePieceColor;
2990 gc_values.background = darkSquareColor;
2991 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
2993 gc_values.foreground = whitePieceColor;
2994 gc_values.background = lightSquareColor;
2995 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
2997 gc_values.foreground = whitePieceColor;
2998 gc_values.background = jailSquareColor;
2999 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3001 gc_values.foreground = blackPieceColor;
3002 gc_values.background = darkSquareColor;
3003 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3005 gc_values.foreground = blackPieceColor;
3006 gc_values.background = lightSquareColor;
3007 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3009 gc_values.foreground = blackPieceColor;
3010 gc_values.background = jailSquareColor;
3011 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3015 void loadXIM(xim, xmask, filename, dest, mask)
3028 fp = fopen(filename, "rb");
3030 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3037 for (y=0; y<h; ++y) {
3038 for (x=0; x<h; ++x) {
3043 XPutPixel(xim, x, y, blackPieceColor);
3045 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3048 XPutPixel(xim, x, y, darkSquareColor);
3050 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3053 XPutPixel(xim, x, y, whitePieceColor);
3055 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3058 XPutPixel(xim, x, y, lightSquareColor);
3060 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3066 /* create Pixmap of piece */
3067 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3069 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3072 /* create Pixmap of clipmask
3073 Note: We assume the white/black pieces have the same
3074 outline, so we make only 6 masks. This is okay
3075 since the XPM clipmask routines do the same. */
3077 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3079 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3082 /* now create the 1-bit version */
3083 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3086 values.foreground = 1;
3087 values.background = 0;
3089 /* Don't use XtGetGC, not read only */
3090 maskGC = XCreateGC(xDisplay, *mask,
3091 GCForeground | GCBackground, &values);
3092 XCopyPlane(xDisplay, temp, *mask, maskGC,
3093 0, 0, squareSize, squareSize, 0, 0, 1);
3094 XFreePixmap(xDisplay, temp);
3099 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3101 void CreateXIMPieces()
3106 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3111 /* The XSynchronize calls were copied from CreatePieces.
3112 Not sure if needed, but can't hurt */
3113 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3116 /* temp needed by loadXIM() */
3117 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3118 0, 0, ss, ss, AllPlanes, XYPixmap);
3120 if (strlen(appData.pixmapDirectory) == 0) {
3124 if (appData.monoMode) {
3125 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3129 fprintf(stderr, _("\nLoading XIMs...\n"));
3131 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3132 fprintf(stderr, "%d", piece+1);
3133 for (kind=0; kind<4; kind++) {
3134 fprintf(stderr, ".");
3135 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3136 ExpandPathName(appData.pixmapDirectory),
3137 piece <= (int) WhiteKing ? "" : "w",
3138 pieceBitmapNames[piece],
3140 ximPieceBitmap[kind][piece] =
3141 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3142 0, 0, ss, ss, AllPlanes, XYPixmap);
3143 if (appData.debugMode)
3144 fprintf(stderr, _("(File:%s:) "), buf);
3145 loadXIM(ximPieceBitmap[kind][piece],
3147 &(xpmPieceBitmap2[kind][piece]),
3148 &(ximMaskPm2[piece]));
3149 if(piece <= (int)WhiteKing)
3150 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3152 fprintf(stderr," ");
3154 /* Load light and dark squares */
3155 /* If the LSQ and DSQ pieces don't exist, we will
3156 draw them with solid squares. */
3157 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3158 if (access(buf, 0) != 0) {
3162 fprintf(stderr, _("light square "));
3164 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3165 0, 0, ss, ss, AllPlanes, XYPixmap);
3166 if (appData.debugMode)
3167 fprintf(stderr, _("(File:%s:) "), buf);
3169 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3170 fprintf(stderr, _("dark square "));
3171 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3172 ExpandPathName(appData.pixmapDirectory), ss);
3173 if (appData.debugMode)
3174 fprintf(stderr, _("(File:%s:) "), buf);
3176 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3177 0, 0, ss, ss, AllPlanes, XYPixmap);
3178 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3179 xpmJailSquare = xpmLightSquare;
3181 fprintf(stderr, _("Done.\n"));
3183 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3187 void CreateXPMPieces()
3191 u_int ss = squareSize;
3193 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3194 XpmColorSymbol symbols[4];
3196 /* The XSynchronize calls were copied from CreatePieces.
3197 Not sure if needed, but can't hurt */
3198 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3200 /* Setup translations so piece colors match square colors */
3201 symbols[0].name = "light_piece";
3202 symbols[0].value = appData.whitePieceColor;
3203 symbols[1].name = "dark_piece";
3204 symbols[1].value = appData.blackPieceColor;
3205 symbols[2].name = "light_square";
3206 symbols[2].value = appData.lightSquareColor;
3207 symbols[3].name = "dark_square";
3208 symbols[3].value = appData.darkSquareColor;
3210 attr.valuemask = XpmColorSymbols;
3211 attr.colorsymbols = symbols;
3212 attr.numsymbols = 4;
3214 if (appData.monoMode) {
3215 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3219 if (strlen(appData.pixmapDirectory) == 0) {
3220 XpmPieces* pieces = builtInXpms;
3223 while (pieces->size != squareSize && pieces->size) pieces++;
3224 if (!pieces->size) {
3225 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3228 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3229 for (kind=0; kind<4; kind++) {
3231 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3232 pieces->xpm[piece][kind],
3233 &(xpmPieceBitmap2[kind][piece]),
3234 NULL, &attr)) != 0) {
3235 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3239 if(piece <= (int) WhiteKing)
3240 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3244 xpmJailSquare = xpmLightSquare;
3248 fprintf(stderr, _("\nLoading XPMs...\n"));
3251 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3252 fprintf(stderr, "%d ", piece+1);
3253 for (kind=0; kind<4; kind++) {
3254 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3255 ExpandPathName(appData.pixmapDirectory),
3256 piece > (int) WhiteKing ? "w" : "",
3257 pieceBitmapNames[piece],
3259 if (appData.debugMode) {
3260 fprintf(stderr, _("(File:%s:) "), buf);
3262 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3263 &(xpmPieceBitmap2[kind][piece]),
3264 NULL, &attr)) != 0) {
3265 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3266 // [HGM] missing: read of unorthodox piece failed; substitute King.
3267 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3268 ExpandPathName(appData.pixmapDirectory),
3270 if (appData.debugMode) {
3271 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3273 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3274 &(xpmPieceBitmap2[kind][piece]),
3278 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3283 if(piece <= (int) WhiteKing)
3284 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3287 /* Load light and dark squares */
3288 /* If the LSQ and DSQ pieces don't exist, we will
3289 draw them with solid squares. */
3290 fprintf(stderr, _("light square "));
3291 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3292 if (access(buf, 0) != 0) {
3296 if (appData.debugMode)
3297 fprintf(stderr, _("(File:%s:) "), buf);
3299 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3300 &xpmLightSquare, NULL, &attr)) != 0) {
3301 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3304 fprintf(stderr, _("dark square "));
3305 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3306 ExpandPathName(appData.pixmapDirectory), ss);
3307 if (appData.debugMode) {
3308 fprintf(stderr, _("(File:%s:) "), buf);
3310 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3311 &xpmDarkSquare, NULL, &attr)) != 0) {
3312 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3316 xpmJailSquare = xpmLightSquare;
3317 fprintf(stderr, _("Done.\n"));
3319 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3322 #endif /* HAVE_LIBXPM */
3325 /* No built-in bitmaps */
3330 u_int ss = squareSize;
3332 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3335 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3336 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3337 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3338 pieceBitmapNames[piece],
3339 ss, kind == SOLID ? 's' : 'o');
3340 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3341 if(piece <= (int)WhiteKing)
3342 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3346 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3350 /* With built-in bitmaps */
3353 BuiltInBits* bib = builtInBits;
3356 u_int ss = squareSize;
3358 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3361 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3363 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3364 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3365 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3366 pieceBitmapNames[piece],
3367 ss, kind == SOLID ? 's' : 'o');
3368 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3369 bib->bits[kind][piece], ss, ss);
3370 if(piece <= (int)WhiteKing)
3371 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3375 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3380 void ReadBitmap(pm, name, bits, wreq, hreq)
3383 unsigned char bits[];
3389 char msg[MSG_SIZ], fullname[MSG_SIZ];
3391 if (*appData.bitmapDirectory != NULLCHAR) {
3392 strcpy(fullname, appData.bitmapDirectory);
3393 strcat(fullname, "/");
3394 strcat(fullname, name);
3395 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3396 &w, &h, pm, &x_hot, &y_hot);
3397 fprintf(stderr, "load %s\n", name);
3398 if (errcode != BitmapSuccess) {
3400 case BitmapOpenFailed:
3401 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3403 case BitmapFileInvalid:
3404 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3406 case BitmapNoMemory:
3407 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3411 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3415 fprintf(stderr, _("%s: %s...using built-in\n"),
3417 } else if (w != wreq || h != hreq) {
3419 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3420 programName, fullname, w, h, wreq, hreq);
3426 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3435 if (lineGap == 0) return;
3437 /* [HR] Split this into 2 loops for non-square boards. */
3439 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3440 gridSegments[i].x1 = 0;
3441 gridSegments[i].x2 =
3442 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3443 gridSegments[i].y1 = gridSegments[i].y2
3444 = lineGap / 2 + (i * (squareSize + lineGap));
3447 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3448 gridSegments[j + i].y1 = 0;
3449 gridSegments[j + i].y2 =
3450 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3451 gridSegments[j + i].x1 = gridSegments[j + i].x2
3452 = lineGap / 2 + (j * (squareSize + lineGap));
3456 static void MenuBarSelect(w, addr, index)
3461 XtActionProc proc = (XtActionProc) addr;
3463 (proc)(NULL, NULL, NULL, NULL);
3466 void CreateMenuBarPopup(parent, name, mb)
3476 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3479 XtSetArg(args[j], XtNleftMargin, 20); j++;
3480 XtSetArg(args[j], XtNrightMargin, 20); j++;
3482 while (mi->string != NULL) {
3483 if (strcmp(mi->string, "----") == 0) {
3484 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3487 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3488 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3490 XtAddCallback(entry, XtNcallback,
3491 (XtCallbackProc) MenuBarSelect,
3492 (caddr_t) mi->proc);
3498 Widget CreateMenuBar(mb)
3502 Widget anchor, menuBar;
3504 char menuName[MSG_SIZ];
3507 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3508 XtSetArg(args[j], XtNvSpace, 0); j++;
3509 XtSetArg(args[j], XtNborderWidth, 0); j++;
3510 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3511 formWidget, args, j);
3513 while (mb->name != NULL) {
3514 strcpy(menuName, "menu");
3515 strcat(menuName, mb->name);
3517 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3520 shortName[0] = _(mb->name)[0];
3521 shortName[1] = NULLCHAR;
3522 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3525 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3528 XtSetArg(args[j], XtNborderWidth, 0); j++;
3529 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3531 CreateMenuBarPopup(menuBar, menuName, mb);
3537 Widget CreateButtonBar(mi)
3541 Widget button, buttonBar;
3545 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3547 XtSetArg(args[j], XtNhSpace, 0); j++;
3549 XtSetArg(args[j], XtNborderWidth, 0); j++;
3550 XtSetArg(args[j], XtNvSpace, 0); j++;
3551 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3552 formWidget, args, j);
3554 while (mi->string != NULL) {
3557 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3558 XtSetArg(args[j], XtNborderWidth, 0); j++;
3560 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3561 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3562 buttonBar, args, j);
3563 XtAddCallback(button, XtNcallback,
3564 (XtCallbackProc) MenuBarSelect,
3565 (caddr_t) mi->proc);
3572 CreatePieceMenu(name, color)
3579 ChessSquare selection;
3581 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3582 boardWidget, args, 0);
3584 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3585 String item = pieceMenuStrings[color][i];
3587 if (strcmp(item, "----") == 0) {
3588 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3591 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3592 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3594 selection = pieceMenuTranslation[color][i];
3595 XtAddCallback(entry, XtNcallback,
3596 (XtCallbackProc) PieceMenuSelect,
3597 (caddr_t) selection);
3598 if (selection == WhitePawn || selection == BlackPawn) {
3599 XtSetArg(args[0], XtNpopupOnEntry, entry);
3600 XtSetValues(menu, args, 1);
3613 ChessSquare selection;
3615 whitePieceMenu = CreatePieceMenu("menuW", 0);
3616 blackPieceMenu = CreatePieceMenu("menuB", 1);
3618 XtRegisterGrabAction(PieceMenuPopup, True,
3619 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3620 GrabModeAsync, GrabModeAsync);
3622 XtSetArg(args[0], XtNlabel, _("Drop"));
3623 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3624 boardWidget, args, 1);
3625 for (i = 0; i < DROP_MENU_SIZE; i++) {
3626 String item = dropMenuStrings[i];
3628 if (strcmp(item, "----") == 0) {
3629 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3632 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3633 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3635 selection = dropMenuTranslation[i];
3636 XtAddCallback(entry, XtNcallback,
3637 (XtCallbackProc) DropMenuSelect,
3638 (caddr_t) selection);
3643 void SetupDropMenu()
3651 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3652 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3653 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3654 dmEnables[i].piece);
3655 XtSetSensitive(entry, p != NULL || !appData.testLegality
3656 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3657 && !appData.icsActive));
3659 while (p && *p++ == dmEnables[i].piece) count++;
3660 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3662 XtSetArg(args[j], XtNlabel, label); j++;
3663 XtSetValues(entry, args, j);
3667 void PieceMenuPopup(w, event, params, num_params)
3671 Cardinal *num_params;
3674 if (event->type != ButtonPress) return;
3675 if (errorUp) ErrorPopDown();
3679 whichMenu = params[0];
3681 case IcsPlayingWhite:
3682 case IcsPlayingBlack:
3684 case MachinePlaysWhite:
3685 case MachinePlaysBlack:
3686 if (appData.testLegality &&
3687 gameInfo.variant != VariantBughouse &&
3688 gameInfo.variant != VariantCrazyhouse) return;
3690 whichMenu = "menuD";
3696 if (((pmFromX = EventToSquare(event->xbutton.x, BOARD_WIDTH)) < 0) ||
3697 ((pmFromY = EventToSquare(event->xbutton.y, BOARD_HEIGHT)) < 0)) {
3698 pmFromX = pmFromY = -1;
3702 pmFromX = BOARD_WIDTH - 1 - pmFromX;
3704 pmFromY = BOARD_HEIGHT - 1 - pmFromY;
3706 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3709 static void PieceMenuSelect(w, piece, junk)
3714 if (pmFromX < 0 || pmFromY < 0) return;
3715 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3718 static void DropMenuSelect(w, piece, junk)
3723 if (pmFromX < 0 || pmFromY < 0) return;
3724 DropMenuEvent(piece, pmFromX, pmFromY);
3727 void WhiteClock(w, event, prms, nprms)
3733 if (gameMode == EditPosition || gameMode == IcsExamining) {
3734 SetWhiteToPlayEvent();
3735 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3740 void BlackClock(w, event, prms, nprms)
3746 if (gameMode == EditPosition || gameMode == IcsExamining) {
3747 SetBlackToPlayEvent();
3748 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3755 * If the user selects on a border boundary, return -1; if off the board,
3756 * return -2. Otherwise map the event coordinate to the square.
3758 int EventToSquare(x, limit)
3766 if ((x % (squareSize + lineGap)) >= squareSize)
3768 x /= (squareSize + lineGap);
3774 static void do_flash_delay(msec)
3780 static void drawHighlight(file, rank, gc)
3786 if (lineGap == 0 || appData.blindfold) return;
3789 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3790 (squareSize + lineGap);
3791 y = lineGap/2 + rank * (squareSize + lineGap);
3793 x = lineGap/2 + file * (squareSize + lineGap);
3794 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3795 (squareSize + lineGap);
3798 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3799 squareSize+lineGap, squareSize+lineGap);
3802 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3803 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3806 SetHighlights(fromX, fromY, toX, toY)
3807 int fromX, fromY, toX, toY;
3809 if (hi1X != fromX || hi1Y != fromY) {
3810 if (hi1X >= 0 && hi1Y >= 0) {
3811 drawHighlight(hi1X, hi1Y, lineGC);
3813 if (fromX >= 0 && fromY >= 0) {
3814 drawHighlight(fromX, fromY, highlineGC);
3817 if (hi2X != toX || hi2Y != toY) {
3818 if (hi2X >= 0 && hi2Y >= 0) {
3819 drawHighlight(hi2X, hi2Y, lineGC);
3821 if (toX >= 0 && toY >= 0) {
3822 drawHighlight(toX, toY, highlineGC);
3834 SetHighlights(-1, -1, -1, -1);
3839 SetPremoveHighlights(fromX, fromY, toX, toY)
3840 int fromX, fromY, toX, toY;
3842 if (pm1X != fromX || pm1Y != fromY) {
3843 if (pm1X >= 0 && pm1Y >= 0) {
3844 drawHighlight(pm1X, pm1Y, lineGC);
3846 if (fromX >= 0 && fromY >= 0) {
3847 drawHighlight(fromX, fromY, prelineGC);
3850 if (pm2X != toX || pm2Y != toY) {
3851 if (pm2X >= 0 && pm2Y >= 0) {
3852 drawHighlight(pm2X, pm2Y, lineGC);
3854 if (toX >= 0 && toY >= 0) {
3855 drawHighlight(toX, toY, prelineGC);
3865 ClearPremoveHighlights()
3867 SetPremoveHighlights(-1, -1, -1, -1);
3870 static void BlankSquare(x, y, color, piece, dest)
3875 if (useImages && useImageSqs) {
3879 pm = xpmLightSquare;
3884 case 2: /* neutral */
3889 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
3890 squareSize, squareSize, x, y);
3900 case 2: /* neutral */
3905 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
3910 I split out the routines to draw a piece so that I could
3911 make a generic flash routine.
3913 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
3915 int square_color, x, y;
3918 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3919 switch (square_color) {
3921 case 2: /* neutral */
3923 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3924 ? *pieceToOutline(piece)
3925 : *pieceToSolid(piece),
3926 dest, bwPieceGC, 0, 0,
3927 squareSize, squareSize, x, y);
3930 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3931 ? *pieceToSolid(piece)
3932 : *pieceToOutline(piece),
3933 dest, wbPieceGC, 0, 0,
3934 squareSize, squareSize, x, y);
3939 static void monoDrawPiece(piece, square_color, x, y, dest)
3941 int square_color, x, y;
3944 switch (square_color) {
3946 case 2: /* neutral */
3948 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3949 ? *pieceToOutline(piece)
3950 : *pieceToSolid(piece),
3951 dest, bwPieceGC, 0, 0,
3952 squareSize, squareSize, x, y, 1);
3955 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3956 ? *pieceToSolid(piece)
3957 : *pieceToOutline(piece),
3958 dest, wbPieceGC, 0, 0,
3959 squareSize, squareSize, x, y, 1);
3964 static void colorDrawPiece(piece, square_color, x, y, dest)
3966 int square_color, x, y;
3969 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
3970 switch (square_color) {
3972 XCopyPlane(xDisplay, *pieceToSolid(piece),
3973 dest, (int) piece < (int) BlackPawn
3974 ? wlPieceGC : blPieceGC, 0, 0,
3975 squareSize, squareSize, x, y, 1);
3978 XCopyPlane(xDisplay, *pieceToSolid(piece),
3979 dest, (int) piece < (int) BlackPawn
3980 ? wdPieceGC : bdPieceGC, 0, 0,
3981 squareSize, squareSize, x, y, 1);
3983 case 2: /* neutral */
3985 XCopyPlane(xDisplay, *pieceToSolid(piece),
3986 dest, (int) piece < (int) BlackPawn
3987 ? wjPieceGC : bjPieceGC, 0, 0,
3988 squareSize, squareSize, x, y, 1);
3993 static void colorDrawPieceImage(piece, square_color, x, y, dest)
3995 int square_color, x, y;
4000 switch (square_color) {
4002 case 2: /* neutral */
4004 if ((int)piece < (int) BlackPawn) {
4012 if ((int)piece < (int) BlackPawn) {
4020 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4021 dest, wlPieceGC, 0, 0,
4022 squareSize, squareSize, x, y);
4025 typedef void (*DrawFunc)();
4027 DrawFunc ChooseDrawFunc()
4029 if (appData.monoMode) {
4030 if (DefaultDepth(xDisplay, xScreen) == 1) {
4031 return monoDrawPiece_1bit;
4033 return monoDrawPiece;
4037 return colorDrawPieceImage;
4039 return colorDrawPiece;
4043 /* [HR] determine square color depending on chess variant. */
4044 static int SquareColor(row, column)
4049 if (gameInfo.variant == VariantXiangqi) {
4050 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4052 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4054 } else if (row <= 4) {
4060 square_color = ((column + row) % 2) == 1;
4063 /* [hgm] holdings: next line makes all holdings squares light */
4064 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4066 return square_color;
4069 void DrawSquare(row, column, piece, do_flash)
4070 int row, column, do_flash;
4073 int square_color, x, y, direction, font_ascent, font_descent;
4076 XCharStruct overall;
4080 /* Calculate delay in milliseconds (2-delays per complete flash) */
4081 flash_delay = 500 / appData.flashRate;
4084 x = lineGap + ((BOARD_WIDTH-1)-column) *
4085 (squareSize + lineGap);
4086 y = lineGap + row * (squareSize + lineGap);
4088 x = lineGap + column * (squareSize + lineGap);
4089 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4090 (squareSize + lineGap);
4093 square_color = SquareColor(row, column);
4095 if ( // [HGM] holdings: blank out area between board and holdings
4096 column == BOARD_LEFT-1 || column == BOARD_RGHT
4097 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4098 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4099 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4101 // [HGM] print piece counts next to holdings
4102 string[1] = NULLCHAR;
4103 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4104 string[0] = '0' + piece;
4105 XTextExtents(countFontStruct, string, 1, &direction,
4106 &font_ascent, &font_descent, &overall);
4107 if (appData.monoMode) {
4108 XDrawImageString(xDisplay, xBoardWindow, countGC,
4109 x + squareSize - overall.width - 2,
4110 y + font_ascent + 1, string, 1);
4112 XDrawString(xDisplay, xBoardWindow, countGC,
4113 x + squareSize - overall.width - 2,
4114 y + font_ascent + 1, string, 1);
4117 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4118 string[0] = '0' + piece;
4119 XTextExtents(countFontStruct, string, 1, &direction,
4120 &font_ascent, &font_descent, &overall);
4121 if (appData.monoMode) {
4122 XDrawImageString(xDisplay, xBoardWindow, countGC,
4123 x + 2, y + font_ascent + 1, string, 1);
4125 XDrawString(xDisplay, xBoardWindow, countGC,
4126 x + 2, y + font_ascent + 1, string, 1);
4130 if (piece == EmptySquare || appData.blindfold) {
4131 BlankSquare(x, y, square_color, piece, xBoardWindow);
4133 drawfunc = ChooseDrawFunc();
4134 if (do_flash && appData.flashCount > 0) {
4135 for (i=0; i<appData.flashCount; ++i) {
4137 drawfunc(piece, square_color, x, y, xBoardWindow);
4138 XSync(xDisplay, False);
4139 do_flash_delay(flash_delay);
4141 BlankSquare(x, y, square_color, piece, xBoardWindow);
4142 XSync(xDisplay, False);
4143 do_flash_delay(flash_delay);
4146 drawfunc(piece, square_color, x, y, xBoardWindow);
4150 string[1] = NULLCHAR;
4151 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4152 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4153 string[0] = 'a' + column - BOARD_LEFT;
4154 XTextExtents(coordFontStruct, string, 1, &direction,
4155 &font_ascent, &font_descent, &overall);
4156 if (appData.monoMode) {
4157 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4158 x + squareSize - overall.width - 2,
4159 y + squareSize - font_descent - 1, string, 1);
4161 XDrawString(xDisplay, xBoardWindow, coordGC,
4162 x + squareSize - overall.width - 2,
4163 y + squareSize - font_descent - 1, string, 1);
4166 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4167 string[0] = ONE + row;
4168 XTextExtents(coordFontStruct, string, 1, &direction,
4169 &font_ascent, &font_descent, &overall);
4170 if (appData.monoMode) {
4171 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4172 x + 2, y + font_ascent + 1, string, 1);
4174 XDrawString(xDisplay, xBoardWindow, coordGC,
4175 x + 2, y + font_ascent + 1, string, 1);
4181 /* Why is this needed on some versions of X? */
4182 void EventProc(widget, unused, event)
4187 if (!XtIsRealized(widget))
4190 switch (event->type) {
4192 if (event->xexpose.count > 0) return; /* no clipping is done */
4193 XDrawPosition(widget, True, NULL);
4201 void DrawPosition(fullRedraw, board)
4202 /*Boolean*/int fullRedraw;
4205 XDrawPosition(boardWidget, fullRedraw, board);
4208 /* Returns 1 if there are "too many" differences between b1 and b2
4209 (i.e. more than 1 move was made) */
4210 static int too_many_diffs(b1, b2)
4216 for (i=0; i<BOARD_HEIGHT; ++i) {
4217 for (j=0; j<BOARD_WIDTH; ++j) {
4218 if (b1[i][j] != b2[i][j]) {
4219 if (++c > 4) /* Castling causes 4 diffs */
4228 /* Matrix describing castling maneuvers */
4229 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4230 static int castling_matrix[4][5] = {
4231 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4232 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4233 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4234 { 7, 7, 4, 5, 6 } /* 0-0, black */
4237 /* Checks whether castling occurred. If it did, *rrow and *rcol
4238 are set to the destination (row,col) of the rook that moved.
4240 Returns 1 if castling occurred, 0 if not.
4242 Note: Only handles a max of 1 castling move, so be sure
4243 to call too_many_diffs() first.
4245 static int check_castle_draw(newb, oldb, rrow, rcol)