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 programName = strrchr(argv[0], '/');
1669 if (programName == NULL)
1670 programName = argv[0];
1675 XtSetLanguageProc(NULL, NULL, NULL);
1676 bindtextdomain(PACKAGE, LOCALEDIR);
1677 textdomain(PACKAGE);
1681 XtAppInitialize(&appContext, "XBoard", shellOptions,
1682 XtNumber(shellOptions),
1683 &argc, argv, xboardResources, NULL, 0);
1684 appData.boardSize = "";
1685 InitAppData(ConvertToLine(argc, argv));
1687 if (p == NULL) p = "/tmp";
1688 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1689 gameCopyFilename = (char*) malloc(i);
1690 gamePasteFilename = (char*) malloc(i);
1691 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1692 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1694 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1695 clientResources, XtNumber(clientResources),
1698 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1699 static char buf[MSG_SIZ];
1700 EscapeExpand(buf, appData.initString);
1701 appData.initString = strdup(buf);
1702 EscapeExpand(buf, appData.secondInitString);
1703 appData.secondInitString = strdup(buf);
1704 EscapeExpand(buf, appData.firstComputerString);
1705 appData.firstComputerString = strdup(buf);
1706 EscapeExpand(buf, appData.secondComputerString);
1707 appData.secondComputerString = strdup(buf);
1710 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1713 if (chdir(chessDir) != 0) {
1714 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1720 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1721 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1722 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1723 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1726 setbuf(debugFP, NULL);
1729 /* [HGM,HR] make sure board size is acceptable */
1730 if(appData.NrFiles > BOARD_FILES ||
1731 appData.NrRanks > BOARD_RANKS )
1732 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1735 /* This feature does not work; animation needs a rewrite */
1736 appData.highlightDragging = FALSE;
1740 xDisplay = XtDisplay(shellWidget);
1741 xScreen = DefaultScreen(xDisplay);
1742 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1744 gameInfo.variant = StringToVariant(appData.variant);
1745 InitPosition(FALSE);
1748 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1750 if (isdigit(appData.boardSize[0])) {
1751 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1752 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1753 &fontPxlSize, &smallLayout, &tinyLayout);
1755 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1756 programName, appData.boardSize);
1760 /* Find some defaults; use the nearest known size */
1761 SizeDefaults *szd, *nearest;
1762 int distance = 99999;
1763 nearest = szd = sizeDefaults;
1764 while (szd->name != NULL) {
1765 if (abs(szd->squareSize - squareSize) < distance) {
1767 distance = abs(szd->squareSize - squareSize);
1768 if (distance == 0) break;
1772 if (i < 2) lineGap = nearest->lineGap;
1773 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1774 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1775 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1776 if (i < 6) smallLayout = nearest->smallLayout;
1777 if (i < 7) tinyLayout = nearest->tinyLayout;
1780 SizeDefaults *szd = sizeDefaults;
1781 if (*appData.boardSize == NULLCHAR) {
1782 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1783 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1786 if (szd->name == NULL) szd--;
1787 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1789 while (szd->name != NULL &&
1790 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1791 if (szd->name == NULL) {
1792 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1793 programName, appData.boardSize);
1797 squareSize = szd->squareSize;
1798 lineGap = szd->lineGap;
1799 clockFontPxlSize = szd->clockFontPxlSize;
1800 coordFontPxlSize = szd->coordFontPxlSize;
1801 fontPxlSize = szd->fontPxlSize;
1802 smallLayout = szd->smallLayout;
1803 tinyLayout = szd->tinyLayout;
1806 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1807 if (strlen(appData.pixmapDirectory) > 0) {
1808 p = ExpandPathName(appData.pixmapDirectory);
1810 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1811 appData.pixmapDirectory);
1814 if (appData.debugMode) {
1815 fprintf(stderr, _("\
1816 XBoard square size (hint): %d\n\
1817 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1819 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1820 if (appData.debugMode) {
1821 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1825 /* [HR] height treated separately (hacked) */
1826 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1827 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1828 if (appData.showJail == 1) {
1829 /* Jail on top and bottom */
1830 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1831 XtSetArg(boardArgs[2], XtNheight,
1832 boardHeight + 2*(lineGap + squareSize));
1833 } else if (appData.showJail == 2) {
1835 XtSetArg(boardArgs[1], XtNwidth,
1836 boardWidth + 2*(lineGap + squareSize));
1837 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1840 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1841 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1845 * Determine what fonts to use.
1847 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1848 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1849 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1850 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1851 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1852 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1853 appData.font = FindFont(appData.font, fontPxlSize);
1854 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1855 countFontStruct = XQueryFont(xDisplay, countFontID);
1856 // appData.font = FindFont(appData.font, fontPxlSize);
1858 xdb = XtDatabase(xDisplay);
1859 XrmPutStringResource(&xdb, "*font", appData.font);
1862 * Detect if there are not enough colors available and adapt.
1864 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1865 appData.monoMode = True;
1868 if (!appData.monoMode) {
1869 vFrom.addr = (caddr_t) appData.lightSquareColor;
1870 vFrom.size = strlen(appData.lightSquareColor);
1871 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1872 if (vTo.addr == NULL) {
1873 appData.monoMode = True;
1876 lightSquareColor = *(Pixel *) vTo.addr;
1879 if (!appData.monoMode) {
1880 vFrom.addr = (caddr_t) appData.darkSquareColor;
1881 vFrom.size = strlen(appData.darkSquareColor);
1882 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1883 if (vTo.addr == NULL) {
1884 appData.monoMode = True;
1887 darkSquareColor = *(Pixel *) vTo.addr;
1890 if (!appData.monoMode) {
1891 vFrom.addr = (caddr_t) appData.whitePieceColor;
1892 vFrom.size = strlen(appData.whitePieceColor);
1893 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1894 if (vTo.addr == NULL) {
1895 appData.monoMode = True;
1898 whitePieceColor = *(Pixel *) vTo.addr;
1901 if (!appData.monoMode) {
1902 vFrom.addr = (caddr_t) appData.blackPieceColor;
1903 vFrom.size = strlen(appData.blackPieceColor);
1904 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1905 if (vTo.addr == NULL) {
1906 appData.monoMode = True;
1909 blackPieceColor = *(Pixel *) vTo.addr;
1913 if (!appData.monoMode) {
1914 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1915 vFrom.size = strlen(appData.highlightSquareColor);
1916 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1917 if (vTo.addr == NULL) {
1918 appData.monoMode = True;
1921 highlightSquareColor = *(Pixel *) vTo.addr;
1925 if (!appData.monoMode) {
1926 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1927 vFrom.size = strlen(appData.premoveHighlightColor);
1928 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1929 if (vTo.addr == NULL) {
1930 appData.monoMode = True;
1933 premoveHighlightColor = *(Pixel *) vTo.addr;
1938 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1941 if (appData.bitmapDirectory == NULL ||
1942 appData.bitmapDirectory[0] == NULLCHAR)
1943 appData.bitmapDirectory = DEF_BITMAP_DIR;
1946 if (appData.lowTimeWarning && !appData.monoMode) {
1947 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
1948 vFrom.size = strlen(appData.lowTimeWarningColor);
1949 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1950 if (vTo.addr == NULL)
1951 appData.monoMode = True;
1953 lowTimeWarningColor = *(Pixel *) vTo.addr;
1956 if (appData.monoMode && appData.debugMode) {
1957 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1958 (unsigned long) XWhitePixel(xDisplay, xScreen),
1959 (unsigned long) XBlackPixel(xDisplay, xScreen));
1962 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1963 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1964 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1965 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1966 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1967 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1968 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1969 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1970 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1971 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1973 if (appData.colorize) {
1975 _("%s: can't parse color names; disabling colorization\n"),
1978 appData.colorize = FALSE;
1980 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
1981 textColors[ColorNone].attr = 0;
1983 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
1989 layoutName = "tinyLayout";
1990 } else if (smallLayout) {
1991 layoutName = "smallLayout";
1993 layoutName = "normalLayout";
1995 /* Outer layoutWidget is there only to provide a name for use in
1996 resources that depend on the layout style */
1998 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
1999 layoutArgs, XtNumber(layoutArgs));
2001 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2002 formArgs, XtNumber(formArgs));
2003 XtSetArg(args[0], XtNdefaultDistance, &sep);
2004 XtGetValues(formWidget, args, 1);
2007 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2008 XtSetArg(args[0], XtNtop, XtChainTop);
2009 XtSetArg(args[1], XtNbottom, XtChainTop);
2010 XtSetArg(args[2], XtNright, XtChainLeft);
2011 XtSetValues(menuBarWidget, args, 3);
2013 widgetList[j++] = whiteTimerWidget =
2014 XtCreateWidget("whiteTime", labelWidgetClass,
2015 formWidget, timerArgs, XtNumber(timerArgs));
2016 XtSetArg(args[0], XtNfont, clockFontStruct);
2017 XtSetArg(args[1], XtNtop, XtChainTop);
2018 XtSetArg(args[2], XtNbottom, XtChainTop);
2019 XtSetValues(whiteTimerWidget, args, 3);
2021 widgetList[j++] = blackTimerWidget =
2022 XtCreateWidget("blackTime", labelWidgetClass,
2023 formWidget, timerArgs, XtNumber(timerArgs));
2024 XtSetArg(args[0], XtNfont, clockFontStruct);
2025 XtSetArg(args[1], XtNtop, XtChainTop);
2026 XtSetArg(args[2], XtNbottom, XtChainTop);
2027 XtSetValues(blackTimerWidget, args, 3);
2029 if (appData.titleInWindow) {
2030 widgetList[j++] = titleWidget =
2031 XtCreateWidget("title", labelWidgetClass, formWidget,
2032 titleArgs, XtNumber(titleArgs));
2033 XtSetArg(args[0], XtNtop, XtChainTop);
2034 XtSetArg(args[1], XtNbottom, XtChainTop);
2035 XtSetValues(titleWidget, args, 2);
2038 if (appData.showButtonBar) {
2039 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2040 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2041 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2042 XtSetArg(args[2], XtNtop, XtChainTop);
2043 XtSetArg(args[3], XtNbottom, XtChainTop);
2044 XtSetValues(buttonBarWidget, args, 4);
2047 widgetList[j++] = messageWidget =
2048 XtCreateWidget("message", labelWidgetClass, formWidget,
2049 messageArgs, XtNumber(messageArgs));
2050 XtSetArg(args[0], XtNtop, XtChainTop);
2051 XtSetArg(args[1], XtNbottom, XtChainTop);
2052 XtSetValues(messageWidget, args, 2);
2054 widgetList[j++] = boardWidget =
2055 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2056 XtNumber(boardArgs));
2058 XtManageChildren(widgetList, j);
2060 timerWidth = (boardWidth - sep) / 2;
2061 XtSetArg(args[0], XtNwidth, timerWidth);
2062 XtSetValues(whiteTimerWidget, args, 1);
2063 XtSetValues(blackTimerWidget, args, 1);
2065 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2066 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2067 XtGetValues(whiteTimerWidget, args, 2);
2069 if (appData.showButtonBar) {
2070 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2071 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2072 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2076 * formWidget uses these constraints but they are stored
2080 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2081 XtSetValues(menuBarWidget, args, i);
2082 if (appData.titleInWindow) {
2085 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2086 XtSetValues(whiteTimerWidget, args, i);
2088 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2089 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2090 XtSetValues(blackTimerWidget, args, i);
2092 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2093 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2094 XtSetValues(titleWidget, args, i);
2096 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2097 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2098 XtSetValues(messageWidget, args, i);
2099 if (appData.showButtonBar) {
2101 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2102 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2103 XtSetValues(buttonBarWidget, args, i);
2107 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2108 XtSetValues(whiteTimerWidget, args, i);
2110 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2111 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2112 XtSetValues(blackTimerWidget, args, i);
2114 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2115 XtSetValues(titleWidget, args, i);
2117 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2118 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2119 XtSetValues(messageWidget, args, i);
2120 if (appData.showButtonBar) {
2122 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2123 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2124 XtSetValues(buttonBarWidget, args, i);
2129 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2130 XtSetValues(whiteTimerWidget, args, i);
2132 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2133 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2134 XtSetValues(blackTimerWidget, args, i);
2136 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2137 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2138 XtSetValues(messageWidget, args, i);
2139 if (appData.showButtonBar) {
2141 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2142 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2143 XtSetValues(buttonBarWidget, args, i);
2147 XtSetArg(args[0], XtNfromVert, messageWidget);
2148 XtSetArg(args[1], XtNtop, XtChainTop);
2149 XtSetArg(args[2], XtNbottom, XtChainBottom);
2150 XtSetArg(args[3], XtNleft, XtChainLeft);
2151 XtSetArg(args[4], XtNright, XtChainRight);
2152 XtSetValues(boardWidget, args, 5);
2154 XtRealizeWidget(shellWidget);
2157 XtSetArg(args[0], XtNx, wpMain.x);
2158 XtSetArg(args[1], XtNy, wpMain.y);
2159 XtSetValues(shellWidget, args, 2);
2163 * Correct the width of the message and title widgets.
2164 * It is not known why some systems need the extra fudge term.
2165 * The value "2" is probably larger than needed.
2167 XawFormDoLayout(formWidget, False);
2169 #define WIDTH_FUDGE 2
2171 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2172 XtSetArg(args[i], XtNheight, &h); i++;
2173 XtGetValues(messageWidget, args, i);
2174 if (appData.showButtonBar) {
2176 XtSetArg(args[i], XtNwidth, &w); i++;
2177 XtGetValues(buttonBarWidget, args, i);
2178 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2180 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2183 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2184 if (gres != XtGeometryYes && appData.debugMode) {
2185 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2186 programName, gres, w, h, wr, hr);
2189 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2190 /* The size used for the child widget in layout lags one resize behind
2191 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2193 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2194 if (gres != XtGeometryYes && appData.debugMode) {
2195 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2196 programName, gres, w, h, wr, hr);
2199 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2200 XtSetArg(args[1], XtNright, XtChainRight);
2201 XtSetValues(messageWidget, args, 2);
2203 if (appData.titleInWindow) {
2205 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2206 XtSetArg(args[i], XtNheight, &h); i++;
2207 XtGetValues(titleWidget, args, i);
2209 w = boardWidth - 2*bor;
2211 XtSetArg(args[0], XtNwidth, &w);
2212 XtGetValues(menuBarWidget, args, 1);
2213 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2216 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2217 if (gres != XtGeometryYes && appData.debugMode) {
2219 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2220 programName, gres, w, h, wr, hr);
2223 XawFormDoLayout(formWidget, True);
2225 xBoardWindow = XtWindow(boardWidget);
2227 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2228 // not need to go into InitDrawingSizes().
2232 * Create X checkmark bitmap and initialize option menu checks.
2234 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2235 checkmark_bits, checkmark_width, checkmark_height);
2236 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2237 if (appData.alwaysPromoteToQueen) {
2238 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2241 if (appData.animateDragging) {
2242 XtSetValues(XtNameToWidget(menuBarWidget,
2243 "menuOptions.Animate Dragging"),
2246 if (appData.animate) {
2247 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2250 if (appData.autoComment) {
2251 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2254 if (appData.autoCallFlag) {
2255 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2258 if (appData.autoFlipView) {
2259 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2262 if (appData.autoObserve) {
2263 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2266 if (appData.autoRaiseBoard) {
2267 XtSetValues(XtNameToWidget(menuBarWidget,
2268 "menuOptions.Auto Raise Board"), args, 1);
2270 if (appData.autoSaveGames) {
2271 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2274 if (appData.saveGameFile[0] != NULLCHAR) {
2275 /* Can't turn this off from menu */
2276 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2278 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2282 if (appData.blindfold) {
2283 XtSetValues(XtNameToWidget(menuBarWidget,
2284 "menuOptions.Blindfold"), args, 1);
2286 if (appData.flashCount > 0) {
2287 XtSetValues(XtNameToWidget(menuBarWidget,
2288 "menuOptions.Flash Moves"),
2291 if (appData.getMoveList) {
2292 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2296 if (appData.highlightDragging) {
2297 XtSetValues(XtNameToWidget(menuBarWidget,
2298 "menuOptions.Highlight Dragging"),
2302 if (appData.highlightLastMove) {
2303 XtSetValues(XtNameToWidget(menuBarWidget,
2304 "menuOptions.Highlight Last Move"),
2307 if (appData.icsAlarm) {
2308 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2311 if (appData.ringBellAfterMoves) {
2312 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2315 if (appData.oldSaveStyle) {
2316 XtSetValues(XtNameToWidget(menuBarWidget,
2317 "menuOptions.Old Save Style"), args, 1);
2319 if (appData.periodicUpdates) {
2320 XtSetValues(XtNameToWidget(menuBarWidget,
2321 "menuOptions.Periodic Updates"), args, 1);
2323 if (appData.ponderNextMove) {
2324 XtSetValues(XtNameToWidget(menuBarWidget,
2325 "menuOptions.Ponder Next Move"), args, 1);
2327 if (appData.popupExitMessage) {
2328 XtSetValues(XtNameToWidget(menuBarWidget,
2329 "menuOptions.Popup Exit Message"), args, 1);
2331 if (appData.popupMoveErrors) {
2332 XtSetValues(XtNameToWidget(menuBarWidget,
2333 "menuOptions.Popup Move Errors"), args, 1);
2335 if (appData.premove) {
2336 XtSetValues(XtNameToWidget(menuBarWidget,
2337 "menuOptions.Premove"), args, 1);
2339 if (appData.quietPlay) {
2340 XtSetValues(XtNameToWidget(menuBarWidget,
2341 "menuOptions.Quiet Play"), args, 1);
2343 if (appData.showCoords) {
2344 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2347 if (appData.hideThinkingFromHuman) {
2348 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2351 if (appData.testLegality) {
2352 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2355 if (saveSettingsOnExit) {
2356 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2363 ReadBitmap(&wIconPixmap, "icon_white.bm",
2364 icon_white_bits, icon_white_width, icon_white_height);
2365 ReadBitmap(&bIconPixmap, "icon_black.bm",
2366 icon_black_bits, icon_black_width, icon_black_height);
2367 iconPixmap = wIconPixmap;
2369 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2370 XtSetValues(shellWidget, args, i);
2373 * Create a cursor for the board widget.
2375 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2376 XChangeWindowAttributes(xDisplay, xBoardWindow,
2377 CWCursor, &window_attributes);
2380 * Inhibit shell resizing.
2382 shellArgs[0].value = (XtArgVal) &w;
2383 shellArgs[1].value = (XtArgVal) &h;
2384 XtGetValues(shellWidget, shellArgs, 2);
2385 shellArgs[4].value = shellArgs[2].value = w;
2386 shellArgs[5].value = shellArgs[3].value = h;
2387 XtSetValues(shellWidget, &shellArgs[2], 4);
2388 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2389 marginH = h - boardHeight;
2391 CatchDeleteWindow(shellWidget, "QuitProc");
2396 if (appData.bitmapDirectory[0] != NULLCHAR) {
2403 /* Create regular pieces */
2404 if (!useImages) CreatePieces();
2409 if (appData.animate || appData.animateDragging)
2412 XtAugmentTranslations(formWidget,
2413 XtParseTranslationTable(globalTranslations));
2414 XtAugmentTranslations(boardWidget,
2415 XtParseTranslationTable(boardTranslations));
2416 XtAugmentTranslations(whiteTimerWidget,
2417 XtParseTranslationTable(whiteTranslations));
2418 XtAugmentTranslations(blackTimerWidget,
2419 XtParseTranslationTable(blackTranslations));
2421 /* Why is the following needed on some versions of X instead
2422 * of a translation? */
2423 XtAddEventHandler(boardWidget, ExposureMask, False,
2424 (XtEventHandler) EventProc, NULL);
2427 /* [AS] Restore layout */
2428 if( wpMoveHistory.visible ) {
2432 if( wpEvalGraph.visible )
2437 if( wpEngineOutput.visible ) {
2438 EngineOutputPopUp();
2443 if (errorExitStatus == -1) {
2444 if (appData.icsActive) {
2445 /* We now wait until we see "login:" from the ICS before
2446 sending the logon script (problems with timestamp otherwise) */
2447 /*ICSInitScript();*/
2448 if (appData.icsInputBox) ICSInputBoxPopUp();
2452 signal(SIGWINCH, TermSizeSigHandler);
2454 signal(SIGINT, IntSigHandler);
2455 signal(SIGTERM, IntSigHandler);
2456 if (*appData.cmailGameName != NULLCHAR) {
2457 signal(SIGUSR1, CmailSigHandler);
2460 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2463 XtAppMainLoop(appContext);
2464 if (appData.debugMode) fclose(debugFP); // [DM] debug
2471 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2472 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2474 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2475 unlink(gameCopyFilename);
2476 unlink(gamePasteFilename);
2479 RETSIGTYPE TermSizeSigHandler(int sig)
2492 CmailSigHandler(sig)
2498 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2500 /* Activate call-back function CmailSigHandlerCallBack() */
2501 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2503 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2507 CmailSigHandlerCallBack(isr, closure, message, count, error)
2515 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2517 /**** end signal code ****/
2527 f = fopen(appData.icsLogon, "r");
2533 strcat(buf, appData.icsLogon);
2534 f = fopen(buf, "r");
2538 ProcessICSInitScript(f);
2545 EditCommentPopDown();
2560 if (!menuBarWidget) return;
2561 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2563 DisplayError("menuStep.Revert", 0);
2565 XtSetSensitive(w, !grey);
2570 SetMenuEnables(enab)
2574 if (!menuBarWidget) return;
2575 while (enab->name != NULL) {
2576 w = XtNameToWidget(menuBarWidget, enab->name);
2578 DisplayError(enab->name, 0);
2580 XtSetSensitive(w, enab->value);
2586 Enables icsEnables[] = {
2587 { "menuFile.Mail Move", False },
2588 { "menuFile.Reload CMail Message", False },
2589 { "menuMode.Machine Black", False },
2590 { "menuMode.Machine White", False },
2591 { "menuMode.Analysis Mode", False },
2592 { "menuMode.Analyze File", False },
2593 { "menuMode.Two Machines", False },
2595 { "menuHelp.Hint", False },
2596 { "menuHelp.Book", False },
2597 { "menuStep.Move Now", False },
2598 { "menuOptions.Periodic Updates", False },
2599 { "menuOptions.Hide Thinking", False },
2600 { "menuOptions.Ponder Next Move", False },
2605 Enables ncpEnables[] = {
2606 { "menuFile.Mail Move", False },
2607 { "menuFile.Reload CMail Message", False },
2608 { "menuMode.Machine White", False },
2609 { "menuMode.Machine Black", False },
2610 { "menuMode.Analysis Mode", False },
2611 { "menuMode.Analyze File", False },
2612 { "menuMode.Two Machines", False },
2613 { "menuMode.ICS Client", False },
2614 { "menuMode.ICS Input Box", False },
2615 { "Action", False },
2616 { "menuStep.Revert", False },
2617 { "menuStep.Move Now", False },
2618 { "menuStep.Retract Move", False },
2619 { "menuOptions.Auto Comment", False },
2620 { "menuOptions.Auto Flag", False },
2621 { "menuOptions.Auto Flip View", False },
2622 { "menuOptions.Auto Observe", False },
2623 { "menuOptions.Auto Raise Board", False },
2624 { "menuOptions.Get Move List", False },
2625 { "menuOptions.ICS Alarm", False },
2626 { "menuOptions.Move Sound", False },
2627 { "menuOptions.Quiet Play", False },
2628 { "menuOptions.Hide Thinking", False },
2629 { "menuOptions.Periodic Updates", False },
2630 { "menuOptions.Ponder Next Move", False },
2631 { "menuHelp.Hint", False },
2632 { "menuHelp.Book", False },
2636 Enables gnuEnables[] = {
2637 { "menuMode.ICS Client", False },
2638 { "menuMode.ICS Input Box", False },
2639 { "menuAction.Accept", False },
2640 { "menuAction.Decline", False },
2641 { "menuAction.Rematch", False },
2642 { "menuAction.Adjourn", False },
2643 { "menuAction.Stop Examining", False },
2644 { "menuAction.Stop Observing", False },
2645 { "menuStep.Revert", False },
2646 { "menuOptions.Auto Comment", False },
2647 { "menuOptions.Auto Observe", False },
2648 { "menuOptions.Auto Raise Board", False },
2649 { "menuOptions.Get Move List", False },
2650 { "menuOptions.Premove", False },
2651 { "menuOptions.Quiet Play", False },
2653 /* The next two options rely on SetCmailMode being called *after* */
2654 /* SetGNUMode so that when GNU is being used to give hints these */
2655 /* menu options are still available */
2657 { "menuFile.Mail Move", False },
2658 { "menuFile.Reload CMail Message", False },
2662 Enables cmailEnables[] = {
2664 { "menuAction.Call Flag", False },
2665 { "menuAction.Draw", True },
2666 { "menuAction.Adjourn", False },
2667 { "menuAction.Abort", False },
2668 { "menuAction.Stop Observing", False },
2669 { "menuAction.Stop Examining", False },
2670 { "menuFile.Mail Move", True },
2671 { "menuFile.Reload CMail Message", True },
2675 Enables trainingOnEnables[] = {
2676 { "menuMode.Edit Comment", False },
2677 { "menuMode.Pause", False },
2678 { "menuStep.Forward", False },
2679 { "menuStep.Backward", False },
2680 { "menuStep.Forward to End", False },
2681 { "menuStep.Back to Start", False },
2682 { "menuStep.Move Now", False },
2683 { "menuStep.Truncate Game", False },
2687 Enables trainingOffEnables[] = {
2688 { "menuMode.Edit Comment", True },
2689 { "menuMode.Pause", True },
2690 { "menuStep.Forward", True },
2691 { "menuStep.Backward", True },
2692 { "menuStep.Forward to End", True },
2693 { "menuStep.Back to Start", True },
2694 { "menuStep.Move Now", True },
2695 { "menuStep.Truncate Game", True },
2699 Enables machineThinkingEnables[] = {
2700 { "menuFile.Load Game", False },
2701 { "menuFile.Load Next Game", False },
2702 { "menuFile.Load Previous Game", False },
2703 { "menuFile.Reload Same Game", False },
2704 { "menuFile.Paste Game", False },
2705 { "menuFile.Load Position", False },
2706 { "menuFile.Load Next Position", False },
2707 { "menuFile.Load Previous Position", False },
2708 { "menuFile.Reload Same Position", False },
2709 { "menuFile.Paste Position", False },
2710 { "menuMode.Machine White", False },
2711 { "menuMode.Machine Black", False },
2712 { "menuMode.Two Machines", False },
2713 { "menuStep.Retract Move", False },
2717 Enables userThinkingEnables[] = {
2718 { "menuFile.Load Game", True },
2719 { "menuFile.Load Next Game", True },
2720 { "menuFile.Load Previous Game", True },
2721 { "menuFile.Reload Same Game", True },
2722 { "menuFile.Paste Game", True },
2723 { "menuFile.Load Position", True },
2724 { "menuFile.Load Next Position", True },
2725 { "menuFile.Load Previous Position", True },
2726 { "menuFile.Reload Same Position", True },
2727 { "menuFile.Paste Position", True },
2728 { "menuMode.Machine White", True },
2729 { "menuMode.Machine Black", True },
2730 { "menuMode.Two Machines", True },
2731 { "menuStep.Retract Move", True },
2737 SetMenuEnables(icsEnables);
2740 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2741 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2748 SetMenuEnables(ncpEnables);
2754 SetMenuEnables(gnuEnables);
2760 SetMenuEnables(cmailEnables);
2766 SetMenuEnables(trainingOnEnables);
2767 if (appData.showButtonBar) {
2768 XtSetSensitive(buttonBarWidget, False);
2774 SetTrainingModeOff()
2776 SetMenuEnables(trainingOffEnables);
2777 if (appData.showButtonBar) {
2778 XtSetSensitive(buttonBarWidget, True);
2783 SetUserThinkingEnables()
2785 if (appData.noChessProgram) return;
2786 SetMenuEnables(userThinkingEnables);
2790 SetMachineThinkingEnables()
2792 if (appData.noChessProgram) return;
2793 SetMenuEnables(machineThinkingEnables);
2795 case MachinePlaysBlack:
2796 case MachinePlaysWhite:
2797 case TwoMachinesPlay:
2798 XtSetSensitive(XtNameToWidget(menuBarWidget,
2799 ModeToWidgetName(gameMode)), True);
2806 #define Abs(n) ((n)<0 ? -(n) : (n))
2809 * Find a font that matches "pattern" that is as close as
2810 * possible to the targetPxlSize. Prefer fonts that are k
2811 * pixels smaller to fonts that are k pixels larger. The
2812 * pattern must be in the X Consortium standard format,
2813 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2814 * The return value should be freed with XtFree when no
2817 char *FindFont(pattern, targetPxlSize)
2821 char **fonts, *p, *best, *scalable, *scalableTail;
2822 int i, j, nfonts, minerr, err, pxlSize;
2825 char **missing_list;
2827 char *def_string, *base_fnt_lst, strInt[3];
2829 XFontStruct **fnt_list;
2831 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2832 sprintf(strInt, "%d", targetPxlSize);
2833 p = strstr(pattern, "--");
2834 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2835 strcat(base_fnt_lst, strInt);
2836 strcat(base_fnt_lst, strchr(p + 2, '-'));
2838 if ((fntSet = XCreateFontSet(xDisplay,
2842 &def_string)) == NULL) {
2844 fprintf(stderr, _("Unable to create font set.\n"));
2848 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2850 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2852 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2853 programName, pattern);
2861 for (i=0; i<nfonts; i++) {
2864 if (*p != '-') continue;
2866 if (*p == NULLCHAR) break;
2867 if (*p++ == '-') j++;
2869 if (j < 7) continue;
2872 scalable = fonts[i];
2875 err = pxlSize - targetPxlSize;
2876 if (Abs(err) < Abs(minerr) ||
2877 (minerr > 0 && err < 0 && -err == minerr)) {
2883 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
2884 /* If the error is too big and there is a scalable font,
2885 use the scalable font. */
2886 int headlen = scalableTail - scalable;
2887 p = (char *) XtMalloc(strlen(scalable) + 10);
2888 while (isdigit(*scalableTail)) scalableTail++;
2889 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
2891 p = (char *) XtMalloc(strlen(best) + 1);
2894 if (appData.debugMode) {
2895 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
2896 pattern, targetPxlSize, p);
2899 if (missing_count > 0)
2900 XFreeStringList(missing_list);
2901 XFreeFontSet(xDisplay, fntSet);
2903 XFreeFontNames(fonts);
2910 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
2911 | GCBackground | GCFunction | GCPlaneMask;
2912 XGCValues gc_values;
2915 gc_values.plane_mask = AllPlanes;
2916 gc_values.line_width = lineGap;
2917 gc_values.line_style = LineSolid;
2918 gc_values.function = GXcopy;
2920 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2921 gc_values.background = XBlackPixel(xDisplay, xScreen);
2922 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2924 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2925 gc_values.background = XWhitePixel(xDisplay, xScreen);
2926 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
2927 XSetFont(xDisplay, coordGC, coordFontID);
2929 // [HGM] make font for holdings counts (white on black0
2930 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2931 gc_values.background = XBlackPixel(xDisplay, xScreen);
2932 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
2933 XSetFont(xDisplay, countGC, countFontID);
2935 if (appData.monoMode) {
2936 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2937 gc_values.background = XWhitePixel(xDisplay, xScreen);
2938 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2940 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2941 gc_values.background = XBlackPixel(xDisplay, xScreen);
2942 lightSquareGC = wbPieceGC
2943 = XtGetGC(shellWidget, value_mask, &gc_values);
2945 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2946 gc_values.background = XWhitePixel(xDisplay, xScreen);
2947 darkSquareGC = bwPieceGC
2948 = XtGetGC(shellWidget, value_mask, &gc_values);
2950 if (DefaultDepth(xDisplay, xScreen) == 1) {
2951 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
2952 gc_values.function = GXcopyInverted;
2953 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
2954 gc_values.function = GXcopy;
2955 if (XBlackPixel(xDisplay, xScreen) == 1) {
2956 bwPieceGC = darkSquareGC;
2957 wbPieceGC = copyInvertedGC;
2959 bwPieceGC = copyInvertedGC;
2960 wbPieceGC = lightSquareGC;
2964 gc_values.foreground = highlightSquareColor;
2965 gc_values.background = highlightSquareColor;
2966 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2968 gc_values.foreground = premoveHighlightColor;
2969 gc_values.background = premoveHighlightColor;
2970 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2972 gc_values.foreground = lightSquareColor;
2973 gc_values.background = darkSquareColor;
2974 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2976 gc_values.foreground = darkSquareColor;
2977 gc_values.background = lightSquareColor;
2978 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2980 gc_values.foreground = jailSquareColor;
2981 gc_values.background = jailSquareColor;
2982 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2984 gc_values.foreground = whitePieceColor;
2985 gc_values.background = darkSquareColor;
2986 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
2988 gc_values.foreground = whitePieceColor;
2989 gc_values.background = lightSquareColor;
2990 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
2992 gc_values.foreground = whitePieceColor;
2993 gc_values.background = jailSquareColor;
2994 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
2996 gc_values.foreground = blackPieceColor;
2997 gc_values.background = darkSquareColor;
2998 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3000 gc_values.foreground = blackPieceColor;
3001 gc_values.background = lightSquareColor;
3002 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3004 gc_values.foreground = blackPieceColor;
3005 gc_values.background = jailSquareColor;
3006 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3010 void loadXIM(xim, xmask, filename, dest, mask)
3023 fp = fopen(filename, "rb");
3025 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3032 for (y=0; y<h; ++y) {
3033 for (x=0; x<h; ++x) {
3038 XPutPixel(xim, x, y, blackPieceColor);
3040 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3043 XPutPixel(xim, x, y, darkSquareColor);
3045 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3048 XPutPixel(xim, x, y, whitePieceColor);
3050 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3053 XPutPixel(xim, x, y, lightSquareColor);
3055 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3061 /* create Pixmap of piece */
3062 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3064 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3067 /* create Pixmap of clipmask
3068 Note: We assume the white/black pieces have the same
3069 outline, so we make only 6 masks. This is okay
3070 since the XPM clipmask routines do the same. */
3072 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3074 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3077 /* now create the 1-bit version */
3078 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3081 values.foreground = 1;
3082 values.background = 0;
3084 /* Don't use XtGetGC, not read only */
3085 maskGC = XCreateGC(xDisplay, *mask,
3086 GCForeground | GCBackground, &values);
3087 XCopyPlane(xDisplay, temp, *mask, maskGC,
3088 0, 0, squareSize, squareSize, 0, 0, 1);
3089 XFreePixmap(xDisplay, temp);
3094 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3096 void CreateXIMPieces()
3101 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3106 /* The XSynchronize calls were copied from CreatePieces.
3107 Not sure if needed, but can't hurt */
3108 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3111 /* temp needed by loadXIM() */
3112 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3113 0, 0, ss, ss, AllPlanes, XYPixmap);
3115 if (strlen(appData.pixmapDirectory) == 0) {
3119 if (appData.monoMode) {
3120 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3124 fprintf(stderr, _("\nLoading XIMs...\n"));
3126 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3127 fprintf(stderr, "%d", piece+1);
3128 for (kind=0; kind<4; kind++) {
3129 fprintf(stderr, ".");
3130 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3131 ExpandPathName(appData.pixmapDirectory),
3132 piece <= (int) WhiteKing ? "" : "w",
3133 pieceBitmapNames[piece],
3135 ximPieceBitmap[kind][piece] =
3136 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3137 0, 0, ss, ss, AllPlanes, XYPixmap);
3138 if (appData.debugMode)
3139 fprintf(stderr, _("(File:%s:) "), buf);
3140 loadXIM(ximPieceBitmap[kind][piece],
3142 &(xpmPieceBitmap2[kind][piece]),
3143 &(ximMaskPm2[piece]));
3144 if(piece <= (int)WhiteKing)
3145 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3147 fprintf(stderr," ");
3149 /* Load light and dark squares */
3150 /* If the LSQ and DSQ pieces don't exist, we will
3151 draw them with solid squares. */
3152 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3153 if (access(buf, 0) != 0) {
3157 fprintf(stderr, _("light square "));
3159 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3160 0, 0, ss, ss, AllPlanes, XYPixmap);
3161 if (appData.debugMode)
3162 fprintf(stderr, _("(File:%s:) "), buf);
3164 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3165 fprintf(stderr, _("dark square "));
3166 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3167 ExpandPathName(appData.pixmapDirectory), ss);
3168 if (appData.debugMode)
3169 fprintf(stderr, _("(File:%s:) "), buf);
3171 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3172 0, 0, ss, ss, AllPlanes, XYPixmap);
3173 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3174 xpmJailSquare = xpmLightSquare;
3176 fprintf(stderr, _("Done.\n"));
3178 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3182 void CreateXPMPieces()
3186 u_int ss = squareSize;
3188 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3189 XpmColorSymbol symbols[4];
3191 /* The XSynchronize calls were copied from CreatePieces.
3192 Not sure if needed, but can't hurt */
3193 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3195 /* Setup translations so piece colors match square colors */
3196 symbols[0].name = "light_piece";
3197 symbols[0].value = appData.whitePieceColor;
3198 symbols[1].name = "dark_piece";
3199 symbols[1].value = appData.blackPieceColor;
3200 symbols[2].name = "light_square";
3201 symbols[2].value = appData.lightSquareColor;
3202 symbols[3].name = "dark_square";
3203 symbols[3].value = appData.darkSquareColor;
3205 attr.valuemask = XpmColorSymbols;
3206 attr.colorsymbols = symbols;
3207 attr.numsymbols = 4;
3209 if (appData.monoMode) {
3210 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3214 if (strlen(appData.pixmapDirectory) == 0) {
3215 XpmPieces* pieces = builtInXpms;
3218 while (pieces->size != squareSize && pieces->size) pieces++;
3219 if (!pieces->size) {
3220 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3223 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3224 for (kind=0; kind<4; kind++) {
3226 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3227 pieces->xpm[piece][kind],
3228 &(xpmPieceBitmap2[kind][piece]),
3229 NULL, &attr)) != 0) {
3230 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3234 if(piece <= (int) WhiteKing)
3235 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3239 xpmJailSquare = xpmLightSquare;
3243 fprintf(stderr, _("\nLoading XPMs...\n"));
3246 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3247 fprintf(stderr, "%d ", piece+1);
3248 for (kind=0; kind<4; kind++) {
3249 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3250 ExpandPathName(appData.pixmapDirectory),
3251 piece > (int) WhiteKing ? "w" : "",
3252 pieceBitmapNames[piece],
3254 if (appData.debugMode) {
3255 fprintf(stderr, _("(File:%s:) "), buf);
3257 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3258 &(xpmPieceBitmap2[kind][piece]),
3259 NULL, &attr)) != 0) {
3260 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3261 // [HGM] missing: read of unorthodox piece failed; substitute King.
3262 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3263 ExpandPathName(appData.pixmapDirectory),
3265 if (appData.debugMode) {
3266 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3268 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3269 &(xpmPieceBitmap2[kind][piece]),
3273 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3278 if(piece <= (int) WhiteKing)
3279 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3282 /* Load light and dark squares */
3283 /* If the LSQ and DSQ pieces don't exist, we will
3284 draw them with solid squares. */
3285 fprintf(stderr, _("light square "));
3286 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3287 if (access(buf, 0) != 0) {
3291 if (appData.debugMode)
3292 fprintf(stderr, _("(File:%s:) "), buf);
3294 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3295 &xpmLightSquare, NULL, &attr)) != 0) {
3296 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3299 fprintf(stderr, _("dark square "));
3300 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3301 ExpandPathName(appData.pixmapDirectory), ss);
3302 if (appData.debugMode) {
3303 fprintf(stderr, _("(File:%s:) "), buf);
3305 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3306 &xpmDarkSquare, NULL, &attr)) != 0) {
3307 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3311 xpmJailSquare = xpmLightSquare;
3312 fprintf(stderr, _("Done.\n"));
3314 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3317 #endif /* HAVE_LIBXPM */
3320 /* No built-in bitmaps */
3325 u_int ss = squareSize;
3327 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3330 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3331 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3332 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3333 pieceBitmapNames[piece],
3334 ss, kind == SOLID ? 's' : 'o');
3335 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3336 if(piece <= (int)WhiteKing)
3337 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3341 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3345 /* With built-in bitmaps */
3348 BuiltInBits* bib = builtInBits;
3351 u_int ss = squareSize;
3353 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3356 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3358 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3359 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3360 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3361 pieceBitmapNames[piece],
3362 ss, kind == SOLID ? 's' : 'o');
3363 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3364 bib->bits[kind][piece], ss, ss);
3365 if(piece <= (int)WhiteKing)
3366 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3370 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3375 void ReadBitmap(pm, name, bits, wreq, hreq)
3378 unsigned char bits[];
3384 char msg[MSG_SIZ], fullname[MSG_SIZ];
3386 if (*appData.bitmapDirectory != NULLCHAR) {
3387 strcpy(fullname, appData.bitmapDirectory);
3388 strcat(fullname, "/");
3389 strcat(fullname, name);
3390 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3391 &w, &h, pm, &x_hot, &y_hot);
3392 fprintf(stderr, "load %s\n", name);
3393 if (errcode != BitmapSuccess) {
3395 case BitmapOpenFailed:
3396 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3398 case BitmapFileInvalid:
3399 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3401 case BitmapNoMemory:
3402 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3406 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3410 fprintf(stderr, _("%s: %s...using built-in\n"),
3412 } else if (w != wreq || h != hreq) {
3414 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3415 programName, fullname, w, h, wreq, hreq);
3421 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3430 if (lineGap == 0) return;
3432 /* [HR] Split this into 2 loops for non-square boards. */
3434 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3435 gridSegments[i].x1 = 0;
3436 gridSegments[i].x2 =
3437 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3438 gridSegments[i].y1 = gridSegments[i].y2
3439 = lineGap / 2 + (i * (squareSize + lineGap));
3442 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3443 gridSegments[j + i].y1 = 0;
3444 gridSegments[j + i].y2 =
3445 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3446 gridSegments[j + i].x1 = gridSegments[j + i].x2
3447 = lineGap / 2 + (j * (squareSize + lineGap));
3451 static void MenuBarSelect(w, addr, index)
3456 XtActionProc proc = (XtActionProc) addr;
3458 (proc)(NULL, NULL, NULL, NULL);
3461 void CreateMenuBarPopup(parent, name, mb)
3471 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3474 XtSetArg(args[j], XtNleftMargin, 20); j++;
3475 XtSetArg(args[j], XtNrightMargin, 20); j++;
3477 while (mi->string != NULL) {
3478 if (strcmp(mi->string, "----") == 0) {
3479 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3482 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3483 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3485 XtAddCallback(entry, XtNcallback,
3486 (XtCallbackProc) MenuBarSelect,
3487 (caddr_t) mi->proc);
3493 Widget CreateMenuBar(mb)
3497 Widget anchor, menuBar;
3499 char menuName[MSG_SIZ];
3502 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3503 XtSetArg(args[j], XtNvSpace, 0); j++;
3504 XtSetArg(args[j], XtNborderWidth, 0); j++;
3505 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3506 formWidget, args, j);
3508 while (mb->name != NULL) {
3509 strcpy(menuName, "menu");
3510 strcat(menuName, mb->name);
3512 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3515 shortName[0] = _(mb->name)[0];
3516 shortName[1] = NULLCHAR;
3517 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3520 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3523 XtSetArg(args[j], XtNborderWidth, 0); j++;
3524 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3526 CreateMenuBarPopup(menuBar, menuName, mb);
3532 Widget CreateButtonBar(mi)
3536 Widget button, buttonBar;
3540 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3542 XtSetArg(args[j], XtNhSpace, 0); j++;
3544 XtSetArg(args[j], XtNborderWidth, 0); j++;
3545 XtSetArg(args[j], XtNvSpace, 0); j++;
3546 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3547 formWidget, args, j);
3549 while (mi->string != NULL) {
3552 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3553 XtSetArg(args[j], XtNborderWidth, 0); j++;
3555 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3556 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3557 buttonBar, args, j);
3558 XtAddCallback(button, XtNcallback,
3559 (XtCallbackProc) MenuBarSelect,
3560 (caddr_t) mi->proc);
3567 CreatePieceMenu(name, color)
3574 ChessSquare selection;
3576 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3577 boardWidget, args, 0);
3579 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3580 String item = pieceMenuStrings[color][i];
3582 if (strcmp(item, "----") == 0) {
3583 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3586 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3587 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3589 selection = pieceMenuTranslation[color][i];
3590 XtAddCallback(entry, XtNcallback,
3591 (XtCallbackProc) PieceMenuSelect,
3592 (caddr_t) selection);
3593 if (selection == WhitePawn || selection == BlackPawn) {
3594 XtSetArg(args[0], XtNpopupOnEntry, entry);
3595 XtSetValues(menu, args, 1);
3608 ChessSquare selection;
3610 whitePieceMenu = CreatePieceMenu("menuW", 0);
3611 blackPieceMenu = CreatePieceMenu("menuB", 1);
3613 XtRegisterGrabAction(PieceMenuPopup, True,
3614 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3615 GrabModeAsync, GrabModeAsync);
3617 XtSetArg(args[0], XtNlabel, _("Drop"));
3618 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3619 boardWidget, args, 1);
3620 for (i = 0; i < DROP_MENU_SIZE; i++) {
3621 String item = dropMenuStrings[i];
3623 if (strcmp(item, "----") == 0) {
3624 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3627 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3628 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3630 selection = dropMenuTranslation[i];
3631 XtAddCallback(entry, XtNcallback,
3632 (XtCallbackProc) DropMenuSelect,
3633 (caddr_t) selection);
3638 void SetupDropMenu()
3646 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3647 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3648 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3649 dmEnables[i].piece);
3650 XtSetSensitive(entry, p != NULL || !appData.testLegality
3651 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3652 && !appData.icsActive));
3654 while (p && *p++ == dmEnables[i].piece) count++;
3655 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3657 XtSetArg(args[j], XtNlabel, label); j++;
3658 XtSetValues(entry, args, j);
3662 void PieceMenuPopup(w, event, params, num_params)
3666 Cardinal *num_params;
3669 if (event->type != ButtonPress) return;
3670 if (errorUp) ErrorPopDown();
3674 whichMenu = params[0];
3676 case IcsPlayingWhite:
3677 case IcsPlayingBlack:
3679 case MachinePlaysWhite:
3680 case MachinePlaysBlack:
3681 if (appData.testLegality &&
3682 gameInfo.variant != VariantBughouse &&
3683 gameInfo.variant != VariantCrazyhouse) return;
3685 whichMenu = "menuD";
3691 if (((pmFromX = EventToSquare(event->xbutton.x, BOARD_WIDTH)) < 0) ||
3692 ((pmFromY = EventToSquare(event->xbutton.y, BOARD_HEIGHT)) < 0)) {
3693 pmFromX = pmFromY = -1;
3697 pmFromX = BOARD_WIDTH - 1 - pmFromX;
3699 pmFromY = BOARD_HEIGHT - 1 - pmFromY;
3701 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3704 static void PieceMenuSelect(w, piece, junk)
3709 if (pmFromX < 0 || pmFromY < 0) return;
3710 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3713 static void DropMenuSelect(w, piece, junk)
3718 if (pmFromX < 0 || pmFromY < 0) return;
3719 DropMenuEvent(piece, pmFromX, pmFromY);
3722 void WhiteClock(w, event, prms, nprms)
3728 if (gameMode == EditPosition || gameMode == IcsExamining) {
3729 SetWhiteToPlayEvent();
3730 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3735 void BlackClock(w, event, prms, nprms)
3741 if (gameMode == EditPosition || gameMode == IcsExamining) {
3742 SetBlackToPlayEvent();
3743 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3750 * If the user selects on a border boundary, return -1; if off the board,
3751 * return -2. Otherwise map the event coordinate to the square.
3753 int EventToSquare(x, limit)
3761 if ((x % (squareSize + lineGap)) >= squareSize)
3763 x /= (squareSize + lineGap);
3769 static void do_flash_delay(msec)
3775 static void drawHighlight(file, rank, gc)
3781 if (lineGap == 0 || appData.blindfold) return;
3784 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3785 (squareSize + lineGap);
3786 y = lineGap/2 + rank * (squareSize + lineGap);
3788 x = lineGap/2 + file * (squareSize + lineGap);
3789 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3790 (squareSize + lineGap);
3793 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3794 squareSize+lineGap, squareSize+lineGap);
3797 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3798 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3801 SetHighlights(fromX, fromY, toX, toY)
3802 int fromX, fromY, toX, toY;
3804 if (hi1X != fromX || hi1Y != fromY) {
3805 if (hi1X >= 0 && hi1Y >= 0) {
3806 drawHighlight(hi1X, hi1Y, lineGC);
3808 if (fromX >= 0 && fromY >= 0) {
3809 drawHighlight(fromX, fromY, highlineGC);
3812 if (hi2X != toX || hi2Y != toY) {
3813 if (hi2X >= 0 && hi2Y >= 0) {
3814 drawHighlight(hi2X, hi2Y, lineGC);
3816 if (toX >= 0 && toY >= 0) {
3817 drawHighlight(toX, toY, highlineGC);
3829 SetHighlights(-1, -1, -1, -1);
3834 SetPremoveHighlights(fromX, fromY, toX, toY)
3835 int fromX, fromY, toX, toY;
3837 if (pm1X != fromX || pm1Y != fromY) {
3838 if (pm1X >= 0 && pm1Y >= 0) {
3839 drawHighlight(pm1X, pm1Y, lineGC);
3841 if (fromX >= 0 && fromY >= 0) {
3842 drawHighlight(fromX, fromY, prelineGC);
3845 if (pm2X != toX || pm2Y != toY) {
3846 if (pm2X >= 0 && pm2Y >= 0) {
3847 drawHighlight(pm2X, pm2Y, lineGC);
3849 if (toX >= 0 && toY >= 0) {
3850 drawHighlight(toX, toY, prelineGC);
3860 ClearPremoveHighlights()
3862 SetPremoveHighlights(-1, -1, -1, -1);
3865 static void BlankSquare(x, y, color, piece, dest)
3870 if (useImages && useImageSqs) {
3874 pm = xpmLightSquare;
3879 case 2: /* neutral */
3884 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
3885 squareSize, squareSize, x, y);
3895 case 2: /* neutral */
3900 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
3905 I split out the routines to draw a piece so that I could
3906 make a generic flash routine.
3908 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
3910 int square_color, x, y;
3913 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3914 switch (square_color) {
3916 case 2: /* neutral */
3918 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3919 ? *pieceToOutline(piece)
3920 : *pieceToSolid(piece),
3921 dest, bwPieceGC, 0, 0,
3922 squareSize, squareSize, x, y);
3925 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3926 ? *pieceToSolid(piece)
3927 : *pieceToOutline(piece),
3928 dest, wbPieceGC, 0, 0,
3929 squareSize, squareSize, x, y);
3934 static void monoDrawPiece(piece, square_color, x, y, dest)
3936 int square_color, x, y;
3939 switch (square_color) {
3941 case 2: /* neutral */
3943 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3944 ? *pieceToOutline(piece)
3945 : *pieceToSolid(piece),
3946 dest, bwPieceGC, 0, 0,
3947 squareSize, squareSize, x, y, 1);
3950 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3951 ? *pieceToSolid(piece)
3952 : *pieceToOutline(piece),
3953 dest, wbPieceGC, 0, 0,
3954 squareSize, squareSize, x, y, 1);
3959 static void colorDrawPiece(piece, square_color, x, y, dest)
3961 int square_color, x, y;
3964 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
3965 switch (square_color) {
3967 XCopyPlane(xDisplay, *pieceToSolid(piece),
3968 dest, (int) piece < (int) BlackPawn
3969 ? wlPieceGC : blPieceGC, 0, 0,
3970 squareSize, squareSize, x, y, 1);
3973 XCopyPlane(xDisplay, *pieceToSolid(piece),
3974 dest, (int) piece < (int) BlackPawn
3975 ? wdPieceGC : bdPieceGC, 0, 0,
3976 squareSize, squareSize, x, y, 1);
3978 case 2: /* neutral */
3980 XCopyPlane(xDisplay, *pieceToSolid(piece),
3981 dest, (int) piece < (int) BlackPawn
3982 ? wjPieceGC : bjPieceGC, 0, 0,
3983 squareSize, squareSize, x, y, 1);
3988 static void colorDrawPieceImage(piece, square_color, x, y, dest)
3990 int square_color, x, y;
3995 switch (square_color) {
3997 case 2: /* neutral */
3999 if ((int)piece < (int) BlackPawn) {
4007 if ((int)piece < (int) BlackPawn) {
4015 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4016 dest, wlPieceGC, 0, 0,
4017 squareSize, squareSize, x, y);
4020 typedef void (*DrawFunc)();
4022 DrawFunc ChooseDrawFunc()
4024 if (appData.monoMode) {
4025 if (DefaultDepth(xDisplay, xScreen) == 1) {
4026 return monoDrawPiece_1bit;
4028 return monoDrawPiece;
4032 return colorDrawPieceImage;
4034 return colorDrawPiece;
4038 /* [HR] determine square color depending on chess variant. */
4039 static int SquareColor(row, column)
4044 if (gameInfo.variant == VariantXiangqi) {
4045 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4047 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4049 } else if (row <= 4) {
4055 square_color = ((column + row) % 2) == 1;
4058 /* [hgm] holdings: next line makes all holdings squares light */
4059 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4061 return square_color;
4064 void DrawSquare(row, column, piece, do_flash)
4065 int row, column, do_flash;
4068 int square_color, x, y, direction, font_ascent, font_descent;
4071 XCharStruct overall;
4075 /* Calculate delay in milliseconds (2-delays per complete flash) */
4076 flash_delay = 500 / appData.flashRate;
4079 x = lineGap + ((BOARD_WIDTH-1)-column) *
4080 (squareSize + lineGap);
4081 y = lineGap + row * (squareSize + lineGap);
4083 x = lineGap + column * (squareSize + lineGap);
4084 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4085 (squareSize + lineGap);
4088 square_color = SquareColor(row, column);
4090 if ( // [HGM] holdings: blank out area between board and holdings
4091 column == BOARD_LEFT-1 || column == BOARD_RGHT
4092 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4093 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4094 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4096 // [HGM] print piece counts next to holdings
4097 string[1] = NULLCHAR;
4098 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4099 string[0] = '0' + piece;
4100 XTextExtents(countFontStruct, string, 1, &direction,
4101 &font_ascent, &font_descent, &overall);
4102 if (appData.monoMode) {
4103 XDrawImageString(xDisplay, xBoardWindow, countGC,
4104 x + squareSize - overall.width - 2,
4105 y + font_ascent + 1, string, 1);
4107 XDrawString(xDisplay, xBoardWindow, countGC,
4108 x + squareSize - overall.width - 2,
4109 y + font_ascent + 1, string, 1);
4112 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4113 string[0] = '0' + piece;
4114 XTextExtents(countFontStruct, string, 1, &direction,
4115 &font_ascent, &font_descent, &overall);
4116 if (appData.monoMode) {
4117 XDrawImageString(xDisplay, xBoardWindow, countGC,
4118 x + 2, y + font_ascent + 1, string, 1);
4120 XDrawString(xDisplay, xBoardWindow, countGC,
4121 x + 2, y + font_ascent + 1, string, 1);
4125 if (piece == EmptySquare || appData.blindfold) {
4126 BlankSquare(x, y, square_color, piece, xBoardWindow);
4128 drawfunc = ChooseDrawFunc();
4129 if (do_flash && appData.flashCount > 0) {
4130 for (i=0; i<appData.flashCount; ++i) {
4132 drawfunc(piece, square_color, x, y, xBoardWindow);
4133 XSync(xDisplay, False);
4134 do_flash_delay(flash_delay);
4136 BlankSquare(x, y, square_color, piece, xBoardWindow);
4137 XSync(xDisplay, False);
4138 do_flash_delay(flash_delay);
4141 drawfunc(piece, square_color, x, y, xBoardWindow);
4145 string[1] = NULLCHAR;
4146 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4147 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4148 string[0] = 'a' + column - BOARD_LEFT;
4149 XTextExtents(coordFontStruct, string, 1, &direction,
4150 &font_ascent, &font_descent, &overall);
4151 if (appData.monoMode) {
4152 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4153 x + squareSize - overall.width - 2,
4154 y + squareSize - font_descent - 1, string, 1);
4156 XDrawString(xDisplay, xBoardWindow, coordGC,
4157 x + squareSize - overall.width - 2,
4158 y + squareSize - font_descent - 1, string, 1);
4161 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4162 string[0] = ONE + row;
4163 XTextExtents(coordFontStruct, string, 1, &direction,
4164 &font_ascent, &font_descent, &overall);
4165 if (appData.monoMode) {
4166 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4167 x + 2, y + font_ascent + 1, string, 1);
4169 XDrawString(xDisplay, xBoardWindow, coordGC,
4170 x + 2, y + font_ascent + 1, string, 1);
4176 /* Why is this needed on some versions of X? */
4177 void EventProc(widget, unused, event)
4182 if (!XtIsRealized(widget))
4185 switch (event->type) {
4187 if (event->xexpose.count > 0) return; /* no clipping is done */
4188 XDrawPosition(widget, True, NULL);
4196 void DrawPosition(fullRedraw, board)
4197 /*Boolean*/int fullRedraw;
4200 XDrawPosition(boardWidget, fullRedraw, board);
4203 /* Returns 1 if there are "too many" differences between b1 and b2
4204 (i.e. more than 1 move was made) */
4205 static int too_many_diffs(b1, b2)
4211 for (i=0; i<BOARD_HEIGHT; ++i) {
4212 for (j=0; j<BOARD_WIDTH; ++j) {
4213 if (b1[i][j] != b2[i][j]) {
4214 if (++c > 4) /* Castling causes 4 diffs */
4223 /* Matrix describing castling maneuvers */
4224 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4225 static int castling_matrix[4][5] = {
4226 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4227 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4228 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4229 { 7, 7, 4, 5, 6 } /* 0-0, black */
4232 /* Checks whether castling occurred. If it did, *rrow and *rcol
4233 are set to the destination (row,col) of the rook that moved.
4235 Returns 1 if castling occurred, 0 if not.
4237 Note: Only handles a max of 1 castling move, so be sure
4238 to call too_many_diffs() first.
4240 static int check_castle_draw(newb, oldb, rrow, rcol)
4247 /* For each type of castling... */
4248 for (i=0; i<4; ++i) {
4249 r = castling_matrix[i];
4251 /* Check the 4 squares involved in the castling move */