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(());
451 int CopyMemoProc P(());
453 * XBoard depends on Xt R4 or higher
455 int xtVersion = XtSpecificationRelease;
460 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
461 jailSquareColor, highlightSquareColor, premoveHighlightColor;
462 Pixel lowTimeWarningColor;
463 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
464 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
465 wjPieceGC, bjPieceGC, prelineGC, countGC;
466 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
467 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
468 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
469 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
470 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
471 ICSInputShell, fileNameShell, askQuestionShell;
472 Widget historyShell, evalGraphShell, gameListShell;
473 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
474 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
475 Font clockFontID, coordFontID, countFontID;
476 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
477 XtAppContext appContext;
479 char *oldICSInteractionTitle;
483 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
485 Position commentX = -1, commentY = -1;
486 Dimension commentW, commentH;
487 typedef unsigned int BoardSize;
489 Boolean chessProgram;
491 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
492 int squareSize, smallLayout = 0, tinyLayout = 0,
493 marginW, marginH, // [HGM] for run-time resizing
494 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
495 ICSInputBoxUp = False, askQuestionUp = False,
496 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
497 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
498 Pixel timerForegroundPixel, timerBackgroundPixel;
499 Pixel buttonForegroundPixel, buttonBackgroundPixel;
500 char *chessDir, *programName, *programVersion,
501 *gameCopyFilename, *gamePasteFilename;
502 Boolean alwaysOnTop = False;
503 Boolean saveSettingsOnExit;
504 char *settingsFileName;
505 char *icsTextMenuString;
507 char *firstChessProgramNames;
508 char *secondChessProgramNames;
510 WindowPlacement wpMain;
511 WindowPlacement wpConsole;
512 WindowPlacement wpComment;
513 WindowPlacement wpMoveHistory;
514 WindowPlacement wpEvalGraph;
515 WindowPlacement wpEngineOutput;
516 WindowPlacement wpGameList;
517 WindowPlacement wpTags;
521 Pixmap pieceBitmap[2][(int)BlackPawn];
522 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
523 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
524 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
525 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
526 int useImages, useImageSqs;
527 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
528 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
529 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
530 XImage *ximLightSquare, *ximDarkSquare;
533 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
534 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
536 #define White(piece) ((int)(piece) < (int)BlackPawn)
538 /* Variables for doing smooth animation. This whole thing
539 would be much easier if the board was double-buffered,
540 but that would require a fairly major rewrite. */
545 GC blitGC, pieceGC, outlineGC;
546 XPoint startSquare, prevFrame, mouseDelta;
550 int startBoardX, startBoardY;
553 /* There can be two pieces being animated at once: a player
554 can begin dragging a piece before the remote opponent has moved. */
556 static AnimState game, player;
558 /* Bitmaps for use as masks when drawing XPM pieces.
559 Need one for each black and white piece. */
560 static Pixmap xpmMask[BlackKing + 1];
562 /* This magic number is the number of intermediate frames used
563 in each half of the animation. For short moves it's reduced
564 by 1. The total number of frames will be factor * 2 + 1. */
567 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
569 MenuItem fileMenu[] = {
570 {N_("New Game"), ResetProc},
571 {N_("New Shuffle Game ..."), ShuffleMenuProc},
572 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
573 {"----", NothingProc},
574 {N_("Load Game"), LoadGameProc},
575 {N_("Load Next Game"), LoadNextGameProc},
576 {N_("Load Previous Game"), LoadPrevGameProc},
577 {N_("Reload Same Game"), ReloadGameProc},
578 {N_("Save Game"), SaveGameProc},
579 {"----", NothingProc},
580 {N_("Copy Game"), CopyGameProc},
581 {N_("Paste Game"), PasteGameProc},
582 {"----", NothingProc},
583 {N_("Load Position"), LoadPositionProc},
584 {N_("Load Next Position"), LoadNextPositionProc},
585 {N_("Load Previous Position"), LoadPrevPositionProc},
586 {N_("Reload Same Position"), ReloadPositionProc},
587 {N_("Save Position"), SavePositionProc},
588 {"----", NothingProc},
589 {N_("Copy Position"), CopyPositionProc},
590 {N_("Paste Position"), PastePositionProc},
591 {"----", NothingProc},
592 {N_("Mail Move"), MailMoveProc},
593 {N_("Reload CMail Message"), ReloadCmailMsgProc},
594 {"----", NothingProc},
595 {N_("Exit"), QuitProc},
599 MenuItem modeMenu[] = {
600 {N_("Machine White"), MachineWhiteProc},
601 {N_("Machine Black"), MachineBlackProc},
602 {N_("Two Machines"), TwoMachinesProc},
603 {N_("Analysis Mode"), AnalyzeModeProc},
604 {N_("Analyze File"), AnalyzeFileProc },
605 {N_("ICS Client"), IcsClientProc},
606 {N_("Edit Game"), EditGameProc},
607 {N_("Edit Position"), EditPositionProc},
608 {N_("Training"), TrainingProc},
609 {"----", NothingProc},
610 {N_("Show Engine Output"), EngineOutputProc},
611 {N_("Show Evaluation Graph"), EvalGraphProc},
612 {N_("Show Game List"), ShowGameListProc},
613 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
614 {"----", NothingProc},
615 {N_("Edit Tags"), EditTagsProc},
616 {N_("Edit Comment"), EditCommentProc},
617 {N_("ICS Input Box"), IcsInputBoxProc},
618 {N_("Pause"), PauseProc},
622 MenuItem actionMenu[] = {
623 {N_("Accept"), AcceptProc},
624 {N_("Decline"), DeclineProc},
625 {N_("Rematch"), RematchProc},
626 {"----", NothingProc},
627 {N_("Call Flag"), CallFlagProc},
628 {N_("Draw"), DrawProc},
629 {N_("Adjourn"), AdjournProc},
630 {N_("Abort"), AbortProc},
631 {N_("Resign"), ResignProc},
632 {"----", NothingProc},
633 {N_("Stop Observing"), StopObservingProc},
634 {N_("Stop Examining"), StopExaminingProc},
635 {"----", NothingProc},
636 {N_("Adjudicate to White"), AdjuWhiteProc},
637 {N_("Adjudicate to Black"), AdjuBlackProc},
638 {N_("Adjudicate Draw"), AdjuDrawProc},
642 MenuItem stepMenu[] = {
643 {N_("Backward"), BackwardProc},
644 {N_("Forward"), ForwardProc},
645 {N_("Back to Start"), ToStartProc},
646 {N_("Forward to End"), ToEndProc},
647 {N_("Revert"), RevertProc},
648 {N_("Truncate Game"), TruncateGameProc},
649 {"----", NothingProc},
650 {N_("Move Now"), MoveNowProc},
651 {N_("Retract Move"), RetractMoveProc},
655 MenuItem optionsMenu[] = {
656 {N_("Flip View"), FlipViewProc},
657 {"----", NothingProc},
658 {N_("Adjudications ..."), EngineMenuProc},
659 {N_("General Settings ..."), UciMenuProc},
660 {N_("Engine #1 Settings ..."), FirstSettingsProc},
661 {N_("Engine #2 Settings ..."), SecondSettingsProc},
662 {N_("Time Control ..."), TimeControlProc},
663 {"----", NothingProc},
664 {N_("Always Queen"), AlwaysQueenProc},
665 {N_("Animate Dragging"), AnimateDraggingProc},
666 {N_("Animate Moving"), AnimateMovingProc},
667 {N_("Auto Comment"), AutocommProc},
668 {N_("Auto Flag"), AutoflagProc},
669 {N_("Auto Flip View"), AutoflipProc},
670 {N_("Auto Observe"), AutobsProc},
671 {N_("Auto Raise Board"), AutoraiseProc},
672 {N_("Auto Save"), AutosaveProc},
673 {N_("Blindfold"), BlindfoldProc},
674 {N_("Flash Moves"), FlashMovesProc},
675 {N_("Get Move List"), GetMoveListProc},
677 {N_("Highlight Dragging"), HighlightDraggingProc},
679 {N_("Highlight Last Move"), HighlightLastMoveProc},
680 {N_("Move Sound"), MoveSoundProc},
681 {N_("ICS Alarm"), IcsAlarmProc},
682 {N_("Old Save Style"), OldSaveStyleProc},
683 {N_("Periodic Updates"), PeriodicUpdatesProc},
684 {N_("Ponder Next Move"), PonderNextMoveProc},
685 {N_("Popup Exit Message"), PopupExitMessageProc},
686 {N_("Popup Move Errors"), PopupMoveErrorsProc},
687 {N_("Premove"), PremoveProc},
688 {N_("Quiet Play"), QuietPlayProc},
689 {N_("Show Coords"), ShowCoordsProc},
690 {N_("Hide Thinking"), HideThinkingProc},
691 {N_("Test Legality"), TestLegalityProc},
692 {"----", NothingProc},
693 {N_("Save Settings Now"), SaveSettingsProc},
694 {N_("Save Settings on Exit"), SaveOnExitProc},
698 MenuItem helpMenu[] = {
699 {N_("Info XBoard"), InfoProc},
700 {N_("Man XBoard"), ManProc},
701 {"----", NothingProc},
702 {N_("Hint"), HintProc},
703 {N_("Book"), BookProc},
704 {"----", NothingProc},
705 {N_("About XBoard"), AboutProc},
710 {N_("File"), fileMenu},
711 {N_("Mode"), modeMenu},
712 {N_("Action"), actionMenu},
713 {N_("Step"), stepMenu},
714 {N_("Options"), optionsMenu},
715 {N_("Help"), helpMenu},
719 #define PAUSE_BUTTON N_("P")
720 MenuItem buttonBar[] = {
723 {PAUSE_BUTTON, PauseProc},
729 #define PIECE_MENU_SIZE 18
730 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
731 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
732 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
733 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
734 N_("Empty square"), N_("Clear board") },
735 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
736 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
737 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
738 N_("Empty square"), N_("Clear board") }
740 /* must be in same order as PieceMenuStrings! */
741 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
742 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
743 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
744 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
745 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
746 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
747 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
748 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
749 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
752 #define DROP_MENU_SIZE 6
753 String dropMenuStrings[DROP_MENU_SIZE] = {
754 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
756 /* must be in same order as PieceMenuStrings! */
757 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
758 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
759 WhiteRook, WhiteQueen
767 DropMenuEnables dmEnables[] = {
785 { XtNborderWidth, 0 },
786 { XtNdefaultDistance, 0 },
790 { XtNborderWidth, 0 },
791 { XtNresizable, (XtArgVal) True },
795 { XtNborderWidth, 0 },
801 { XtNjustify, (XtArgVal) XtJustifyRight },
802 { XtNlabel, (XtArgVal) "..." },
803 { XtNresizable, (XtArgVal) True },
804 { XtNresize, (XtArgVal) False }
807 Arg messageArgs[] = {
808 { XtNjustify, (XtArgVal) XtJustifyLeft },
809 { XtNlabel, (XtArgVal) "..." },
810 { XtNresizable, (XtArgVal) True },
811 { XtNresize, (XtArgVal) False }
815 { XtNborderWidth, 0 },
816 { XtNjustify, (XtArgVal) XtJustifyLeft }
819 XtResource clientResources[] = {
820 { "flashCount", "flashCount", XtRInt, sizeof(int),
821 XtOffset(AppDataPtr, flashCount), XtRImmediate,
822 (XtPointer) FLASH_COUNT },
825 XrmOptionDescRec shellOptions[] = {
826 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
827 { "-flash", "flashCount", XrmoptionNoArg, "3" },
828 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
831 XtActionsRec boardActions[] = {
832 { "DrawPosition", DrawPositionProc },
833 { "HandleUserMove", HandleUserMove },
834 { "AnimateUserMove", AnimateUserMove },
835 { "FileNameAction", FileNameAction },
836 { "AskQuestionProc", AskQuestionProc },
837 { "AskQuestionReplyAction", AskQuestionReplyAction },
838 { "PieceMenuPopup", PieceMenuPopup },
839 { "WhiteClock", WhiteClock },
840 { "BlackClock", BlackClock },
841 { "Iconify", Iconify },
842 { "ResetProc", ResetProc },
843 { "LoadGameProc", LoadGameProc },
844 { "LoadNextGameProc", LoadNextGameProc },
845 { "LoadPrevGameProc", LoadPrevGameProc },
846 { "LoadSelectedProc", LoadSelectedProc },
847 { "ReloadGameProc", ReloadGameProc },
848 { "LoadPositionProc", LoadPositionProc },
849 { "LoadNextPositionProc", LoadNextPositionProc },
850 { "LoadPrevPositionProc", LoadPrevPositionProc },
851 { "ReloadPositionProc", ReloadPositionProc },
852 { "CopyPositionProc", CopyPositionProc },
853 { "PastePositionProc", PastePositionProc },
854 { "CopyGameProc", CopyGameProc },
855 { "PasteGameProc", PasteGameProc },
856 { "SaveGameProc", SaveGameProc },
857 { "SavePositionProc", SavePositionProc },
858 { "MailMoveProc", MailMoveProc },
859 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
860 { "QuitProc", QuitProc },
861 { "MachineWhiteProc", MachineWhiteProc },
862 { "MachineBlackProc", MachineBlackProc },
863 { "AnalysisModeProc", AnalyzeModeProc },
864 { "AnalyzeFileProc", AnalyzeFileProc },
865 { "TwoMachinesProc", TwoMachinesProc },
866 { "IcsClientProc", IcsClientProc },
867 { "EditGameProc", EditGameProc },
868 { "EditPositionProc", EditPositionProc },
869 { "TrainingProc", EditPositionProc },
870 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
871 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
872 { "ShowGameListProc", ShowGameListProc },
873 { "ShowMoveListProc", HistoryShowProc},
874 { "EditTagsProc", EditCommentProc },
875 { "EditCommentProc", EditCommentProc },
876 { "IcsAlarmProc", IcsAlarmProc },
877 { "IcsInputBoxProc", IcsInputBoxProc },
878 { "PauseProc", PauseProc },
879 { "AcceptProc", AcceptProc },
880 { "DeclineProc", DeclineProc },
881 { "RematchProc", RematchProc },
882 { "CallFlagProc", CallFlagProc },
883 { "DrawProc", DrawProc },
884 { "AdjournProc", AdjournProc },
885 { "AbortProc", AbortProc },
886 { "ResignProc", ResignProc },
887 { "AdjuWhiteProc", AdjuWhiteProc },
888 { "AdjuBlackProc", AdjuBlackProc },
889 { "AdjuDrawProc", AdjuDrawProc },
890 { "EnterKeyProc", EnterKeyProc },
891 { "StopObservingProc", StopObservingProc },
892 { "StopExaminingProc", StopExaminingProc },
893 { "BackwardProc", BackwardProc },
894 { "ForwardProc", ForwardProc },
895 { "ToStartProc", ToStartProc },
896 { "ToEndProc", ToEndProc },
897 { "RevertProc", RevertProc },
898 { "TruncateGameProc", TruncateGameProc },
899 { "MoveNowProc", MoveNowProc },
900 { "RetractMoveProc", RetractMoveProc },
901 { "AlwaysQueenProc", AlwaysQueenProc },
902 { "AnimateDraggingProc", AnimateDraggingProc },
903 { "AnimateMovingProc", AnimateMovingProc },
904 { "AutoflagProc", AutoflagProc },
905 { "AutoflipProc", AutoflipProc },
906 { "AutobsProc", AutobsProc },
907 { "AutoraiseProc", AutoraiseProc },
908 { "AutosaveProc", AutosaveProc },
909 { "BlindfoldProc", BlindfoldProc },
910 { "FlashMovesProc", FlashMovesProc },
911 { "FlipViewProc", FlipViewProc },
912 { "GetMoveListProc", GetMoveListProc },
914 { "HighlightDraggingProc", HighlightDraggingProc },
916 { "HighlightLastMoveProc", HighlightLastMoveProc },
917 { "IcsAlarmProc", IcsAlarmProc },
918 { "MoveSoundProc", MoveSoundProc },
919 { "OldSaveStyleProc", OldSaveStyleProc },
920 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
921 { "PonderNextMoveProc", PonderNextMoveProc },
922 { "PopupExitMessageProc", PopupExitMessageProc },
923 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
924 { "PremoveProc", PremoveProc },
925 { "QuietPlayProc", QuietPlayProc },
926 { "ShowCoordsProc", ShowCoordsProc },
927 { "ShowThinkingProc", ShowThinkingProc },
928 { "HideThinkingProc", HideThinkingProc },
929 { "TestLegalityProc", TestLegalityProc },
930 { "SaveSettingsProc", SaveSettingsProc },
931 { "SaveOnExitProc", SaveOnExitProc },
932 { "InfoProc", InfoProc },
933 { "ManProc", ManProc },
934 { "HintProc", HintProc },
935 { "BookProc", BookProc },
936 { "AboutGameProc", AboutGameProc },
937 { "AboutProc", AboutProc },
938 { "DebugProc", DebugProc },
939 { "NothingProc", NothingProc },
940 { "CommentPopDown", (XtActionProc) CommentPopDown },
941 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
942 { "TagsPopDown", (XtActionProc) TagsPopDown },
943 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
944 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
945 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
946 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
947 { "GameListPopDown", (XtActionProc) GameListPopDown },
948 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
949 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
950 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
951 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
952 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
953 { "EnginePopDown", (XtActionProc) EnginePopDown },
954 { "UciPopDown", (XtActionProc) UciPopDown },
955 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
956 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
957 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
958 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
961 char globalTranslations[] =
962 ":<Key>R: ResignProc() \n \
963 :<Key>r: ResetProc() \n \
964 :<Key>g: LoadGameProc() \n \
965 :<Key>N: LoadNextGameProc() \n \
966 :<Key>P: LoadPrevGameProc() \n \
967 :<Key>Q: QuitProc() \n \
968 :<Key>F: ToEndProc() \n \
969 :<Key>f: ForwardProc() \n \
970 :<Key>B: ToStartProc() \n \
971 :<Key>b: BackwardProc() \n \
972 :<Key>p: PauseProc() \n \
973 :<Key>d: DrawProc() \n \
974 :<Key>t: CallFlagProc() \n \
975 :<Key>i: Iconify() \n \
976 :<Key>c: Iconify() \n \
977 :<Key>v: FlipViewProc() \n \
978 <KeyDown>Control_L: BackwardProc() \n \
979 <KeyUp>Control_L: ForwardProc() \n \
980 <KeyDown>Control_R: BackwardProc() \n \
981 <KeyUp>Control_R: ForwardProc() \n \
982 Shift<Key>1: AskQuestionProc(\"Direct command\",\
983 \"Send to chess program:\",,1) \n \
984 Shift<Key>2: AskQuestionProc(\"Direct command\",\
985 \"Send to second chess program:\",,2) \n";
987 char boardTranslations[] =
988 "<Btn1Down>: HandleUserMove() \n \
989 <Btn1Up>: HandleUserMove() \n \
990 <Btn1Motion>: AnimateUserMove() \n \
991 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
992 PieceMenuPopup(menuB) \n \
993 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
994 PieceMenuPopup(menuW) \n \
995 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
996 PieceMenuPopup(menuW) \n \
997 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
998 PieceMenuPopup(menuB) \n";
1000 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1001 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1003 char ICSInputTranslations[] =
1004 "<Key>Return: EnterKeyProc() \n";
1006 String xboardResources[] = {
1007 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1008 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1009 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1014 /* Max possible square size */
1015 #define MAXSQSIZE 256
1017 static int xpm_avail[MAXSQSIZE];
1019 #ifdef HAVE_DIR_STRUCT
1021 /* Extract piece size from filename */
1023 xpm_getsize(name, len, ext)
1034 if ((p=strchr(name, '.')) == NULL ||
1035 StrCaseCmp(p+1, ext) != 0)
1041 while (*p && isdigit(*p))
1048 /* Setup xpm_avail */
1050 xpm_getavail(dirname, ext)
1058 for (i=0; i<MAXSQSIZE; ++i)
1061 if (appData.debugMode)
1062 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1064 dir = opendir(dirname);
1067 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1068 programName, dirname);
1072 while ((ent=readdir(dir)) != NULL) {
1073 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1074 if (i > 0 && i < MAXSQSIZE)
1084 xpm_print_avail(fp, ext)
1090 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1091 for (i=1; i<MAXSQSIZE; ++i) {
1097 /* Return XPM piecesize closest to size */
1099 xpm_closest_to(dirname, size, ext)
1105 int sm_diff = MAXSQSIZE;
1109 xpm_getavail(dirname, ext);
1111 if (appData.debugMode)
1112 xpm_print_avail(stderr, ext);
1114 for (i=1; i<MAXSQSIZE; ++i) {
1117 diff = (diff<0) ? -diff : diff;
1118 if (diff < sm_diff) {
1126 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1132 #else /* !HAVE_DIR_STRUCT */
1133 /* If we are on a system without a DIR struct, we can't
1134 read the directory, so we can't collect a list of
1135 filenames, etc., so we can't do any size-fitting. */
1137 xpm_closest_to(dirname, size, ext)
1142 fprintf(stderr, _("\
1143 Warning: No DIR structure found on this system --\n\
1144 Unable to autosize for XPM/XIM pieces.\n\
1145 Please report this error to frankm@hiwaay.net.\n\
1146 Include system type & operating system in message.\n"));
1149 #endif /* HAVE_DIR_STRUCT */
1151 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1152 "magenta", "cyan", "white" };
1156 TextColors textColors[(int)NColorClasses];
1158 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1160 parse_color(str, which)
1164 char *p, buf[100], *d;
1167 if (strlen(str) > 99) /* watch bounds on buf */
1172 for (i=0; i<which; ++i) {
1179 /* Could be looking at something like:
1181 .. in which case we want to stop on a comma also */
1182 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1186 return -1; /* Use default for empty field */
1189 if (which == 2 || isdigit(*p))
1192 while (*p && isalpha(*p))
1197 for (i=0; i<8; ++i) {
1198 if (!StrCaseCmp(buf, cnames[i]))
1199 return which? (i+40) : (i+30);
1201 if (!StrCaseCmp(buf, "default")) return -1;
1203 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1208 parse_cpair(cc, str)
1212 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1213 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1218 /* bg and attr are optional */
1219 textColors[(int)cc].bg = parse_color(str, 1);
1220 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1221 textColors[(int)cc].attr = 0;
1227 /* Arrange to catch delete-window events */
1228 Atom wm_delete_window;
1230 CatchDeleteWindow(Widget w, String procname)
1233 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1234 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1235 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1242 XtSetArg(args[0], XtNiconic, False);
1243 XtSetValues(shellWidget, args, 1);
1245 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1248 //---------------------------------------------------------------------------------------------------------
1249 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1252 #define CW_USEDEFAULT (1<<31)
1253 #define ICS_TEXT_MENU_SIZE 90
1254 #define DEBUG_FILE "xboard.debug"
1255 #define SetCurrentDirectory chdir
1256 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1260 // these two must some day move to frontend.h, when they are implemented
1261 Boolean MoveHistoryIsUp();
1262 Boolean GameListIsUp();
1264 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1267 // front-end part of option handling
1269 // [HGM] This platform-dependent table provides the location for storing the color info
1270 extern char *crWhite, * crBlack;
1274 &appData.whitePieceColor,
1275 &appData.blackPieceColor,
1276 &appData.lightSquareColor,
1277 &appData.darkSquareColor,
1278 &appData.highlightSquareColor,
1279 &appData.premoveHighlightColor,
1292 ParseFont(char *name, int number)
1293 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1295 case 0: // CLOCK_FONT
1296 appData.clockFont = strdup(name);
1298 case 1: // MESSAGE_FONT
1299 appData.font = strdup(name);
1301 case 2: // COORD_FONT
1302 appData.coordFont = strdup(name);
1311 { // only 2 fonts currently
1312 appData.clockFont = CLOCK_FONT_NAME;
1313 appData.coordFont = COORD_FONT_NAME;
1314 appData.font = DEFAULT_FONT_NAME;
1319 { // no-op, until we identify the code for this already in XBoard and move it here
1323 ParseColor(int n, char *name)
1324 { // in XBoard, just copy the color-name string
1325 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1329 ParseTextAttribs(ColorClass cc, char *s)
1331 (&appData.colorShout)[cc] = strdup(s);
1335 ParseBoardSize(void *addr, char *name)
1337 appData.boardSize = strdup(name);
1342 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1346 SetCommPortDefaults()
1347 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1350 // [HGM] args: these three cases taken out to stay in front-end
1352 SaveFontArg(FILE *f, ArgDescriptor *ad)
1355 switch((int)ad->argLoc) {
1356 case 0: // CLOCK_FONT
1357 name = appData.clockFont;
1359 case 1: // MESSAGE_FONT
1360 name = appData.font;
1362 case 2: // COORD_FONT
1363 name = appData.coordFont;
1368 // Do not save fonts for now, as the saved font would be board-size specific
1369 // and not suitable for a re-start at another board size
1370 // fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, name);
1375 { // nothing to do, as the sounds are at all times represented by their text-string names already
1379 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1380 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1381 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1385 SaveColor(FILE *f, ArgDescriptor *ad)
1386 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1387 if(colorVariable[(int)ad->argLoc])
1388 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1392 SaveBoardSize(FILE *f, char *name, void *addr)
1393 { // wrapper to shield back-end from BoardSize & sizeInfo
1394 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1398 ParseCommPortSettings(char *s)
1399 { // no such option in XBoard (yet)
1402 extern Widget engineOutputShell;
1403 extern Widget tagsShell, editTagsShell;
1405 GetActualPlacement(Widget wg, WindowPlacement *wp)
1415 XtSetArg(args[i], XtNx, &x); i++;
1416 XtSetArg(args[i], XtNy, &y); i++;
1417 XtSetArg(args[i], XtNwidth, &w); i++;
1418 XtSetArg(args[i], XtNheight, &h); i++;
1419 XtGetValues(wg, args, i);
1428 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1429 // In XBoard this will have to wait until awareness of window parameters is implemented
1430 GetActualPlacement(shellWidget, &wpMain);
1431 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1432 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1433 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1434 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1435 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1436 else GetActualPlacement(editShell, &wpComment);
1437 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1438 else GetActualPlacement(editTagsShell, &wpTags);
1442 PrintCommPortSettings(FILE *f, char *name)
1443 { // This option does not exist in XBoard
1447 MySearchPath(char *installDir, char *name, char *fullname)
1448 { // just append installDir and name. Perhaps ExpandPath should be used here?
1449 name = ExpandPathName(name);
1450 if(name && name[0] == '/') strcpy(fullname, name); else {
1451 sprintf(fullname, "%s%c%s", installDir, '/', name);
1457 MyGetFullPathName(char *name, char *fullname)
1458 { // should use ExpandPath?
1459 name = ExpandPathName(name);
1460 strcpy(fullname, name);
1465 EnsureOnScreen(int *x, int *y, int minX, int minY)
1472 { // [HGM] args: allows testing if main window is realized from back-end
1473 return xBoardWindow != 0;
1477 PopUpStartupDialog()
1478 { // start menu not implemented in XBoard
1481 ConvertToLine(int argc, char **argv)
1483 static char line[128*1024], buf[1024];
1487 for(i=1; i<argc; i++) {
1488 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1489 && argv[i][0] != '{' )
1490 sprintf(buf, "{%s} ", argv[i]);
1491 else sprintf(buf, "%s ", argv[i]);
1494 line[strlen(line)-1] = NULLCHAR;
1498 //--------------------------------------------------------------------------------------------
1501 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1503 #define BoardSize int
1504 void InitDrawingSizes(BoardSize boardSize, int flags)
1505 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1506 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1508 XtGeometryResult gres;
1511 if(!formWidget) return;
1514 * Enable shell resizing.
1516 shellArgs[0].value = (XtArgVal) &w;
1517 shellArgs[1].value = (XtArgVal) &h;
1518 XtGetValues(shellWidget, shellArgs, 2);
1520 shellArgs[4].value = 2*w; shellArgs[2].value = 10;
1521 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1522 XtSetValues(shellWidget, &shellArgs[2], 4);
1524 XtSetArg(args[0], XtNdefaultDistance, &sep);
1525 XtGetValues(formWidget, args, 1);
1527 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1528 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1531 XtSetArg(args[0], XtNwidth, boardWidth);
1532 XtSetArg(args[1], XtNheight, boardHeight);
1533 XtSetValues(boardWidget, args, 2);
1535 timerWidth = (boardWidth - sep) / 2;
1536 XtSetArg(args[0], XtNwidth, timerWidth);
1537 XtSetValues(whiteTimerWidget, args, 1);
1538 XtSetValues(blackTimerWidget, args, 1);
1540 XawFormDoLayout(formWidget, False);
1542 if (appData.titleInWindow) {
1544 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1545 XtSetArg(args[i], XtNheight, &h); i++;
1546 XtGetValues(titleWidget, args, i);
1548 w = boardWidth - 2*bor;
1550 XtSetArg(args[0], XtNwidth, &w);
1551 XtGetValues(menuBarWidget, args, 1);
1552 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1555 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1556 if (gres != XtGeometryYes && appData.debugMode) {
1558 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1559 programName, gres, w, h, wr, hr);
1563 XawFormDoLayout(formWidget, True);
1566 * Inhibit shell resizing.
1568 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW;
1569 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1570 shellArgs[4].value = shellArgs[2].value = w;
1571 shellArgs[5].value = shellArgs[3].value = h;
1572 XtSetValues(shellWidget, &shellArgs[0], 6);
1574 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1577 for(i=0; i<4; i++) {
1579 for(p=0; p<=(int)WhiteKing; p++)
1580 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1581 if(gameInfo.variant == VariantShogi) {
1582 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1583 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1584 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1585 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1586 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1589 if(gameInfo.variant == VariantGothic) {
1590 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1594 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1595 for(p=0; p<=(int)WhiteKing; p++)
1596 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1597 if(gameInfo.variant == VariantShogi) {
1598 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1599 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1600 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1601 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1602 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1605 if(gameInfo.variant == VariantGothic) {
1606 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1612 for(i=0; i<2; i++) {
1614 for(p=0; p<=(int)WhiteKing; p++)
1615 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1616 if(gameInfo.variant == VariantShogi) {
1617 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1618 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1619 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1620 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1621 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1624 if(gameInfo.variant == VariantGothic) {
1625 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1636 void EscapeExpand(char *p, char *q)
1637 { // [HGM] initstring: routine to shape up string arguments
1638 while(*p++ = *q++) if(p[-1] == '\\')
1640 case 'n': p[-1] = '\n'; break;
1641 case 'r': p[-1] = '\r'; break;
1642 case 't': p[-1] = '\t'; break;
1643 case '\\': p[-1] = '\\'; break;
1644 case 0: *p = 0; return;
1645 default: p[-1] = q[-1]; break;
1654 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1655 XSetWindowAttributes window_attributes;
1657 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1658 XrmValue vFrom, vTo;
1659 XtGeometryResult gres;
1662 int forceMono = False;
1664 srandom(time(0)); // [HGM] book: make random truly random
1666 setbuf(stdout, NULL);
1667 setbuf(stderr, NULL);
1670 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1671 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1675 programName = strrchr(argv[0], '/');
1676 if (programName == NULL)
1677 programName = argv[0];
1682 XtSetLanguageProc(NULL, NULL, NULL);
1683 bindtextdomain(PACKAGE, LOCALEDIR);
1684 textdomain(PACKAGE);
1688 XtAppInitialize(&appContext, "XBoard", shellOptions,
1689 XtNumber(shellOptions),
1690 &argc, argv, xboardResources, NULL, 0);
1691 appData.boardSize = "";
1692 InitAppData(ConvertToLine(argc, argv));
1694 if (p == NULL) p = "/tmp";
1695 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1696 gameCopyFilename = (char*) malloc(i);
1697 gamePasteFilename = (char*) malloc(i);
1698 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1699 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1701 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1702 clientResources, XtNumber(clientResources),
1705 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1706 static char buf[MSG_SIZ];
1707 EscapeExpand(buf, appData.initString);
1708 appData.initString = strdup(buf);
1709 EscapeExpand(buf, appData.secondInitString);
1710 appData.secondInitString = strdup(buf);
1711 EscapeExpand(buf, appData.firstComputerString);
1712 appData.firstComputerString = strdup(buf);
1713 EscapeExpand(buf, appData.secondComputerString);
1714 appData.secondComputerString = strdup(buf);
1717 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1720 if (chdir(chessDir) != 0) {
1721 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1727 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1728 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1729 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1730 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1733 setbuf(debugFP, NULL);
1736 /* [HGM,HR] make sure board size is acceptable */
1737 if(appData.NrFiles > BOARD_FILES ||
1738 appData.NrRanks > BOARD_RANKS )
1739 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1742 /* This feature does not work; animation needs a rewrite */
1743 appData.highlightDragging = FALSE;
1747 xDisplay = XtDisplay(shellWidget);
1748 xScreen = DefaultScreen(xDisplay);
1749 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1751 gameInfo.variant = StringToVariant(appData.variant);
1752 InitPosition(FALSE);
1755 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1757 if (isdigit(appData.boardSize[0])) {
1758 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1759 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1760 &fontPxlSize, &smallLayout, &tinyLayout);
1762 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1763 programName, appData.boardSize);
1767 /* Find some defaults; use the nearest known size */
1768 SizeDefaults *szd, *nearest;
1769 int distance = 99999;
1770 nearest = szd = sizeDefaults;
1771 while (szd->name != NULL) {
1772 if (abs(szd->squareSize - squareSize) < distance) {
1774 distance = abs(szd->squareSize - squareSize);
1775 if (distance == 0) break;
1779 if (i < 2) lineGap = nearest->lineGap;
1780 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1781 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1782 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1783 if (i < 6) smallLayout = nearest->smallLayout;
1784 if (i < 7) tinyLayout = nearest->tinyLayout;
1787 SizeDefaults *szd = sizeDefaults;
1788 if (*appData.boardSize == NULLCHAR) {
1789 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1790 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1793 if (szd->name == NULL) szd--;
1794 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1796 while (szd->name != NULL &&
1797 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1798 if (szd->name == NULL) {
1799 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1800 programName, appData.boardSize);
1804 squareSize = szd->squareSize;
1805 lineGap = szd->lineGap;
1806 clockFontPxlSize = szd->clockFontPxlSize;
1807 coordFontPxlSize = szd->coordFontPxlSize;
1808 fontPxlSize = szd->fontPxlSize;
1809 smallLayout = szd->smallLayout;
1810 tinyLayout = szd->tinyLayout;
1813 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1814 if (strlen(appData.pixmapDirectory) > 0) {
1815 p = ExpandPathName(appData.pixmapDirectory);
1817 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1818 appData.pixmapDirectory);
1821 if (appData.debugMode) {
1822 fprintf(stderr, _("\
1823 XBoard square size (hint): %d\n\
1824 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1826 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1827 if (appData.debugMode) {
1828 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1832 /* [HR] height treated separately (hacked) */
1833 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1834 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1835 if (appData.showJail == 1) {
1836 /* Jail on top and bottom */
1837 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1838 XtSetArg(boardArgs[2], XtNheight,
1839 boardHeight + 2*(lineGap + squareSize));
1840 } else if (appData.showJail == 2) {
1842 XtSetArg(boardArgs[1], XtNwidth,
1843 boardWidth + 2*(lineGap + squareSize));
1844 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1847 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1848 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1852 * Determine what fonts to use.
1854 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1855 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1856 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1857 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1858 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1859 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1860 appData.font = FindFont(appData.font, fontPxlSize);
1861 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1862 countFontStruct = XQueryFont(xDisplay, countFontID);
1863 // appData.font = FindFont(appData.font, fontPxlSize);
1865 xdb = XtDatabase(xDisplay);
1866 XrmPutStringResource(&xdb, "*font", appData.font);
1869 * Detect if there are not enough colors available and adapt.
1871 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1872 appData.monoMode = True;
1875 if (!appData.monoMode) {
1876 vFrom.addr = (caddr_t) appData.lightSquareColor;
1877 vFrom.size = strlen(appData.lightSquareColor);
1878 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1879 if (vTo.addr == NULL) {
1880 appData.monoMode = True;
1883 lightSquareColor = *(Pixel *) vTo.addr;
1886 if (!appData.monoMode) {
1887 vFrom.addr = (caddr_t) appData.darkSquareColor;
1888 vFrom.size = strlen(appData.darkSquareColor);
1889 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1890 if (vTo.addr == NULL) {
1891 appData.monoMode = True;
1894 darkSquareColor = *(Pixel *) vTo.addr;
1897 if (!appData.monoMode) {
1898 vFrom.addr = (caddr_t) appData.whitePieceColor;
1899 vFrom.size = strlen(appData.whitePieceColor);
1900 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1901 if (vTo.addr == NULL) {
1902 appData.monoMode = True;
1905 whitePieceColor = *(Pixel *) vTo.addr;
1908 if (!appData.monoMode) {
1909 vFrom.addr = (caddr_t) appData.blackPieceColor;
1910 vFrom.size = strlen(appData.blackPieceColor);
1911 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1912 if (vTo.addr == NULL) {
1913 appData.monoMode = True;
1916 blackPieceColor = *(Pixel *) vTo.addr;
1920 if (!appData.monoMode) {
1921 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1922 vFrom.size = strlen(appData.highlightSquareColor);
1923 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1924 if (vTo.addr == NULL) {
1925 appData.monoMode = True;
1928 highlightSquareColor = *(Pixel *) vTo.addr;
1932 if (!appData.monoMode) {
1933 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1934 vFrom.size = strlen(appData.premoveHighlightColor);
1935 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1936 if (vTo.addr == NULL) {
1937 appData.monoMode = True;
1940 premoveHighlightColor = *(Pixel *) vTo.addr;
1945 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1948 if (appData.bitmapDirectory == NULL ||
1949 appData.bitmapDirectory[0] == NULLCHAR)
1950 appData.bitmapDirectory = DEF_BITMAP_DIR;
1953 if (appData.lowTimeWarning && !appData.monoMode) {
1954 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
1955 vFrom.size = strlen(appData.lowTimeWarningColor);
1956 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1957 if (vTo.addr == NULL)
1958 appData.monoMode = True;
1960 lowTimeWarningColor = *(Pixel *) vTo.addr;
1963 if (appData.monoMode && appData.debugMode) {
1964 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1965 (unsigned long) XWhitePixel(xDisplay, xScreen),
1966 (unsigned long) XBlackPixel(xDisplay, xScreen));
1969 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1970 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1971 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1972 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1973 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1974 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1975 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1976 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1977 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1978 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1980 if (appData.colorize) {
1982 _("%s: can't parse color names; disabling colorization\n"),
1985 appData.colorize = FALSE;
1987 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
1988 textColors[ColorNone].attr = 0;
1990 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
1996 layoutName = "tinyLayout";
1997 } else if (smallLayout) {
1998 layoutName = "smallLayout";
2000 layoutName = "normalLayout";
2002 /* Outer layoutWidget is there only to provide a name for use in
2003 resources that depend on the layout style */
2005 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2006 layoutArgs, XtNumber(layoutArgs));
2008 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2009 formArgs, XtNumber(formArgs));
2010 XtSetArg(args[0], XtNdefaultDistance, &sep);
2011 XtGetValues(formWidget, args, 1);
2014 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2015 XtSetArg(args[0], XtNtop, XtChainTop);
2016 XtSetArg(args[1], XtNbottom, XtChainTop);
2017 XtSetArg(args[2], XtNright, XtChainLeft);
2018 XtSetValues(menuBarWidget, args, 3);
2020 widgetList[j++] = whiteTimerWidget =
2021 XtCreateWidget("whiteTime", labelWidgetClass,
2022 formWidget, timerArgs, XtNumber(timerArgs));
2023 XtSetArg(args[0], XtNfont, clockFontStruct);
2024 XtSetArg(args[1], XtNtop, XtChainTop);
2025 XtSetArg(args[2], XtNbottom, XtChainTop);
2026 XtSetValues(whiteTimerWidget, args, 3);
2028 widgetList[j++] = blackTimerWidget =
2029 XtCreateWidget("blackTime", labelWidgetClass,
2030 formWidget, timerArgs, XtNumber(timerArgs));
2031 XtSetArg(args[0], XtNfont, clockFontStruct);
2032 XtSetArg(args[1], XtNtop, XtChainTop);
2033 XtSetArg(args[2], XtNbottom, XtChainTop);
2034 XtSetValues(blackTimerWidget, args, 3);
2036 if (appData.titleInWindow) {
2037 widgetList[j++] = titleWidget =
2038 XtCreateWidget("title", labelWidgetClass, formWidget,
2039 titleArgs, XtNumber(titleArgs));
2040 XtSetArg(args[0], XtNtop, XtChainTop);
2041 XtSetArg(args[1], XtNbottom, XtChainTop);
2042 XtSetValues(titleWidget, args, 2);
2045 if (appData.showButtonBar) {
2046 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2047 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2048 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2049 XtSetArg(args[2], XtNtop, XtChainTop);
2050 XtSetArg(args[3], XtNbottom, XtChainTop);
2051 XtSetValues(buttonBarWidget, args, 4);
2054 widgetList[j++] = messageWidget =
2055 XtCreateWidget("message", labelWidgetClass, formWidget,
2056 messageArgs, XtNumber(messageArgs));
2057 XtSetArg(args[0], XtNtop, XtChainTop);
2058 XtSetArg(args[1], XtNbottom, XtChainTop);
2059 XtSetValues(messageWidget, args, 2);
2061 widgetList[j++] = boardWidget =
2062 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2063 XtNumber(boardArgs));
2065 XtManageChildren(widgetList, j);
2067 timerWidth = (boardWidth - sep) / 2;
2068 XtSetArg(args[0], XtNwidth, timerWidth);
2069 XtSetValues(whiteTimerWidget, args, 1);
2070 XtSetValues(blackTimerWidget, args, 1);
2072 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2073 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2074 XtGetValues(whiteTimerWidget, args, 2);
2076 if (appData.showButtonBar) {
2077 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2078 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2079 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2083 * formWidget uses these constraints but they are stored
2087 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2088 XtSetValues(menuBarWidget, args, i);
2089 if (appData.titleInWindow) {
2092 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2093 XtSetValues(whiteTimerWidget, args, i);
2095 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2096 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2097 XtSetValues(blackTimerWidget, args, i);
2099 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2100 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2101 XtSetValues(titleWidget, args, i);
2103 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2104 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2105 XtSetValues(messageWidget, args, i);
2106 if (appData.showButtonBar) {
2108 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2109 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2110 XtSetValues(buttonBarWidget, args, i);
2114 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2115 XtSetValues(whiteTimerWidget, args, i);
2117 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2118 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2119 XtSetValues(blackTimerWidget, args, i);
2121 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2122 XtSetValues(titleWidget, args, i);
2124 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2125 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2126 XtSetValues(messageWidget, args, i);
2127 if (appData.showButtonBar) {
2129 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2130 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2131 XtSetValues(buttonBarWidget, args, i);
2136 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2137 XtSetValues(whiteTimerWidget, args, i);
2139 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2140 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2141 XtSetValues(blackTimerWidget, args, i);
2143 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2144 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2145 XtSetValues(messageWidget, args, i);
2146 if (appData.showButtonBar) {
2148 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2149 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2150 XtSetValues(buttonBarWidget, args, i);
2154 XtSetArg(args[0], XtNfromVert, messageWidget);
2155 XtSetArg(args[1], XtNtop, XtChainTop);
2156 XtSetArg(args[2], XtNbottom, XtChainBottom);
2157 XtSetArg(args[3], XtNleft, XtChainLeft);
2158 XtSetArg(args[4], XtNright, XtChainRight);
2159 XtSetValues(boardWidget, args, 5);
2161 XtRealizeWidget(shellWidget);
2164 XtSetArg(args[0], XtNx, wpMain.x);
2165 XtSetArg(args[1], XtNy, wpMain.y);
2166 XtSetValues(shellWidget, args, 2);
2170 * Correct the width of the message and title widgets.
2171 * It is not known why some systems need the extra fudge term.
2172 * The value "2" is probably larger than needed.
2174 XawFormDoLayout(formWidget, False);
2176 #define WIDTH_FUDGE 2
2178 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2179 XtSetArg(args[i], XtNheight, &h); i++;
2180 XtGetValues(messageWidget, args, i);
2181 if (appData.showButtonBar) {
2183 XtSetArg(args[i], XtNwidth, &w); i++;
2184 XtGetValues(buttonBarWidget, args, i);
2185 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2187 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2190 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2191 if (gres != XtGeometryYes && appData.debugMode) {
2192 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2193 programName, gres, w, h, wr, hr);
2196 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2197 /* The size used for the child widget in layout lags one resize behind
2198 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2200 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2201 if (gres != XtGeometryYes && appData.debugMode) {
2202 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2203 programName, gres, w, h, wr, hr);
2206 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2207 XtSetArg(args[1], XtNright, XtChainRight);
2208 XtSetValues(messageWidget, args, 2);
2210 if (appData.titleInWindow) {
2212 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2213 XtSetArg(args[i], XtNheight, &h); i++;
2214 XtGetValues(titleWidget, args, i);
2216 w = boardWidth - 2*bor;
2218 XtSetArg(args[0], XtNwidth, &w);
2219 XtGetValues(menuBarWidget, args, 1);
2220 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2223 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2224 if (gres != XtGeometryYes && appData.debugMode) {
2226 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2227 programName, gres, w, h, wr, hr);
2230 XawFormDoLayout(formWidget, True);
2232 xBoardWindow = XtWindow(boardWidget);
2234 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2235 // not need to go into InitDrawingSizes().
2239 * Create X checkmark bitmap and initialize option menu checks.
2241 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2242 checkmark_bits, checkmark_width, checkmark_height);
2243 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2244 if (appData.alwaysPromoteToQueen) {
2245 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2248 if (appData.animateDragging) {
2249 XtSetValues(XtNameToWidget(menuBarWidget,
2250 "menuOptions.Animate Dragging"),
2253 if (appData.animate) {
2254 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2257 if (appData.autoComment) {
2258 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2261 if (appData.autoCallFlag) {
2262 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2265 if (appData.autoFlipView) {
2266 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2269 if (appData.autoObserve) {
2270 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2273 if (appData.autoRaiseBoard) {
2274 XtSetValues(XtNameToWidget(menuBarWidget,
2275 "menuOptions.Auto Raise Board"), args, 1);
2277 if (appData.autoSaveGames) {
2278 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2281 if (appData.saveGameFile[0] != NULLCHAR) {
2282 /* Can't turn this off from menu */
2283 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2285 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2289 if (appData.blindfold) {
2290 XtSetValues(XtNameToWidget(menuBarWidget,
2291 "menuOptions.Blindfold"), args, 1);
2293 if (appData.flashCount > 0) {
2294 XtSetValues(XtNameToWidget(menuBarWidget,
2295 "menuOptions.Flash Moves"),
2298 if (appData.getMoveList) {
2299 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2303 if (appData.highlightDragging) {
2304 XtSetValues(XtNameToWidget(menuBarWidget,
2305 "menuOptions.Highlight Dragging"),
2309 if (appData.highlightLastMove) {
2310 XtSetValues(XtNameToWidget(menuBarWidget,
2311 "menuOptions.Highlight Last Move"),
2314 if (appData.icsAlarm) {
2315 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2318 if (appData.ringBellAfterMoves) {
2319 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2322 if (appData.oldSaveStyle) {
2323 XtSetValues(XtNameToWidget(menuBarWidget,
2324 "menuOptions.Old Save Style"), args, 1);
2326 if (appData.periodicUpdates) {
2327 XtSetValues(XtNameToWidget(menuBarWidget,
2328 "menuOptions.Periodic Updates"), args, 1);
2330 if (appData.ponderNextMove) {
2331 XtSetValues(XtNameToWidget(menuBarWidget,
2332 "menuOptions.Ponder Next Move"), args, 1);
2334 if (appData.popupExitMessage) {
2335 XtSetValues(XtNameToWidget(menuBarWidget,
2336 "menuOptions.Popup Exit Message"), args, 1);
2338 if (appData.popupMoveErrors) {
2339 XtSetValues(XtNameToWidget(menuBarWidget,
2340 "menuOptions.Popup Move Errors"), args, 1);
2342 if (appData.premove) {
2343 XtSetValues(XtNameToWidget(menuBarWidget,
2344 "menuOptions.Premove"), args, 1);
2346 if (appData.quietPlay) {
2347 XtSetValues(XtNameToWidget(menuBarWidget,
2348 "menuOptions.Quiet Play"), args, 1);
2350 if (appData.showCoords) {
2351 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2354 if (appData.hideThinkingFromHuman) {
2355 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2358 if (appData.testLegality) {
2359 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2362 if (saveSettingsOnExit) {
2363 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2370 ReadBitmap(&wIconPixmap, "icon_white.bm",
2371 icon_white_bits, icon_white_width, icon_white_height);
2372 ReadBitmap(&bIconPixmap, "icon_black.bm",
2373 icon_black_bits, icon_black_width, icon_black_height);
2374 iconPixmap = wIconPixmap;
2376 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2377 XtSetValues(shellWidget, args, i);
2380 * Create a cursor for the board widget.
2382 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2383 XChangeWindowAttributes(xDisplay, xBoardWindow,
2384 CWCursor, &window_attributes);
2387 * Inhibit shell resizing.
2389 shellArgs[0].value = (XtArgVal) &w;
2390 shellArgs[1].value = (XtArgVal) &h;
2391 XtGetValues(shellWidget, shellArgs, 2);
2392 shellArgs[4].value = shellArgs[2].value = w;
2393 shellArgs[5].value = shellArgs[3].value = h;
2394 XtSetValues(shellWidget, &shellArgs[2], 4);
2395 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2396 marginH = h - boardHeight;
2398 CatchDeleteWindow(shellWidget, "QuitProc");
2403 if (appData.bitmapDirectory[0] != NULLCHAR) {
2410 /* Create regular pieces */
2411 if (!useImages) CreatePieces();
2416 if (appData.animate || appData.animateDragging)
2419 XtAugmentTranslations(formWidget,
2420 XtParseTranslationTable(globalTranslations));
2421 XtAugmentTranslations(boardWidget,
2422 XtParseTranslationTable(boardTranslations));
2423 XtAugmentTranslations(whiteTimerWidget,
2424 XtParseTranslationTable(whiteTranslations));
2425 XtAugmentTranslations(blackTimerWidget,
2426 XtParseTranslationTable(blackTranslations));
2428 /* Why is the following needed on some versions of X instead
2429 * of a translation? */
2430 XtAddEventHandler(boardWidget, ExposureMask, False,
2431 (XtEventHandler) EventProc, NULL);
2434 /* [AS] Restore layout */
2435 if( wpMoveHistory.visible ) {
2439 if( wpEvalGraph.visible )
2444 if( wpEngineOutput.visible ) {
2445 EngineOutputPopUp();
2450 if (errorExitStatus == -1) {
2451 if (appData.icsActive) {
2452 /* We now wait until we see "login:" from the ICS before
2453 sending the logon script (problems with timestamp otherwise) */
2454 /*ICSInitScript();*/
2455 if (appData.icsInputBox) ICSInputBoxPopUp();
2459 signal(SIGWINCH, TermSizeSigHandler);
2461 signal(SIGINT, IntSigHandler);
2462 signal(SIGTERM, IntSigHandler);
2463 if (*appData.cmailGameName != NULLCHAR) {
2464 signal(SIGUSR1, CmailSigHandler);
2467 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2470 XtAppMainLoop(appContext);
2471 if (appData.debugMode) fclose(debugFP); // [DM] debug
2478 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2479 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2481 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2482 unlink(gameCopyFilename);
2483 unlink(gamePasteFilename);
2486 RETSIGTYPE TermSizeSigHandler(int sig)
2499 CmailSigHandler(sig)
2505 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2507 /* Activate call-back function CmailSigHandlerCallBack() */
2508 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2510 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2514 CmailSigHandlerCallBack(isr, closure, message, count, error)
2522 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2524 /**** end signal code ****/
2534 f = fopen(appData.icsLogon, "r");
2540 strcat(buf, appData.icsLogon);
2541 f = fopen(buf, "r");
2545 ProcessICSInitScript(f);
2552 EditCommentPopDown();
2567 if (!menuBarWidget) return;
2568 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2570 DisplayError("menuStep.Revert", 0);
2572 XtSetSensitive(w, !grey);
2577 SetMenuEnables(enab)
2581 if (!menuBarWidget) return;
2582 while (enab->name != NULL) {
2583 w = XtNameToWidget(menuBarWidget, enab->name);
2585 DisplayError(enab->name, 0);
2587 XtSetSensitive(w, enab->value);
2593 Enables icsEnables[] = {
2594 { "menuFile.Mail Move", False },
2595 { "menuFile.Reload CMail Message", False },
2596 { "menuMode.Machine Black", False },
2597 { "menuMode.Machine White", False },
2598 { "menuMode.Analysis Mode", False },
2599 { "menuMode.Analyze File", False },
2600 { "menuMode.Two Machines", False },
2602 { "menuHelp.Hint", False },
2603 { "menuHelp.Book", False },
2604 { "menuStep.Move Now", False },
2605 { "menuOptions.Periodic Updates", False },
2606 { "menuOptions.Hide Thinking", False },
2607 { "menuOptions.Ponder Next Move", False },
2612 Enables ncpEnables[] = {
2613 { "menuFile.Mail Move", False },
2614 { "menuFile.Reload CMail Message", False },
2615 { "menuMode.Machine White", False },
2616 { "menuMode.Machine Black", False },
2617 { "menuMode.Analysis Mode", False },
2618 { "menuMode.Analyze File", False },
2619 { "menuMode.Two Machines", False },
2620 { "menuMode.ICS Client", False },
2621 { "menuMode.ICS Input Box", False },
2622 { "Action", False },
2623 { "menuStep.Revert", False },
2624 { "menuStep.Move Now", False },
2625 { "menuStep.Retract Move", False },
2626 { "menuOptions.Auto Comment", False },
2627 { "menuOptions.Auto Flag", False },
2628 { "menuOptions.Auto Flip View", False },
2629 { "menuOptions.Auto Observe", False },
2630 { "menuOptions.Auto Raise Board", False },
2631 { "menuOptions.Get Move List", False },
2632 { "menuOptions.ICS Alarm", False },
2633 { "menuOptions.Move Sound", False },
2634 { "menuOptions.Quiet Play", False },
2635 { "menuOptions.Hide Thinking", False },
2636 { "menuOptions.Periodic Updates", False },
2637 { "menuOptions.Ponder Next Move", False },
2638 { "menuHelp.Hint", False },
2639 { "menuHelp.Book", False },
2643 Enables gnuEnables[] = {
2644 { "menuMode.ICS Client", False },
2645 { "menuMode.ICS Input Box", False },
2646 { "menuAction.Accept", False },
2647 { "menuAction.Decline", False },
2648 { "menuAction.Rematch", False },
2649 { "menuAction.Adjourn", False },
2650 { "menuAction.Stop Examining", False },
2651 { "menuAction.Stop Observing", False },
2652 { "menuStep.Revert", False },
2653 { "menuOptions.Auto Comment", False },
2654 { "menuOptions.Auto Observe", False },
2655 { "menuOptions.Auto Raise Board", False },
2656 { "menuOptions.Get Move List", False },
2657 { "menuOptions.Premove", False },
2658 { "menuOptions.Quiet Play", False },
2660 /* The next two options rely on SetCmailMode being called *after* */
2661 /* SetGNUMode so that when GNU is being used to give hints these */
2662 /* menu options are still available */
2664 { "menuFile.Mail Move", False },
2665 { "menuFile.Reload CMail Message", False },
2669 Enables cmailEnables[] = {
2671 { "menuAction.Call Flag", False },
2672 { "menuAction.Draw", True },
2673 { "menuAction.Adjourn", False },
2674 { "menuAction.Abort", False },
2675 { "menuAction.Stop Observing", False },
2676 { "menuAction.Stop Examining", False },
2677 { "menuFile.Mail Move", True },
2678 { "menuFile.Reload CMail Message", True },
2682 Enables trainingOnEnables[] = {
2683 { "menuMode.Edit Comment", False },
2684 { "menuMode.Pause", False },
2685 { "menuStep.Forward", False },
2686 { "menuStep.Backward", False },
2687 { "menuStep.Forward to End", False },
2688 { "menuStep.Back to Start", False },
2689 { "menuStep.Move Now", False },
2690 { "menuStep.Truncate Game", False },
2694 Enables trainingOffEnables[] = {
2695 { "menuMode.Edit Comment", True },
2696 { "menuMode.Pause", True },
2697 { "menuStep.Forward", True },
2698 { "menuStep.Backward", True },
2699 { "menuStep.Forward to End", True },
2700 { "menuStep.Back to Start", True },
2701 { "menuStep.Move Now", True },
2702 { "menuStep.Truncate Game", True },
2706 Enables machineThinkingEnables[] = {
2707 { "menuFile.Load Game", False },
2708 { "menuFile.Load Next Game", False },
2709 { "menuFile.Load Previous Game", False },
2710 { "menuFile.Reload Same Game", False },
2711 { "menuFile.Paste Game", False },
2712 { "menuFile.Load Position", False },
2713 { "menuFile.Load Next Position", False },
2714 { "menuFile.Load Previous Position", False },
2715 { "menuFile.Reload Same Position", False },
2716 { "menuFile.Paste Position", False },
2717 { "menuMode.Machine White", False },
2718 { "menuMode.Machine Black", False },
2719 { "menuMode.Two Machines", False },
2720 { "menuStep.Retract Move", False },
2724 Enables userThinkingEnables[] = {
2725 { "menuFile.Load Game", True },
2726 { "menuFile.Load Next Game", True },
2727 { "menuFile.Load Previous Game", True },
2728 { "menuFile.Reload Same Game", True },
2729 { "menuFile.Paste Game", True },
2730 { "menuFile.Load Position", True },
2731 { "menuFile.Load Next Position", True },
2732 { "menuFile.Load Previous Position", True },
2733 { "menuFile.Reload Same Position", True },
2734 { "menuFile.Paste Position", True },
2735 { "menuMode.Machine White", True },
2736 { "menuMode.Machine Black", True },
2737 { "menuMode.Two Machines", True },
2738 { "menuStep.Retract Move", True },
2744 SetMenuEnables(icsEnables);
2747 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2748 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2755 SetMenuEnables(ncpEnables);
2761 SetMenuEnables(gnuEnables);
2767 SetMenuEnables(cmailEnables);
2773 SetMenuEnables(trainingOnEnables);
2774 if (appData.showButtonBar) {
2775 XtSetSensitive(buttonBarWidget, False);
2781 SetTrainingModeOff()
2783 SetMenuEnables(trainingOffEnables);
2784 if (appData.showButtonBar) {
2785 XtSetSensitive(buttonBarWidget, True);
2790 SetUserThinkingEnables()
2792 if (appData.noChessProgram) return;
2793 SetMenuEnables(userThinkingEnables);
2797 SetMachineThinkingEnables()
2799 if (appData.noChessProgram) return;
2800 SetMenuEnables(machineThinkingEnables);
2802 case MachinePlaysBlack:
2803 case MachinePlaysWhite:
2804 case TwoMachinesPlay:
2805 XtSetSensitive(XtNameToWidget(menuBarWidget,
2806 ModeToWidgetName(gameMode)), True);
2813 #define Abs(n) ((n)<0 ? -(n) : (n))
2816 * Find a font that matches "pattern" that is as close as
2817 * possible to the targetPxlSize. Prefer fonts that are k
2818 * pixels smaller to fonts that are k pixels larger. The
2819 * pattern must be in the X Consortium standard format,
2820 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2821 * The return value should be freed with XtFree when no
2824 char *FindFont(pattern, targetPxlSize)
2828 char **fonts, *p, *best, *scalable, *scalableTail;
2829 int i, j, nfonts, minerr, err, pxlSize;
2832 char **missing_list;
2834 char *def_string, *base_fnt_lst, strInt[3];
2836 XFontStruct **fnt_list;
2838 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2839 sprintf(strInt, "%d", targetPxlSize);
2840 p = strstr(pattern, "--");
2841 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2842 strcat(base_fnt_lst, strInt);
2843 strcat(base_fnt_lst, strchr(p + 2, '-'));
2845 if ((fntSet = XCreateFontSet(xDisplay,
2849 &def_string)) == NULL) {
2851 fprintf(stderr, _("Unable to create font set.\n"));
2855 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2857 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2859 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2860 programName, pattern);
2868 for (i=0; i<nfonts; i++) {
2871 if (*p != '-') continue;
2873 if (*p == NULLCHAR) break;
2874 if (*p++ == '-') j++;
2876 if (j < 7) continue;
2879 scalable = fonts[i];
2882 err = pxlSize - targetPxlSize;
2883 if (Abs(err) < Abs(minerr) ||
2884 (minerr > 0 && err < 0 && -err == minerr)) {
2890 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
2891 /* If the error is too big and there is a scalable font,
2892 use the scalable font. */
2893 int headlen = scalableTail - scalable;
2894 p = (char *) XtMalloc(strlen(scalable) + 10);
2895 while (isdigit(*scalableTail)) scalableTail++;
2896 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
2898 p = (char *) XtMalloc(strlen(best) + 1);
2901 if (appData.debugMode) {
2902 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
2903 pattern, targetPxlSize, p);
2906 if (missing_count > 0)
2907 XFreeStringList(missing_list);
2908 XFreeFontSet(xDisplay, fntSet);
2910 XFreeFontNames(fonts);
2917 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
2918 | GCBackground | GCFunction | GCPlaneMask;
2919 XGCValues gc_values;
2922 gc_values.plane_mask = AllPlanes;
2923 gc_values.line_width = lineGap;
2924 gc_values.line_style = LineSolid;
2925 gc_values.function = GXcopy;
2927 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2928 gc_values.background = XBlackPixel(xDisplay, xScreen);
2929 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2931 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2932 gc_values.background = XWhitePixel(xDisplay, xScreen);
2933 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
2934 XSetFont(xDisplay, coordGC, coordFontID);
2936 // [HGM] make font for holdings counts (white on black0
2937 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2938 gc_values.background = XBlackPixel(xDisplay, xScreen);
2939 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
2940 XSetFont(xDisplay, countGC, countFontID);
2942 if (appData.monoMode) {
2943 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2944 gc_values.background = XWhitePixel(xDisplay, xScreen);
2945 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2947 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2948 gc_values.background = XBlackPixel(xDisplay, xScreen);
2949 lightSquareGC = wbPieceGC
2950 = XtGetGC(shellWidget, value_mask, &gc_values);
2952 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2953 gc_values.background = XWhitePixel(xDisplay, xScreen);
2954 darkSquareGC = bwPieceGC
2955 = XtGetGC(shellWidget, value_mask, &gc_values);
2957 if (DefaultDepth(xDisplay, xScreen) == 1) {
2958 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
2959 gc_values.function = GXcopyInverted;
2960 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
2961 gc_values.function = GXcopy;
2962 if (XBlackPixel(xDisplay, xScreen) == 1) {
2963 bwPieceGC = darkSquareGC;
2964 wbPieceGC = copyInvertedGC;
2966 bwPieceGC = copyInvertedGC;
2967 wbPieceGC = lightSquareGC;
2971 gc_values.foreground = highlightSquareColor;
2972 gc_values.background = highlightSquareColor;
2973 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2975 gc_values.foreground = premoveHighlightColor;
2976 gc_values.background = premoveHighlightColor;
2977 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2979 gc_values.foreground = lightSquareColor;
2980 gc_values.background = darkSquareColor;
2981 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2983 gc_values.foreground = darkSquareColor;
2984 gc_values.background = lightSquareColor;
2985 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2987 gc_values.foreground = jailSquareColor;
2988 gc_values.background = jailSquareColor;
2989 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2991 gc_values.foreground = whitePieceColor;
2992 gc_values.background = darkSquareColor;
2993 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
2995 gc_values.foreground = whitePieceColor;
2996 gc_values.background = lightSquareColor;
2997 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
2999 gc_values.foreground = whitePieceColor;
3000 gc_values.background = jailSquareColor;
3001 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3003 gc_values.foreground = blackPieceColor;
3004 gc_values.background = darkSquareColor;
3005 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3007 gc_values.foreground = blackPieceColor;
3008 gc_values.background = lightSquareColor;
3009 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3011 gc_values.foreground = blackPieceColor;
3012 gc_values.background = jailSquareColor;
3013 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3017 void loadXIM(xim, xmask, filename, dest, mask)
3030 fp = fopen(filename, "rb");
3032 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3039 for (y=0; y<h; ++y) {
3040 for (x=0; x<h; ++x) {
3045 XPutPixel(xim, x, y, blackPieceColor);
3047 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3050 XPutPixel(xim, x, y, darkSquareColor);
3052 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3055 XPutPixel(xim, x, y, whitePieceColor);
3057 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3060 XPutPixel(xim, x, y, lightSquareColor);
3062 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3068 /* create Pixmap of piece */
3069 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3071 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3074 /* create Pixmap of clipmask
3075 Note: We assume the white/black pieces have the same
3076 outline, so we make only 6 masks. This is okay
3077 since the XPM clipmask routines do the same. */
3079 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3081 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3084 /* now create the 1-bit version */
3085 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3088 values.foreground = 1;
3089 values.background = 0;
3091 /* Don't use XtGetGC, not read only */
3092 maskGC = XCreateGC(xDisplay, *mask,
3093 GCForeground | GCBackground, &values);
3094 XCopyPlane(xDisplay, temp, *mask, maskGC,
3095 0, 0, squareSize, squareSize, 0, 0, 1);
3096 XFreePixmap(xDisplay, temp);
3101 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3103 void CreateXIMPieces()
3108 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3113 /* The XSynchronize calls were copied from CreatePieces.
3114 Not sure if needed, but can't hurt */
3115 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3118 /* temp needed by loadXIM() */
3119 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3120 0, 0, ss, ss, AllPlanes, XYPixmap);
3122 if (strlen(appData.pixmapDirectory) == 0) {
3126 if (appData.monoMode) {
3127 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3131 fprintf(stderr, _("\nLoading XIMs...\n"));
3133 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3134 fprintf(stderr, "%d", piece+1);
3135 for (kind=0; kind<4; kind++) {
3136 fprintf(stderr, ".");
3137 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3138 ExpandPathName(appData.pixmapDirectory),
3139 piece <= (int) WhiteKing ? "" : "w",
3140 pieceBitmapNames[piece],
3142 ximPieceBitmap[kind][piece] =
3143 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3144 0, 0, ss, ss, AllPlanes, XYPixmap);
3145 if (appData.debugMode)
3146 fprintf(stderr, _("(File:%s:) "), buf);
3147 loadXIM(ximPieceBitmap[kind][piece],
3149 &(xpmPieceBitmap2[kind][piece]),
3150 &(ximMaskPm2[piece]));
3151 if(piece <= (int)WhiteKing)
3152 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3154 fprintf(stderr," ");
3156 /* Load light and dark squares */
3157 /* If the LSQ and DSQ pieces don't exist, we will
3158 draw them with solid squares. */
3159 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3160 if (access(buf, 0) != 0) {
3164 fprintf(stderr, _("light square "));
3166 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3167 0, 0, ss, ss, AllPlanes, XYPixmap);
3168 if (appData.debugMode)
3169 fprintf(stderr, _("(File:%s:) "), buf);
3171 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3172 fprintf(stderr, _("dark square "));
3173 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3174 ExpandPathName(appData.pixmapDirectory), ss);
3175 if (appData.debugMode)
3176 fprintf(stderr, _("(File:%s:) "), buf);
3178 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3179 0, 0, ss, ss, AllPlanes, XYPixmap);
3180 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3181 xpmJailSquare = xpmLightSquare;
3183 fprintf(stderr, _("Done.\n"));
3185 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3189 void CreateXPMPieces()
3193 u_int ss = squareSize;
3195 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3196 XpmColorSymbol symbols[4];
3198 /* The XSynchronize calls were copied from CreatePieces.
3199 Not sure if needed, but can't hurt */
3200 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3202 /* Setup translations so piece colors match square colors */
3203 symbols[0].name = "light_piece";
3204 symbols[0].value = appData.whitePieceColor;
3205 symbols[1].name = "dark_piece";
3206 symbols[1].value = appData.blackPieceColor;
3207 symbols[2].name = "light_square";
3208 symbols[2].value = appData.lightSquareColor;
3209 symbols[3].name = "dark_square";
3210 symbols[3].value = appData.darkSquareColor;
3212 attr.valuemask = XpmColorSymbols;
3213 attr.colorsymbols = symbols;
3214 attr.numsymbols = 4;
3216 if (appData.monoMode) {
3217 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3221 if (strlen(appData.pixmapDirectory) == 0) {
3222 XpmPieces* pieces = builtInXpms;
3225 while (pieces->size != squareSize && pieces->size) pieces++;
3226 if (!pieces->size) {
3227 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3230 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3231 for (kind=0; kind<4; kind++) {
3233 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3234 pieces->xpm[piece][kind],
3235 &(xpmPieceBitmap2[kind][piece]),
3236 NULL, &attr)) != 0) {
3237 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3241 if(piece <= (int) WhiteKing)
3242 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3246 xpmJailSquare = xpmLightSquare;
3250 fprintf(stderr, _("\nLoading XPMs...\n"));
3253 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3254 fprintf(stderr, "%d ", piece+1);
3255 for (kind=0; kind<4; kind++) {
3256 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3257 ExpandPathName(appData.pixmapDirectory),
3258 piece > (int) WhiteKing ? "w" : "",
3259 pieceBitmapNames[piece],
3261 if (appData.debugMode) {
3262 fprintf(stderr, _("(File:%s:) "), buf);
3264 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3265 &(xpmPieceBitmap2[kind][piece]),
3266 NULL, &attr)) != 0) {
3267 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3268 // [HGM] missing: read of unorthodox piece failed; substitute King.
3269 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3270 ExpandPathName(appData.pixmapDirectory),
3272 if (appData.debugMode) {
3273 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3275 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3276 &(xpmPieceBitmap2[kind][piece]),
3280 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3285 if(piece <= (int) WhiteKing)
3286 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3289 /* Load light and dark squares */
3290 /* If the LSQ and DSQ pieces don't exist, we will
3291 draw them with solid squares. */
3292 fprintf(stderr, _("light square "));
3293 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3294 if (access(buf, 0) != 0) {
3298 if (appData.debugMode)
3299 fprintf(stderr, _("(File:%s:) "), buf);
3301 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3302 &xpmLightSquare, NULL, &attr)) != 0) {
3303 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3306 fprintf(stderr, _("dark square "));
3307 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3308 ExpandPathName(appData.pixmapDirectory), ss);
3309 if (appData.debugMode) {
3310 fprintf(stderr, _("(File:%s:) "), buf);
3312 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3313 &xpmDarkSquare, NULL, &attr)) != 0) {
3314 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3318 xpmJailSquare = xpmLightSquare;
3319 fprintf(stderr, _("Done.\n"));
3321 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3324 #endif /* HAVE_LIBXPM */
3327 /* No built-in bitmaps */
3332 u_int ss = squareSize;
3334 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3337 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3338 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3339 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3340 pieceBitmapNames[piece],
3341 ss, kind == SOLID ? 's' : 'o');
3342 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3343 if(piece <= (int)WhiteKing)
3344 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3348 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3352 /* With built-in bitmaps */
3355 BuiltInBits* bib = builtInBits;
3358 u_int ss = squareSize;
3360 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3363 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3365 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3366 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3367 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3368 pieceBitmapNames[piece],
3369 ss, kind == SOLID ? 's' : 'o');
3370 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3371 bib->bits[kind][piece], ss, ss);
3372 if(piece <= (int)WhiteKing)
3373 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3377 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3382 void ReadBitmap(pm, name, bits, wreq, hreq)
3385 unsigned char bits[];
3391 char msg[MSG_SIZ], fullname[MSG_SIZ];
3393 if (*appData.bitmapDirectory != NULLCHAR) {
3394 strcpy(fullname, appData.bitmapDirectory);
3395 strcat(fullname, "/");
3396 strcat(fullname, name);
3397 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3398 &w, &h, pm, &x_hot, &y_hot);
3399 fprintf(stderr, "load %s\n", name);
3400 if (errcode != BitmapSuccess) {
3402 case BitmapOpenFailed:
3403 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3405 case BitmapFileInvalid:
3406 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3408 case BitmapNoMemory:
3409 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3413 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3417 fprintf(stderr, _("%s: %s...using built-in\n"),
3419 } else if (w != wreq || h != hreq) {
3421 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3422 programName, fullname, w, h, wreq, hreq);
3428 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3437 if (lineGap == 0) return;
3439 /* [HR] Split this into 2 loops for non-square boards. */
3441 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3442 gridSegments[i].x1 = 0;
3443 gridSegments[i].x2 =
3444 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3445 gridSegments[i].y1 = gridSegments[i].y2
3446 = lineGap / 2 + (i * (squareSize + lineGap));
3449 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3450 gridSegments[j + i].y1 = 0;
3451 gridSegments[j + i].y2 =
3452 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3453 gridSegments[j + i].x1 = gridSegments[j + i].x2
3454 = lineGap / 2 + (j * (squareSize + lineGap));
3458 static void MenuBarSelect(w, addr, index)
3463 XtActionProc proc = (XtActionProc) addr;
3465 (proc)(NULL, NULL, NULL, NULL);
3468 void CreateMenuBarPopup(parent, name, mb)
3478 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3481 XtSetArg(args[j], XtNleftMargin, 20); j++;
3482 XtSetArg(args[j], XtNrightMargin, 20); j++;
3484 while (mi->string != NULL) {
3485 if (strcmp(mi->string, "----") == 0) {
3486 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3489 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3490 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3492 XtAddCallback(entry, XtNcallback,
3493 (XtCallbackProc) MenuBarSelect,
3494 (caddr_t) mi->proc);
3500 Widget CreateMenuBar(mb)
3504 Widget anchor, menuBar;
3506 char menuName[MSG_SIZ];
3509 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3510 XtSetArg(args[j], XtNvSpace, 0); j++;
3511 XtSetArg(args[j], XtNborderWidth, 0); j++;
3512 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3513 formWidget, args, j);
3515 while (mb->name != NULL) {
3516 strcpy(menuName, "menu");
3517 strcat(menuName, mb->name);
3519 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3522 shortName[0] = _(mb->name)[0];
3523 shortName[1] = NULLCHAR;
3524 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3527 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3530 XtSetArg(args[j], XtNborderWidth, 0); j++;
3531 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3533 CreateMenuBarPopup(menuBar, menuName, mb);
3539 Widget CreateButtonBar(mi)
3543 Widget button, buttonBar;
3547 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3549 XtSetArg(args[j], XtNhSpace, 0); j++;
3551 XtSetArg(args[j], XtNborderWidth, 0); j++;
3552 XtSetArg(args[j], XtNvSpace, 0); j++;
3553 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3554 formWidget, args, j);
3556 while (mi->string != NULL) {
3559 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3560 XtSetArg(args[j], XtNborderWidth, 0); j++;
3562 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3563 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3564 buttonBar, args, j);
3565 XtAddCallback(button, XtNcallback,
3566 (XtCallbackProc) MenuBarSelect,
3567 (caddr_t) mi->proc);
3574 CreatePieceMenu(name, color)
3581 ChessSquare selection;
3583 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3584 boardWidget, args, 0);
3586 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3587 String item = pieceMenuStrings[color][i];
3589 if (strcmp(item, "----") == 0) {
3590 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3593 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3594 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3596 selection = pieceMenuTranslation[color][i];
3597 XtAddCallback(entry, XtNcallback,
3598 (XtCallbackProc) PieceMenuSelect,
3599 (caddr_t) selection);
3600 if (selection == WhitePawn || selection == BlackPawn) {
3601 XtSetArg(args[0], XtNpopupOnEntry, entry);
3602 XtSetValues(menu, args, 1);
3615 ChessSquare selection;
3617 whitePieceMenu = CreatePieceMenu("menuW", 0);
3618 blackPieceMenu = CreatePieceMenu("menuB", 1);
3620 XtRegisterGrabAction(PieceMenuPopup, True,
3621 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3622 GrabModeAsync, GrabModeAsync);
3624 XtSetArg(args[0], XtNlabel, _("Drop"));
3625 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3626 boardWidget, args, 1);
3627 for (i = 0; i < DROP_MENU_SIZE; i++) {
3628 String item = dropMenuStrings[i];
3630 if (strcmp(item, "----") == 0) {
3631 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3634 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3635 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3637 selection = dropMenuTranslation[i];
3638 XtAddCallback(entry, XtNcallback,
3639 (XtCallbackProc) DropMenuSelect,
3640 (caddr_t) selection);
3645 void SetupDropMenu()
3653 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3654 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3655 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3656 dmEnables[i].piece);
3657 XtSetSensitive(entry, p != NULL || !appData.testLegality
3658 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3659 && !appData.icsActive));
3661 while (p && *p++ == dmEnables[i].piece) count++;
3662 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3664 XtSetArg(args[j], XtNlabel, label); j++;
3665 XtSetValues(entry, args, j);
3669 void PieceMenuPopup(w, event, params, num_params)
3673 Cardinal *num_params;
3676 if (event->type != ButtonPress) return;
3677 if (errorUp) ErrorPopDown();
3681 whichMenu = params[0];
3683 case IcsPlayingWhite:
3684 case IcsPlayingBlack:
3686 case MachinePlaysWhite:
3687 case MachinePlaysBlack:
3688 if (appData.testLegality &&
3689 gameInfo.variant != VariantBughouse &&
3690 gameInfo.variant != VariantCrazyhouse) return;
3692 whichMenu = "menuD";
3698 if (((pmFromX = EventToSquare(event->xbutton.x, BOARD_WIDTH)) < 0) ||
3699 ((pmFromY = EventToSquare(event->xbutton.y, BOARD_HEIGHT)) < 0)) {
3700 pmFromX = pmFromY = -1;
3704 pmFromX = BOARD_WIDTH - 1 - pmFromX;
3706 pmFromY = BOARD_HEIGHT - 1 - pmFromY;
3708 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3711 static void PieceMenuSelect(w, piece, junk)
3716 if (pmFromX < 0 || pmFromY < 0) return;
3717 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3720 static void DropMenuSelect(w, piece, junk)
3725 if (pmFromX < 0 || pmFromY < 0) return;
3726 DropMenuEvent(piece, pmFromX, pmFromY);
3729 void WhiteClock(w, event, prms, nprms)
3735 if (gameMode == EditPosition || gameMode == IcsExamining) {
3736 SetWhiteToPlayEvent();
3737 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3742 void BlackClock(w, event, prms, nprms)
3748 if (gameMode == EditPosition || gameMode == IcsExamining) {
3749 SetBlackToPlayEvent();
3750 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3757 * If the user selects on a border boundary, return -1; if off the board,
3758 * return -2. Otherwise map the event coordinate to the square.
3760 int EventToSquare(x, limit)
3768 if ((x % (squareSize + lineGap)) >= squareSize)
3770 x /= (squareSize + lineGap);
3776 static void do_flash_delay(msec)
3782 static void drawHighlight(file, rank, gc)
3788 if (lineGap == 0 || appData.blindfold) return;
3791 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3792 (squareSize + lineGap);
3793 y = lineGap/2 + rank * (squareSize + lineGap);
3795 x = lineGap/2 + file * (squareSize + lineGap);
3796 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3797 (squareSize + lineGap);
3800 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3801 squareSize+lineGap, squareSize+lineGap);
3804 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3805 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3808 SetHighlights(fromX, fromY, toX, toY)
3809 int fromX, fromY, toX, toY;
3811 if (hi1X != fromX || hi1Y != fromY) {
3812 if (hi1X >= 0 && hi1Y >= 0) {
3813 drawHighlight(hi1X, hi1Y, lineGC);
3815 if (fromX >= 0 && fromY >= 0) {
3816 drawHighlight(fromX, fromY, highlineGC);
3819 if (hi2X != toX || hi2Y != toY) {
3820 if (hi2X >= 0 && hi2Y >= 0) {
3821 drawHighlight(hi2X, hi2Y, lineGC);
3823 if (toX >= 0 && toY >= 0) {
3824 drawHighlight(toX, toY, highlineGC);
3836 SetHighlights(-1, -1, -1, -1);
3841 SetPremoveHighlights(fromX, fromY, toX, toY)
3842 int fromX, fromY, toX, toY;
3844 if (pm1X != fromX || pm1Y != fromY) {
3845 if (pm1X >= 0 && pm1Y >= 0) {
3846 drawHighlight(pm1X, pm1Y, lineGC);
3848 if (fromX >= 0 && fromY >= 0) {
3849 drawHighlight(fromX, fromY, prelineGC);
3852 if (pm2X != toX || pm2Y != toY) {
3853 if (pm2X >= 0 && pm2Y >= 0) {
3854 drawHighlight(pm2X, pm2Y, lineGC);
3856 if (toX >= 0 && toY >= 0) {
3857 drawHighlight(toX, toY, prelineGC);
3867 ClearPremoveHighlights()
3869 SetPremoveHighlights(-1, -1, -1, -1);
3872 static void BlankSquare(x, y, color, piece, dest)
3877 if (useImages && useImageSqs) {
3881 pm = xpmLightSquare;
3886 case 2: /* neutral */
3891 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
3892 squareSize, squareSize, x, y);
3902 case 2: /* neutral */
3907 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
3912 I split out the routines to draw a piece so that I could
3913 make a generic flash routine.
3915 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
3917 int square_color, x, y;
3920 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3921 switch (square_color) {
3923 case 2: /* neutral */
3925 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3926 ? *pieceToOutline(piece)
3927 : *pieceToSolid(piece),
3928 dest, bwPieceGC, 0, 0,
3929 squareSize, squareSize, x, y);
3932 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3933 ? *pieceToSolid(piece)
3934 : *pieceToOutline(piece),
3935 dest, wbPieceGC, 0, 0,
3936 squareSize, squareSize, x, y);
3941 static void monoDrawPiece(piece, square_color, x, y, dest)
3943 int square_color, x, y;
3946 switch (square_color) {
3948 case 2: /* neutral */
3950 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3951 ? *pieceToOutline(piece)
3952 : *pieceToSolid(piece),
3953 dest, bwPieceGC, 0, 0,
3954 squareSize, squareSize, x, y, 1);
3957 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3958 ? *pieceToSolid(piece)
3959 : *pieceToOutline(piece),
3960 dest, wbPieceGC, 0, 0,
3961 squareSize, squareSize, x, y, 1);
3966 static void colorDrawPiece(piece, square_color, x, y, dest)
3968 int square_color, x, y;
3971 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
3972 switch (square_color) {
3974 XCopyPlane(xDisplay, *pieceToSolid(piece),
3975 dest, (int) piece < (int) BlackPawn
3976 ? wlPieceGC : blPieceGC, 0, 0,
3977 squareSize, squareSize, x, y, 1);
3980 XCopyPlane(xDisplay, *pieceToSolid(piece),
3981 dest, (int) piece < (int) BlackPawn
3982 ? wdPieceGC : bdPieceGC, 0, 0,
3983 squareSize, squareSize, x, y, 1);
3985 case 2: /* neutral */
3987 XCopyPlane(xDisplay, *pieceToSolid(piece),
3988 dest, (int) piece < (int) BlackPawn
3989 ? wjPieceGC : bjPieceGC, 0, 0,
3990 squareSize, squareSize, x, y, 1);
3995 static void colorDrawPieceImage(piece, square_color, x, y, dest)
3997 int square_color, x, y;
4002 switch (square_color) {
4004 case 2: /* neutral */
4006 if ((int)piece < (int) BlackPawn) {
4014 if ((int)piece < (int) BlackPawn) {
4022 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4023 dest, wlPieceGC, 0, 0,
4024 squareSize, squareSize, x, y);
4027 typedef void (*DrawFunc)();
4029 DrawFunc ChooseDrawFunc()
4031 if (appData.monoMode) {
4032 if (DefaultDepth(xDisplay, xScreen) == 1) {
4033 return monoDrawPiece_1bit;
4035 return monoDrawPiece;
4039 return colorDrawPieceImage;
4041 return colorDrawPiece;
4045 /* [HR] determine square color depending on chess variant. */
4046 static int SquareColor(row, column)
4051 if (gameInfo.variant == VariantXiangqi) {
4052 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4054 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4056 } else if (row <= 4) {
4062 square_color = ((column + row) % 2) == 1;
4065 /* [hgm] holdings: next line makes all holdings squares light */
4066 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4068 return square_color;
4071 void DrawSquare(row, column, piece, do_flash)
4072 int row, column, do_flash;
4075 int square_color, x, y, direction, font_ascent, font_descent;
4078 XCharStruct overall;
4082 /* Calculate delay in milliseconds (2-delays per complete flash) */
4083 flash_delay = 500 / appData.flashRate;
4086 x = lineGap + ((BOARD_WIDTH-1)-column) *
4087 (squareSize + lineGap);
4088 y = lineGap + row * (squareSize + lineGap);
4090 x = lineGap + column * (squareSize + lineGap);
4091 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4092 (squareSize + lineGap);
4095 square_color = SquareColor(row, column);
4097 if ( // [HGM] holdings: blank out area between board and holdings
4098 column == BOARD_LEFT-1 || column == BOARD_RGHT
4099 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4100 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4101 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4103 // [HGM] print piece counts next to holdings
4104 string[1] = NULLCHAR;
4105 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4106 string[0] = '0' + piece;
4107 XTextExtents(countFontStruct, string, 1, &direction,
4108 &font_ascent, &font_descent, &overall);
4109 if (appData.monoMode) {
4110 XDrawImageString(xDisplay, xBoardWindow, countGC,
4111 x + squareSize - overall.width - 2,
4112 y + font_ascent + 1, string, 1);
4114 XDrawString(xDisplay, xBoardWindow, countGC,
4115 x + squareSize - overall.width - 2,
4116 y + font_ascent + 1, string, 1);
4119 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4120 string[0] = '0' + piece;
4121 XTextExtents(countFontStruct, string, 1, &direction,
4122 &font_ascent, &font_descent, &overall);
4123 if (appData.monoMode) {
4124 XDrawImageString(xDisplay, xBoardWindow, countGC,
4125 x + 2, y + font_ascent + 1, string, 1);
4127 XDrawString(xDisplay, xBoardWindow, countGC,
4128 x + 2, y + font_ascent + 1, string, 1);
4132 if (piece == EmptySquare || appData.blindfold) {
4133 BlankSquare(x, y, square_color, piece, xBoardWindow);
4135 drawfunc = ChooseDrawFunc();
4136 if (do_flash && appData.flashCount > 0) {
4137 for (i=0; i<appData.flashCount; ++i) {
4139 drawfunc(piece, square_color, x, y, xBoardWindow);
4140 XSync(xDisplay, False);
4141 do_flash_delay(flash_delay);
4143 BlankSquare(x, y, square_color, piece, xBoardWindow);
4144 XSync(xDisplay, False);
4145 do_flash_delay(flash_delay);
4148 drawfunc(piece, square_color, x, y, xBoardWindow);
4152 string[1] = NULLCHAR;
4153 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4154 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4155 string[0] = 'a' + column - BOARD_LEFT;
4156 XTextExtents(coordFontStruct, string, 1, &direction,
4157 &font_ascent, &font_descent, &overall);
4158 if (appData.monoMode) {
4159 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4160 x + squareSize - overall.width - 2,
4161 y + squareSize - font_descent - 1, string, 1);
4163 XDrawString(xDisplay, xBoardWindow, coordGC,
4164 x + squareSize - overall.width - 2,
4165 y + squareSize - font_descent - 1, string, 1);
4168 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4169 string[0] = ONE + row;
4170 XTextExtents(coordFontStruct, string, 1, &direction,
4171 &font_ascent, &font_descent, &overall);
4172 if (appData.monoMode) {
4173 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4174 x + 2, y + font_ascent + 1, string, 1);
4176 XDrawString(xDisplay, xBoardWindow, coordGC,
4177 x + 2, y + font_ascent + 1, string, 1);
4183 /* Why is this needed on some versions of X? */
4184 void EventProc(widget, unused, event)
4189 if (!XtIsRealized(widget))
4192 switch (event->type) {
4194 if (event->xexpose.count > 0) return; /* no clipping is done */
4195 XDrawPosition(widget, True, NULL);
4203 void DrawPosition(fullRedraw, board)
4204 /*Boolean*/int fullRedraw;
4207 XDrawPosition(boardWidget, fullRedraw, board);
4210 /* Returns 1 if there are "too many" differences between b1 and b2
4211 (i.e. more than 1 move was made) */
4212 static int too_many_diffs(b1, b2)
4218 for (i=0; i<BOARD_HEIGHT; ++i) {
4219 for (j=0; j<BOARD_WIDTH; ++j) {
4220 if (b1[i][j] != b2[i][j]) {
4221 if (++c > 4) /* Castling causes 4 diffs */
4230 /* Matrix describing castling maneuvers */
4231 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4232 static int castling_matrix[4][5] = {
4233 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4234 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4235 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4236 { 7, 7, 4, 5, 6 } /* 0-0, black */
4239 /* Checks whether castling occurred. If it did, *rrow and *rcol
4240 are set to the destination (row,col) of the rook that moved.
4242 Returns 1 if castling occurred, 0 if not.
4244 Note: Only handles a max of 1 castling move, so be sure
4245 to call too_many_diffs() first.
4247 static int check_castle_draw(newb, oldb, rrow, rcol)