2 * xboard.c -- X front end for XBoard
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
8 * 2007, 2008, 2009 Free Software Foundation, Inc.
10 * The following terms apply to Digital Equipment Corporation's copyright
12 * ------------------------------------------------------------------------
15 * Permission to use, copy, modify, and distribute this software and its
16 * documentation for any purpose and without fee is hereby granted,
17 * provided that the above copyright notice appear in all copies and that
18 * both that copyright notice and this permission notice appear in
19 * supporting documentation, and that the name of Digital not be
20 * used in advertising or publicity pertaining to distribution of the
21 * software without specific, written prior permission.
23 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
30 * ------------------------------------------------------------------------
32 * The following terms apply to the enhanced version of XBoard
33 * distributed by the Free Software Foundation:
34 * ------------------------------------------------------------------------
36 * GNU XBoard is free software: you can redistribute it and/or modify
37 * it under the terms of the GNU General Public License as published by
38 * the Free Software Foundation, either version 3 of the License, or (at
39 * your option) any later version.
41 * GNU XBoard is distributed in the hope that it will be useful, but
42 * WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44 * General Public License for more details.
46 * You should have received a copy of the GNU General Public License
47 * along with this program. If not, see http://www.gnu.org/licenses/. *
49 *------------------------------------------------------------------------
50 ** See the file ChangeLog for a revision history. */
58 #include <sys/types.h>
63 # if HAVE_SYS_SOCKET_H
64 # include <sys/socket.h>
65 # include <netinet/in.h>
67 # else /* not HAVE_SYS_SOCKET_H */
68 # if HAVE_LAN_SOCKET_H
69 # include <lan/socket.h>
71 # include <lan/netdb.h>
72 # else /* not HAVE_LAN_SOCKET_H */
73 # define OMIT_SOCKETS 1
74 # endif /* not HAVE_LAN_SOCKET_H */
75 # endif /* not HAVE_SYS_SOCKET_H */
76 #endif /* !OMIT_SOCKETS */
81 #else /* not STDC_HEADERS */
82 extern char *getenv();
85 # else /* not HAVE_STRING_H */
87 # endif /* not HAVE_STRING_H */
88 #endif /* not STDC_HEADERS */
91 # include <sys/fcntl.h>
92 #else /* not HAVE_SYS_FCNTL_H */
95 # endif /* HAVE_FCNTL_H */
96 #endif /* not HAVE_SYS_FCNTL_H */
98 #if HAVE_SYS_SYSTEMINFO_H
99 # include <sys/systeminfo.h>
100 #endif /* HAVE_SYS_SYSTEMINFO_H */
102 #if TIME_WITH_SYS_TIME
103 # include <sys/time.h>
107 # include <sys/time.h>
118 # include <sys/wait.h>
123 # define NAMLEN(dirent) strlen((dirent)->d_name)
124 # define HAVE_DIR_STRUCT
126 # define dirent direct
127 # define NAMLEN(dirent) (dirent)->d_namlen
129 # include <sys/ndir.h>
130 # define HAVE_DIR_STRUCT
133 # include <sys/dir.h>
134 # define HAVE_DIR_STRUCT
138 # define HAVE_DIR_STRUCT
142 #include <X11/Intrinsic.h>
143 #include <X11/StringDefs.h>
144 #include <X11/Shell.h>
145 #include <X11/cursorfont.h>
146 #include <X11/Xatom.h>
147 #include <X11/Xmu/Atoms.h>
149 #include <X11/Xaw3d/Dialog.h>
150 #include <X11/Xaw3d/Form.h>
151 #include <X11/Xaw3d/List.h>
152 #include <X11/Xaw3d/Label.h>
153 #include <X11/Xaw3d/SimpleMenu.h>
154 #include <X11/Xaw3d/SmeBSB.h>
155 #include <X11/Xaw3d/SmeLine.h>
156 #include <X11/Xaw3d/Box.h>
157 #include <X11/Xaw3d/MenuButton.h>
158 #include <X11/Xaw3d/Text.h>
159 #include <X11/Xaw3d/AsciiText.h>
161 #include <X11/Xaw/Dialog.h>
162 #include <X11/Xaw/Form.h>
163 #include <X11/Xaw/List.h>
164 #include <X11/Xaw/Label.h>
165 #include <X11/Xaw/SimpleMenu.h>
166 #include <X11/Xaw/SmeBSB.h>
167 #include <X11/Xaw/SmeLine.h>
168 #include <X11/Xaw/Box.h>
169 #include <X11/Xaw/MenuButton.h>
170 #include <X11/Xaw/Text.h>
171 #include <X11/Xaw/AsciiText.h>
174 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
179 #include "pixmaps/pixmaps.h"
180 #define IMAGE_EXT "xpm"
182 #define IMAGE_EXT "xim"
183 #include "bitmaps/bitmaps.h"
186 #include "bitmaps/icon_white.bm"
187 #include "bitmaps/icon_black.bm"
188 #include "bitmaps/checkmark.bm"
190 #include "frontend.h"
195 #include "xgamelist.h"
196 #include "xhistory.h"
197 #include "xedittags.h"
200 // must be moved to xengineoutput.h
202 void EngineOutputProc P((Widget w, XEvent *event,
203 String *prms, Cardinal *nprms));
204 void EvalGraphProc P((Widget w, XEvent *event,
205 String *prms, Cardinal *nprms));
212 #define usleep(t) _sleep2(((t)+500)/1000)
216 # define _(s) gettext (s)
217 # define N_(s) gettext_noop (s)
233 int main P((int argc, char **argv));
234 RETSIGTYPE CmailSigHandler P((int sig));
235 RETSIGTYPE IntSigHandler P((int sig));
236 RETSIGTYPE TermSizeSigHandler P((int sig));
237 void CreateGCs P((void));
238 void CreateXIMPieces P((void));
239 void CreateXPMPieces P((void));
240 void CreatePieces P((void));
241 void CreatePieceMenus P((void));
242 Widget CreateMenuBar P((Menu *mb));
243 Widget CreateButtonBar P ((MenuItem *mi));
244 char *FindFont P((char *pattern, int targetPxlSize));
245 void PieceMenuPopup P((Widget w, XEvent *event,
246 String *params, Cardinal *num_params));
247 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
248 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
249 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
250 u_int wreq, u_int hreq));
251 void CreateGrid P((void));
252 int EventToSquare P((int x, int limit));
253 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
254 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
255 void HandleUserMove P((Widget w, XEvent *event,
256 String *prms, Cardinal *nprms));
257 void AnimateUserMove P((Widget w, XEvent * event,
258 String * params, Cardinal * nParams));
259 void WhiteClock P((Widget w, XEvent *event,
260 String *prms, Cardinal *nprms));
261 void BlackClock P((Widget w, XEvent *event,
262 String *prms, Cardinal *nprms));
263 void DrawPositionProc P((Widget w, XEvent *event,
264 String *prms, Cardinal *nprms));
265 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
267 void CommentPopUp P((char *title, char *label));
268 void CommentPopDown P((void));
269 void CommentCallback P((Widget w, XtPointer client_data,
270 XtPointer call_data));
271 void ICSInputBoxPopUp P((void));
272 void ICSInputBoxPopDown P((void));
273 void FileNamePopUp P((char *label, char *def,
274 FileProc proc, char *openMode));
275 void FileNamePopDown P((void));
276 void FileNameCallback P((Widget w, XtPointer client_data,
277 XtPointer call_data));
278 void FileNameAction P((Widget w, XEvent *event,
279 String *prms, Cardinal *nprms));
280 void AskQuestionReplyAction P((Widget w, XEvent *event,
281 String *prms, Cardinal *nprms));
282 void AskQuestionProc P((Widget w, XEvent *event,
283 String *prms, Cardinal *nprms));
284 void AskQuestionPopDown P((void));
285 void PromotionPopDown P((void));
286 void PromotionCallback P((Widget w, XtPointer client_data,
287 XtPointer call_data));
288 void EditCommentPopDown P((void));
289 void EditCommentCallback P((Widget w, XtPointer client_data,
290 XtPointer call_data));
291 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
292 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
293 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
294 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
296 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
298 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
300 void LoadPositionProc P((Widget w, XEvent *event,
301 String *prms, Cardinal *nprms));
302 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
304 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
306 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
308 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
310 void PastePositionProc P((Widget w, XEvent *event, String *prms,
312 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
313 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
314 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
315 void SavePositionProc P((Widget w, XEvent *event,
316 String *prms, Cardinal *nprms));
317 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
318 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
320 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
321 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
322 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
324 void MachineWhiteProc P((Widget w, XEvent *event,
325 String *prms, Cardinal *nprms));
326 void AnalyzeModeProc P((Widget w, XEvent *event,
327 String *prms, Cardinal *nprms));
328 void AnalyzeFileProc P((Widget w, XEvent *event,
329 String *prms, Cardinal *nprms));
330 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
332 void IcsClientProc P((Widget w, XEvent *event, String *prms,
334 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
335 void EditPositionProc P((Widget w, XEvent *event,
336 String *prms, Cardinal *nprms));
337 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
338 void EditCommentProc P((Widget w, XEvent *event,
339 String *prms, Cardinal *nprms));
340 void IcsInputBoxProc P((Widget w, XEvent *event,
341 String *prms, Cardinal *nprms));
342 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
343 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
344 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
345 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
346 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
347 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
348 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
349 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
350 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
351 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
352 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
353 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
354 void StopObservingProc P((Widget w, XEvent *event, String *prms,
356 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
358 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
365 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
367 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
370 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
372 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
374 void AutocommProc P((Widget w, XEvent *event, String *prms,
376 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
377 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void AutobsProc P((Widget w, XEvent *event, String *prms,
380 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
385 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
386 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
388 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
390 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
392 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
393 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
394 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
396 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
398 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
400 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
402 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
404 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
405 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
406 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
408 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
410 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
412 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
414 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
415 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
416 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
417 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
418 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
419 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
420 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
421 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
422 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
423 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
424 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
425 void DisplayMove P((int moveNumber));
426 void DisplayTitle P((char *title));
427 void ICSInitScript P((void));
428 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
429 void ErrorPopUp P((char *title, char *text, int modal));
430 void ErrorPopDown P((void));
431 static char *ExpandPathName P((char *path));
432 static void CreateAnimVars P((void));
433 static void DragPieceMove P((int x, int y));
434 static void DrawDragPiece P((void));
435 char *ModeToWidgetName P((GameMode mode));
436 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
442 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
443 void ShufflePopDown P(());
444 void EnginePopDown P(());
445 void UciPopDown P(());
446 void TimeControlPopDown P(());
447 void NewVariantPopDown P(());
448 void SettingsPopDown P(());
449 void update_ics_width P(());
450 int get_term_width P(());
452 * XBoard depends on Xt R4 or higher
454 int xtVersion = XtSpecificationRelease;
459 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
460 jailSquareColor, highlightSquareColor, premoveHighlightColor;
461 Pixel lowTimeWarningColor;
462 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
463 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
464 wjPieceGC, bjPieceGC, prelineGC, countGC;
465 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
466 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
467 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
468 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
469 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
470 ICSInputShell, fileNameShell, askQuestionShell;
471 Widget historyShell, evalGraphShell, gameListShell;
472 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
473 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
474 Font clockFontID, coordFontID, countFontID;
475 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
476 XtAppContext appContext;
478 char *oldICSInteractionTitle;
482 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
484 Position commentX = -1, commentY = -1;
485 Dimension commentW, commentH;
486 typedef unsigned int BoardSize;
488 Boolean chessProgram;
490 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
491 int squareSize, smallLayout = 0, tinyLayout = 0,
492 marginW, marginH, // [HGM] for run-time resizing
493 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
494 ICSInputBoxUp = False, askQuestionUp = False,
495 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
496 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
497 Pixel timerForegroundPixel, timerBackgroundPixel;
498 Pixel buttonForegroundPixel, buttonBackgroundPixel;
499 char *chessDir, *programName, *programVersion,
500 *gameCopyFilename, *gamePasteFilename;
501 Boolean alwaysOnTop = False;
502 Boolean saveSettingsOnExit;
503 char *settingsFileName;
504 char *icsTextMenuString;
506 char *firstChessProgramNames;
507 char *secondChessProgramNames;
509 WindowPlacement wpMain;
510 WindowPlacement wpConsole;
511 WindowPlacement wpComment;
512 WindowPlacement wpMoveHistory;
513 WindowPlacement wpEvalGraph;
514 WindowPlacement wpEngineOutput;
515 WindowPlacement wpGameList;
516 WindowPlacement wpTags;
520 Pixmap pieceBitmap[2][(int)BlackPawn];
521 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
522 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
523 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
524 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
525 int useImages, useImageSqs;
526 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
527 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
528 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
529 XImage *ximLightSquare, *ximDarkSquare;
532 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
533 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
535 #define White(piece) ((int)(piece) < (int)BlackPawn)
537 /* Variables for doing smooth animation. This whole thing
538 would be much easier if the board was double-buffered,
539 but that would require a fairly major rewrite. */
544 GC blitGC, pieceGC, outlineGC;
545 XPoint startSquare, prevFrame, mouseDelta;
549 int startBoardX, startBoardY;
552 /* There can be two pieces being animated at once: a player
553 can begin dragging a piece before the remote opponent has moved. */
555 static AnimState game, player;
557 /* Bitmaps for use as masks when drawing XPM pieces.
558 Need one for each black and white piece. */
559 static Pixmap xpmMask[BlackKing + 1];
561 /* This magic number is the number of intermediate frames used
562 in each half of the animation. For short moves it's reduced
563 by 1. The total number of frames will be factor * 2 + 1. */
566 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
568 MenuItem fileMenu[] = {
569 {N_("New Game"), ResetProc},
570 {N_("New Shuffle Game ..."), ShuffleMenuProc},
571 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
572 {"----", NothingProc},
573 {N_("Load Game"), LoadGameProc},
574 {N_("Load Next Game"), LoadNextGameProc},
575 {N_("Load Previous Game"), LoadPrevGameProc},
576 {N_("Reload Same Game"), ReloadGameProc},
577 {N_("Save Game"), SaveGameProc},
578 {"----", NothingProc},
579 {N_("Copy Game"), CopyGameProc},
580 {N_("Paste Game"), PasteGameProc},
581 {"----", NothingProc},
582 {N_("Load Position"), LoadPositionProc},
583 {N_("Load Next Position"), LoadNextPositionProc},
584 {N_("Load Previous Position"), LoadPrevPositionProc},
585 {N_("Reload Same Position"), ReloadPositionProc},
586 {N_("Save Position"), SavePositionProc},
587 {"----", NothingProc},
588 {N_("Copy Position"), CopyPositionProc},
589 {N_("Paste Position"), PastePositionProc},
590 {"----", NothingProc},
591 {N_("Mail Move"), MailMoveProc},
592 {N_("Reload CMail Message"), ReloadCmailMsgProc},
593 {"----", NothingProc},
594 {N_("Exit"), QuitProc},
598 MenuItem modeMenu[] = {
599 {N_("Machine White"), MachineWhiteProc},
600 {N_("Machine Black"), MachineBlackProc},
601 {N_("Two Machines"), TwoMachinesProc},
602 {N_("Analysis Mode"), AnalyzeModeProc},
603 {N_("Analyze File"), AnalyzeFileProc },
604 {N_("ICS Client"), IcsClientProc},
605 {N_("Edit Game"), EditGameProc},
606 {N_("Edit Position"), EditPositionProc},
607 {N_("Training"), TrainingProc},
608 {"----", NothingProc},
609 {N_("Show Engine Output"), EngineOutputProc},
610 {N_("Show Evaluation Graph"), EvalGraphProc},
611 {N_("Show Game List"), ShowGameListProc},
612 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
613 {"----", NothingProc},
614 {N_("Edit Tags"), EditTagsProc},
615 {N_("Edit Comment"), EditCommentProc},
616 {N_("ICS Input Box"), IcsInputBoxProc},
617 {N_("Pause"), PauseProc},
621 MenuItem actionMenu[] = {
622 {N_("Accept"), AcceptProc},
623 {N_("Decline"), DeclineProc},
624 {N_("Rematch"), RematchProc},
625 {"----", NothingProc},
626 {N_("Call Flag"), CallFlagProc},
627 {N_("Draw"), DrawProc},
628 {N_("Adjourn"), AdjournProc},
629 {N_("Abort"), AbortProc},
630 {N_("Resign"), ResignProc},
631 {"----", NothingProc},
632 {N_("Stop Observing"), StopObservingProc},
633 {N_("Stop Examining"), StopExaminingProc},
634 {"----", NothingProc},
635 {N_("Adjudicate to White"), AdjuWhiteProc},
636 {N_("Adjudicate to Black"), AdjuBlackProc},
637 {N_("Adjudicate Draw"), AdjuDrawProc},
641 MenuItem stepMenu[] = {
642 {N_("Backward"), BackwardProc},
643 {N_("Forward"), ForwardProc},
644 {N_("Back to Start"), ToStartProc},
645 {N_("Forward to End"), ToEndProc},
646 {N_("Revert"), RevertProc},
647 {N_("Truncate Game"), TruncateGameProc},
648 {"----", NothingProc},
649 {N_("Move Now"), MoveNowProc},
650 {N_("Retract Move"), RetractMoveProc},
654 MenuItem optionsMenu[] = {
655 {N_("Flip View"), FlipViewProc},
656 {"----", NothingProc},
657 {N_("Adjudications ..."), EngineMenuProc},
658 {N_("General Settings ..."), UciMenuProc},
659 {N_("Engine #1 Settings ..."), FirstSettingsProc},
660 {N_("Engine #2 Settings ..."), SecondSettingsProc},
661 {N_("Time Control ..."), TimeControlProc},
662 {"----", NothingProc},
663 {N_("Always Queen"), AlwaysQueenProc},
664 {N_("Animate Dragging"), AnimateDraggingProc},
665 {N_("Animate Moving"), AnimateMovingProc},
666 {N_("Auto Comment"), AutocommProc},
667 {N_("Auto Flag"), AutoflagProc},
668 {N_("Auto Flip View"), AutoflipProc},
669 {N_("Auto Observe"), AutobsProc},
670 {N_("Auto Raise Board"), AutoraiseProc},
671 {N_("Auto Save"), AutosaveProc},
672 {N_("Blindfold"), BlindfoldProc},
673 {N_("Flash Moves"), FlashMovesProc},
674 {N_("Get Move List"), GetMoveListProc},
676 {N_("Highlight Dragging"), HighlightDraggingProc},
678 {N_("Highlight Last Move"), HighlightLastMoveProc},
679 {N_("Move Sound"), MoveSoundProc},
680 {N_("ICS Alarm"), IcsAlarmProc},
681 {N_("Old Save Style"), OldSaveStyleProc},
682 {N_("Periodic Updates"), PeriodicUpdatesProc},
683 {N_("Ponder Next Move"), PonderNextMoveProc},
684 {N_("Popup Exit Message"), PopupExitMessageProc},
685 {N_("Popup Move Errors"), PopupMoveErrorsProc},
686 {N_("Premove"), PremoveProc},
687 {N_("Quiet Play"), QuietPlayProc},
688 {N_("Show Coords"), ShowCoordsProc},
689 {N_("Hide Thinking"), HideThinkingProc},
690 {N_("Test Legality"), TestLegalityProc},
691 {"----", NothingProc},
692 {N_("Save Settings Now"), SaveSettingsProc},
693 {N_("Save Settings on Exit"), SaveOnExitProc},
697 MenuItem helpMenu[] = {
698 {N_("Info XBoard"), InfoProc},
699 {N_("Man XBoard"), ManProc},
700 {"----", NothingProc},
701 {N_("Hint"), HintProc},
702 {N_("Book"), BookProc},
703 {"----", NothingProc},
704 {N_("About XBoard"), AboutProc},
709 {N_("File"), fileMenu},
710 {N_("Mode"), modeMenu},
711 {N_("Action"), actionMenu},
712 {N_("Step"), stepMenu},
713 {N_("Options"), optionsMenu},
714 {N_("Help"), helpMenu},
718 #define PAUSE_BUTTON N_("P")
719 MenuItem buttonBar[] = {
722 {PAUSE_BUTTON, PauseProc},
728 #define PIECE_MENU_SIZE 18
729 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
730 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
731 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
732 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
733 N_("Empty square"), N_("Clear board") },
734 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
735 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
736 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
737 N_("Empty square"), N_("Clear board") }
739 /* must be in same order as PieceMenuStrings! */
740 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
741 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
742 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
743 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
744 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
745 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
746 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
747 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
748 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
751 #define DROP_MENU_SIZE 6
752 String dropMenuStrings[DROP_MENU_SIZE] = {
753 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
755 /* must be in same order as PieceMenuStrings! */
756 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
757 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
758 WhiteRook, WhiteQueen
766 DropMenuEnables dmEnables[] = {
784 { XtNborderWidth, 0 },
785 { XtNdefaultDistance, 0 },
789 { XtNborderWidth, 0 },
790 { XtNresizable, (XtArgVal) True },
794 { XtNborderWidth, 0 },
800 { XtNjustify, (XtArgVal) XtJustifyRight },
801 { XtNlabel, (XtArgVal) "..." },
802 { XtNresizable, (XtArgVal) True },
803 { XtNresize, (XtArgVal) False }
806 Arg messageArgs[] = {
807 { XtNjustify, (XtArgVal) XtJustifyLeft },
808 { XtNlabel, (XtArgVal) "..." },
809 { XtNresizable, (XtArgVal) True },
810 { XtNresize, (XtArgVal) False }
814 { XtNborderWidth, 0 },
815 { XtNjustify, (XtArgVal) XtJustifyLeft }
818 XtResource clientResources[] = {
819 { "flashCount", "flashCount", XtRInt, sizeof(int),
820 XtOffset(AppDataPtr, flashCount), XtRImmediate,
821 (XtPointer) FLASH_COUNT },
824 XrmOptionDescRec shellOptions[] = {
825 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
826 { "-flash", "flashCount", XrmoptionNoArg, "3" },
827 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
830 XtActionsRec boardActions[] = {
831 { "DrawPosition", DrawPositionProc },
832 { "HandleUserMove", HandleUserMove },
833 { "AnimateUserMove", AnimateUserMove },
834 { "FileNameAction", FileNameAction },
835 { "AskQuestionProc", AskQuestionProc },
836 { "AskQuestionReplyAction", AskQuestionReplyAction },
837 { "PieceMenuPopup", PieceMenuPopup },
838 { "WhiteClock", WhiteClock },
839 { "BlackClock", BlackClock },
840 { "Iconify", Iconify },
841 { "ResetProc", ResetProc },
842 { "LoadGameProc", LoadGameProc },
843 { "LoadNextGameProc", LoadNextGameProc },
844 { "LoadPrevGameProc", LoadPrevGameProc },
845 { "LoadSelectedProc", LoadSelectedProc },
846 { "ReloadGameProc", ReloadGameProc },
847 { "LoadPositionProc", LoadPositionProc },
848 { "LoadNextPositionProc", LoadNextPositionProc },
849 { "LoadPrevPositionProc", LoadPrevPositionProc },
850 { "ReloadPositionProc", ReloadPositionProc },
851 { "CopyPositionProc", CopyPositionProc },
852 { "PastePositionProc", PastePositionProc },
853 { "CopyGameProc", CopyGameProc },
854 { "PasteGameProc", PasteGameProc },
855 { "SaveGameProc", SaveGameProc },
856 { "SavePositionProc", SavePositionProc },
857 { "MailMoveProc", MailMoveProc },
858 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
859 { "QuitProc", QuitProc },
860 { "MachineWhiteProc", MachineWhiteProc },
861 { "MachineBlackProc", MachineBlackProc },
862 { "AnalysisModeProc", AnalyzeModeProc },
863 { "AnalyzeFileProc", AnalyzeFileProc },
864 { "TwoMachinesProc", TwoMachinesProc },
865 { "IcsClientProc", IcsClientProc },
866 { "EditGameProc", EditGameProc },
867 { "EditPositionProc", EditPositionProc },
868 { "TrainingProc", EditPositionProc },
869 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
870 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
871 { "ShowGameListProc", ShowGameListProc },
872 { "ShowMoveListProc", HistoryShowProc},
873 { "EditTagsProc", EditCommentProc },
874 { "EditCommentProc", EditCommentProc },
875 { "IcsAlarmProc", IcsAlarmProc },
876 { "IcsInputBoxProc", IcsInputBoxProc },
877 { "PauseProc", PauseProc },
878 { "AcceptProc", AcceptProc },
879 { "DeclineProc", DeclineProc },
880 { "RematchProc", RematchProc },
881 { "CallFlagProc", CallFlagProc },
882 { "DrawProc", DrawProc },
883 { "AdjournProc", AdjournProc },
884 { "AbortProc", AbortProc },
885 { "ResignProc", ResignProc },
886 { "AdjuWhiteProc", AdjuWhiteProc },
887 { "AdjuBlackProc", AdjuBlackProc },
888 { "AdjuDrawProc", AdjuDrawProc },
889 { "EnterKeyProc", EnterKeyProc },
890 { "StopObservingProc", StopObservingProc },
891 { "StopExaminingProc", StopExaminingProc },
892 { "BackwardProc", BackwardProc },
893 { "ForwardProc", ForwardProc },
894 { "ToStartProc", ToStartProc },
895 { "ToEndProc", ToEndProc },
896 { "RevertProc", RevertProc },
897 { "TruncateGameProc", TruncateGameProc },
898 { "MoveNowProc", MoveNowProc },
899 { "RetractMoveProc", RetractMoveProc },
900 { "AlwaysQueenProc", AlwaysQueenProc },
901 { "AnimateDraggingProc", AnimateDraggingProc },
902 { "AnimateMovingProc", AnimateMovingProc },
903 { "AutoflagProc", AutoflagProc },
904 { "AutoflipProc", AutoflipProc },
905 { "AutobsProc", AutobsProc },
906 { "AutoraiseProc", AutoraiseProc },
907 { "AutosaveProc", AutosaveProc },
908 { "BlindfoldProc", BlindfoldProc },
909 { "FlashMovesProc", FlashMovesProc },
910 { "FlipViewProc", FlipViewProc },
911 { "GetMoveListProc", GetMoveListProc },
913 { "HighlightDraggingProc", HighlightDraggingProc },
915 { "HighlightLastMoveProc", HighlightLastMoveProc },
916 { "IcsAlarmProc", IcsAlarmProc },
917 { "MoveSoundProc", MoveSoundProc },
918 { "OldSaveStyleProc", OldSaveStyleProc },
919 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
920 { "PonderNextMoveProc", PonderNextMoveProc },
921 { "PopupExitMessageProc", PopupExitMessageProc },
922 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
923 { "PremoveProc", PremoveProc },
924 { "QuietPlayProc", QuietPlayProc },
925 { "ShowCoordsProc", ShowCoordsProc },
926 { "ShowThinkingProc", ShowThinkingProc },
927 { "HideThinkingProc", HideThinkingProc },
928 { "TestLegalityProc", TestLegalityProc },
929 { "SaveSettingsProc", SaveSettingsProc },
930 { "SaveOnExitProc", SaveOnExitProc },
931 { "InfoProc", InfoProc },
932 { "ManProc", ManProc },
933 { "HintProc", HintProc },
934 { "BookProc", BookProc },
935 { "AboutGameProc", AboutGameProc },
936 { "AboutProc", AboutProc },
937 { "DebugProc", DebugProc },
938 { "NothingProc", NothingProc },
939 { "CommentPopDown", (XtActionProc) CommentPopDown },
940 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
941 { "TagsPopDown", (XtActionProc) TagsPopDown },
942 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
943 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
944 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
945 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
946 { "GameListPopDown", (XtActionProc) GameListPopDown },
947 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
948 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
949 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
950 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
951 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
952 { "EnginePopDown", (XtActionProc) EnginePopDown },
953 { "UciPopDown", (XtActionProc) UciPopDown },
954 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
955 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
956 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
959 char globalTranslations[] =
960 ":<Key>R: ResignProc() \n \
961 :<Key>r: ResetProc() \n \
962 :<Key>g: LoadGameProc() \n \
963 :<Key>N: LoadNextGameProc() \n \
964 :<Key>P: LoadPrevGameProc() \n \
965 :<Key>Q: QuitProc() \n \
966 :<Key>F: ToEndProc() \n \
967 :<Key>f: ForwardProc() \n \
968 :<Key>B: ToStartProc() \n \
969 :<Key>b: BackwardProc() \n \
970 :<Key>p: PauseProc() \n \
971 :<Key>d: DrawProc() \n \
972 :<Key>t: CallFlagProc() \n \
973 :<Key>i: Iconify() \n \
974 :<Key>c: Iconify() \n \
975 :<Key>v: FlipViewProc() \n \
976 <KeyDown>Control_L: BackwardProc() \n \
977 <KeyUp>Control_L: ForwardProc() \n \
978 <KeyDown>Control_R: BackwardProc() \n \
979 <KeyUp>Control_R: ForwardProc() \n \
980 Shift<Key>1: AskQuestionProc(\"Direct command\",\
981 \"Send to chess program:\",,1) \n \
982 Shift<Key>2: AskQuestionProc(\"Direct command\",\
983 \"Send to second chess program:\",,2) \n";
985 char boardTranslations[] =
986 "<Btn1Down>: HandleUserMove() \n \
987 <Btn1Up>: HandleUserMove() \n \
988 <Btn1Motion>: AnimateUserMove() \n \
989 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
990 PieceMenuPopup(menuB) \n \
991 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
992 PieceMenuPopup(menuW) \n \
993 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
994 PieceMenuPopup(menuW) \n \
995 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
996 PieceMenuPopup(menuB) \n";
998 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
999 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1001 char ICSInputTranslations[] =
1002 "<Key>Return: EnterKeyProc() \n";
1004 String xboardResources[] = {
1005 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1006 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1007 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1012 /* Max possible square size */
1013 #define MAXSQSIZE 256
1015 static int xpm_avail[MAXSQSIZE];
1017 #ifdef HAVE_DIR_STRUCT
1019 /* Extract piece size from filename */
1021 xpm_getsize(name, len, ext)
1032 if ((p=strchr(name, '.')) == NULL ||
1033 StrCaseCmp(p+1, ext) != 0)
1039 while (*p && isdigit(*p))
1046 /* Setup xpm_avail */
1048 xpm_getavail(dirname, ext)
1056 for (i=0; i<MAXSQSIZE; ++i)
1059 if (appData.debugMode)
1060 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1062 dir = opendir(dirname);
1065 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1066 programName, dirname);
1070 while ((ent=readdir(dir)) != NULL) {
1071 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1072 if (i > 0 && i < MAXSQSIZE)
1082 xpm_print_avail(fp, ext)
1088 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1089 for (i=1; i<MAXSQSIZE; ++i) {
1095 /* Return XPM piecesize closest to size */
1097 xpm_closest_to(dirname, size, ext)
1103 int sm_diff = MAXSQSIZE;
1107 xpm_getavail(dirname, ext);
1109 if (appData.debugMode)
1110 xpm_print_avail(stderr, ext);
1112 for (i=1; i<MAXSQSIZE; ++i) {
1115 diff = (diff<0) ? -diff : diff;
1116 if (diff < sm_diff) {
1124 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1130 #else /* !HAVE_DIR_STRUCT */
1131 /* If we are on a system without a DIR struct, we can't
1132 read the directory, so we can't collect a list of
1133 filenames, etc., so we can't do any size-fitting. */
1135 xpm_closest_to(dirname, size, ext)
1140 fprintf(stderr, _("\
1141 Warning: No DIR structure found on this system --\n\
1142 Unable to autosize for XPM/XIM pieces.\n\
1143 Please report this error to frankm@hiwaay.net.\n\
1144 Include system type & operating system in message.\n"));
1147 #endif /* HAVE_DIR_STRUCT */
1149 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1150 "magenta", "cyan", "white" };
1154 TextColors textColors[(int)NColorClasses];
1156 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1158 parse_color(str, which)
1162 char *p, buf[100], *d;
1165 if (strlen(str) > 99) /* watch bounds on buf */
1170 for (i=0; i<which; ++i) {
1177 /* Could be looking at something like:
1179 .. in which case we want to stop on a comma also */
1180 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1184 return -1; /* Use default for empty field */
1187 if (which == 2 || isdigit(*p))
1190 while (*p && isalpha(*p))
1195 for (i=0; i<8; ++i) {
1196 if (!StrCaseCmp(buf, cnames[i]))
1197 return which? (i+40) : (i+30);
1199 if (!StrCaseCmp(buf, "default")) return -1;
1201 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1206 parse_cpair(cc, str)
1210 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1211 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1216 /* bg and attr are optional */
1217 textColors[(int)cc].bg = parse_color(str, 1);
1218 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1219 textColors[(int)cc].attr = 0;
1225 /* Arrange to catch delete-window events */
1226 Atom wm_delete_window;
1228 CatchDeleteWindow(Widget w, String procname)
1231 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1232 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1233 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1240 XtSetArg(args[0], XtNiconic, False);
1241 XtSetValues(shellWidget, args, 1);
1243 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1246 //---------------------------------------------------------------------------------------------------------
1247 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1250 #define CW_USEDEFAULT (1<<31)
1251 #define ICS_TEXT_MENU_SIZE 90
1252 #define SetCurrentDirectory chdir
1253 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1257 // these two must some day move to frontend.h, when they are implemented
1258 Boolean MoveHistoryIsUp();
1259 Boolean GameListIsUp();
1261 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1264 // front-end part of option handling
1266 // [HGM] This platform-dependent table provides the location for storing the color info
1267 extern char *crWhite, * crBlack;
1271 &appData.whitePieceColor,
1272 &appData.blackPieceColor,
1273 &appData.lightSquareColor,
1274 &appData.darkSquareColor,
1275 &appData.highlightSquareColor,
1276 &appData.premoveHighlightColor,
1289 ParseFont(char *name, int number)
1290 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1292 case 0: // CLOCK_FONT
1293 appData.clockFont = strdup(name);
1295 case 1: // MESSAGE_FONT
1296 appData.font = strdup(name);
1298 case 2: // COORD_FONT
1299 appData.coordFont = strdup(name);
1308 { // only 2 fonts currently
1309 appData.clockFont = CLOCK_FONT_NAME;
1310 appData.coordFont = COORD_FONT_NAME;
1311 appData.font = DEFAULT_FONT_NAME;
1316 { // no-op, until we identify the code for this already in XBoard and move it here
1320 ParseColor(int n, char *name)
1321 { // in XBoard, just copy the color-name string
1322 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1326 ParseTextAttribs(ColorClass cc, char *s)
1328 (&appData.colorShout)[cc] = strdup(s);
1332 ParseBoardSize(void *addr, char *name)
1334 appData.boardSize = strdup(name);
1339 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1343 SetCommPortDefaults()
1344 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1347 // [HGM] args: these three cases taken out to stay in front-end
1349 SaveFontArg(FILE *f, ArgDescriptor *ad)
1352 switch((int)ad->argLoc) {
1353 case 0: // CLOCK_FONT
1354 name = appData.clockFont;
1356 case 1: // MESSAGE_FONT
1357 name = appData.font;
1359 case 2: // COORD_FONT
1360 name = appData.coordFont;
1365 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, name);
1370 { // nothing to do, as the sounds are at all times represented by their text-string names already
1374 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1375 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1376 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1380 SaveColor(FILE *f, ArgDescriptor *ad)
1381 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1382 if(colorVariable[(int)ad->argLoc])
1383 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1387 SaveBoardSize(FILE *f, char *name, void *addr)
1388 { // wrapper to shield back-end from BoardSize & sizeInfo
1389 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1393 ParseCommPortSettings(char *s)
1394 { // no such option in XBoard (yet)
1397 extern Widget engineOutputShell;
1398 extern Widget tagsShell, editTagsShell;
1400 GetActualPlacement(Widget wg, WindowPlacement *wp)
1410 XtSetArg(args[i], XtNx, &x); i++;
1411 XtSetArg(args[i], XtNy, &y); i++;
1412 XtSetArg(args[i], XtNwidth, &w); i++;
1413 XtSetArg(args[i], XtNheight, &h); i++;
1414 XtGetValues(wg, args, i);
1423 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1424 // In XBoard this will have to wait until awareness of window parameters is implemented
1425 GetActualPlacement(shellWidget, &wpMain);
1426 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1427 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1428 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1429 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1430 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1431 else GetActualPlacement(editShell, &wpComment);
1432 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1433 else GetActualPlacement(editTagsShell, &wpTags);
1437 PrintCommPortSettings(FILE *f, char *name)
1438 { // This option does not exist in XBoard
1442 MySearchPath(char *installDir, char *name, char *fullname)
1443 { // just append installDir and name. Perhaps ExpandPath should be used here?
1444 name = ExpandPathName(name);
1445 if(name && name[0] == '/') strcpy(fullname, name); else {
1446 sprintf(fullname, "%s%c%s", installDir, '/', name);
1452 MyGetFullPathName(char *name, char *fullname)
1453 { // should use ExpandPath?
1454 name = ExpandPathName(name);
1455 strcpy(fullname, name);
1460 EnsureOnScreen(int *x, int *y, int minX, int minY)
1467 { // [HGM] args: allows testing if main window is realized from back-end
1468 return xBoardWindow != 0;
1472 PopUpStartupDialog()
1473 { // start menu not implemented in XBoard
1476 ConvertToLine(int argc, char **argv)
1478 static char line[128*1024], buf[1024];
1482 for(i=1; i<argc; i++) {
1483 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1484 && argv[i][0] != '{' )
1485 sprintf(buf, "{%s} ", argv[i]);
1486 else sprintf(buf, "%s ", argv[i]);
1489 line[strlen(line)-1] = NULLCHAR;
1493 //--------------------------------------------------------------------------------------------
1496 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1498 #define BoardSize int
1499 void InitDrawingSizes(BoardSize boardSize, int flags)
1500 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1501 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1503 XtGeometryResult gres;
1506 if(!formWidget) return;
1509 * Enable shell resizing.
1511 shellArgs[0].value = (XtArgVal) &w;
1512 shellArgs[1].value = (XtArgVal) &h;
1513 XtGetValues(shellWidget, shellArgs, 2);
1515 shellArgs[4].value = 2*w; shellArgs[2].value = 10;
1516 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1517 XtSetValues(shellWidget, &shellArgs[2], 4);
1519 XtSetArg(args[0], XtNdefaultDistance, &sep);
1520 XtGetValues(formWidget, args, 1);
1522 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1523 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1526 XtSetArg(args[0], XtNwidth, boardWidth);
1527 XtSetArg(args[1], XtNheight, boardHeight);
1528 XtSetValues(boardWidget, args, 2);
1530 timerWidth = (boardWidth - sep) / 2;
1531 XtSetArg(args[0], XtNwidth, timerWidth);
1532 XtSetValues(whiteTimerWidget, args, 1);
1533 XtSetValues(blackTimerWidget, args, 1);
1535 XawFormDoLayout(formWidget, False);
1537 if (appData.titleInWindow) {
1539 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1540 XtSetArg(args[i], XtNheight, &h); i++;
1541 XtGetValues(titleWidget, args, i);
1543 w = boardWidth - 2*bor;
1545 XtSetArg(args[0], XtNwidth, &w);
1546 XtGetValues(menuBarWidget, args, 1);
1547 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1550 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1551 if (gres != XtGeometryYes && appData.debugMode) {
1553 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1554 programName, gres, w, h, wr, hr);
1558 XawFormDoLayout(formWidget, True);
1561 * Inhibit shell resizing.
1563 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW;
1564 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1565 shellArgs[4].value = shellArgs[2].value = w;
1566 shellArgs[5].value = shellArgs[3].value = h;
1567 XtSetValues(shellWidget, &shellArgs[0], 6);
1569 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1572 for(i=0; i<4; i++) {
1574 for(p=0; p<=(int)WhiteKing; p++)
1575 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1576 if(gameInfo.variant == VariantShogi) {
1577 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1578 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1579 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1580 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1581 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1584 if(gameInfo.variant == VariantGothic) {
1585 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1589 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1590 for(p=0; p<=(int)WhiteKing; p++)
1591 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1592 if(gameInfo.variant == VariantShogi) {
1593 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1594 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1595 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1596 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1597 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1600 if(gameInfo.variant == VariantGothic) {
1601 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1607 for(i=0; i<2; i++) {
1609 for(p=0; p<=(int)WhiteKing; p++)
1610 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1611 if(gameInfo.variant == VariantShogi) {
1612 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1613 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1614 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1615 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1616 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1619 if(gameInfo.variant == VariantGothic) {
1620 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1631 void EscapeExpand(char *p, char *q)
1632 { // [HGM] initstring: routine to shape up string arguments
1633 while(*p++ = *q++) if(p[-1] == '\\')
1635 case 'n': p[-1] = '\n'; break;
1636 case 'r': p[-1] = '\r'; break;
1637 case 't': p[-1] = '\t'; break;
1638 case '\\': p[-1] = '\\'; break;
1639 case 0: *p = 0; return;
1640 default: p[-1] = q[-1]; break;
1649 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1650 XSetWindowAttributes window_attributes;
1652 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1653 XrmValue vFrom, vTo;
1654 XtGeometryResult gres;
1657 int forceMono = False;
1658 //define INDIRECTION
1660 // [HGM] before anything else, expand any indirection files amongst options
1661 char *argvCopy[1000]; // 1000 seems enough
1662 char newArgs[10000]; // holds actual characters
1665 srandom(time(0)); // [HGM] book: make random truly random
1668 for(i=0; i<argc; i++) {
1669 if(j >= 1000-2) { printf(_("too many arguments\n")); exit(-1); }
1670 //fprintf(stderr, "arg %s\n", argv[i]);
1671 if(argv[i][0] != '@') argvCopy[j++] = argv[i]; else {
1673 FILE *f = fopen(argv[i]+1, "rb");
1674 if(f == NULL) { fprintf(stderr, _("ignore %s\n"), argv[i]); continue; } // do not expand non-existing
1675 argvCopy[j++] = newArgs + k; // get ready for first argument from file
1676 while((c = fgetc(f)) != EOF) { // each line of file inserts 1 argument in the list
1678 if(j >= 1000-2) { printf(_("too many arguments\n")); exit(-1); }
1679 newArgs[k++] = 0; // terminate current arg
1680 if(k >= 10000-1) { printf(_("too long arguments\n")); exit(-1); }
1681 argvCopy[j++] = newArgs + k; // get ready for next
1683 if(k >= 10000-1) { printf(_("too long arguments\n")); exit(-1); }
1697 setbuf(stdout, NULL);
1698 setbuf(stderr, NULL);
1701 programName = strrchr(argv[0], '/');
1702 if (programName == NULL)
1703 programName = argv[0];
1708 XtSetLanguageProc(NULL, NULL, NULL);
1709 bindtextdomain(PACKAGE, LOCALEDIR);
1710 textdomain(PACKAGE);
1714 XtAppInitialize(&appContext, "XBoard", shellOptions,
1715 XtNumber(shellOptions),
1716 &argc, argv, xboardResources, NULL, 0);
1717 appData.boardSize = "";
1718 InitAppData(ConvertToLine(argc, argv));
1720 if (p == NULL) p = "/tmp";
1721 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1722 gameCopyFilename = (char*) malloc(i);
1723 gamePasteFilename = (char*) malloc(i);
1724 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1725 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1727 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1728 clientResources, XtNumber(clientResources),
1731 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1732 static char buf[MSG_SIZ];
1733 EscapeExpand(buf, appData.initString);
1734 appData.initString = strdup(buf);
1735 EscapeExpand(buf, appData.secondInitString);
1736 appData.secondInitString = strdup(buf);
1737 EscapeExpand(buf, appData.firstComputerString);
1738 appData.firstComputerString = strdup(buf);
1739 EscapeExpand(buf, appData.secondComputerString);
1740 appData.secondComputerString = strdup(buf);
1743 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1746 if (chdir(chessDir) != 0) {
1747 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1753 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1754 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1755 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1756 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1759 setbuf(debugFP, NULL);
1762 /* [HGM,HR] make sure board size is acceptable */
1763 if(appData.NrFiles > BOARD_FILES ||
1764 appData.NrRanks > BOARD_RANKS )
1765 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1768 /* This feature does not work; animation needs a rewrite */
1769 appData.highlightDragging = FALSE;
1773 xDisplay = XtDisplay(shellWidget);
1774 xScreen = DefaultScreen(xDisplay);
1775 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1777 gameInfo.variant = StringToVariant(appData.variant);
1778 InitPosition(FALSE);
1781 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1783 if (isdigit(appData.boardSize[0])) {
1784 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1785 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1786 &fontPxlSize, &smallLayout, &tinyLayout);
1788 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1789 programName, appData.boardSize);
1793 /* Find some defaults; use the nearest known size */
1794 SizeDefaults *szd, *nearest;
1795 int distance = 99999;
1796 nearest = szd = sizeDefaults;
1797 while (szd->name != NULL) {
1798 if (abs(szd->squareSize - squareSize) < distance) {
1800 distance = abs(szd->squareSize - squareSize);
1801 if (distance == 0) break;
1805 if (i < 2) lineGap = nearest->lineGap;
1806 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1807 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1808 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1809 if (i < 6) smallLayout = nearest->smallLayout;
1810 if (i < 7) tinyLayout = nearest->tinyLayout;
1813 SizeDefaults *szd = sizeDefaults;
1814 if (*appData.boardSize == NULLCHAR) {
1815 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1816 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1819 if (szd->name == NULL) szd--;
1820 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1822 while (szd->name != NULL &&
1823 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1824 if (szd->name == NULL) {
1825 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1826 programName, appData.boardSize);
1830 squareSize = szd->squareSize;
1831 lineGap = szd->lineGap;
1832 clockFontPxlSize = szd->clockFontPxlSize;
1833 coordFontPxlSize = szd->coordFontPxlSize;
1834 fontPxlSize = szd->fontPxlSize;
1835 smallLayout = szd->smallLayout;
1836 tinyLayout = szd->tinyLayout;
1839 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1840 if (strlen(appData.pixmapDirectory) > 0) {
1841 p = ExpandPathName(appData.pixmapDirectory);
1843 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1844 appData.pixmapDirectory);
1847 if (appData.debugMode) {
1848 fprintf(stderr, _("\
1849 XBoard square size (hint): %d\n\
1850 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1852 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1853 if (appData.debugMode) {
1854 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1858 /* [HR] height treated separately (hacked) */
1859 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1860 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1861 if (appData.showJail == 1) {
1862 /* Jail on top and bottom */
1863 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1864 XtSetArg(boardArgs[2], XtNheight,
1865 boardHeight + 2*(lineGap + squareSize));
1866 } else if (appData.showJail == 2) {
1868 XtSetArg(boardArgs[1], XtNwidth,
1869 boardWidth + 2*(lineGap + squareSize));
1870 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1873 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1874 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1878 * Determine what fonts to use.
1880 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1881 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1882 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1883 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1884 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1885 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1886 appData.font = FindFont(appData.font, fontPxlSize);
1887 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1888 countFontStruct = XQueryFont(xDisplay, countFontID);
1889 // appData.font = FindFont(appData.font, fontPxlSize);
1891 xdb = XtDatabase(xDisplay);
1892 XrmPutStringResource(&xdb, "*font", appData.font);
1895 * Detect if there are not enough colors available and adapt.
1897 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1898 appData.monoMode = True;
1901 if (!appData.monoMode) {
1902 vFrom.addr = (caddr_t) appData.lightSquareColor;
1903 vFrom.size = strlen(appData.lightSquareColor);
1904 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1905 if (vTo.addr == NULL) {
1906 appData.monoMode = True;
1909 lightSquareColor = *(Pixel *) vTo.addr;
1912 if (!appData.monoMode) {
1913 vFrom.addr = (caddr_t) appData.darkSquareColor;
1914 vFrom.size = strlen(appData.darkSquareColor);
1915 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1916 if (vTo.addr == NULL) {
1917 appData.monoMode = True;
1920 darkSquareColor = *(Pixel *) vTo.addr;
1923 if (!appData.monoMode) {
1924 vFrom.addr = (caddr_t) appData.whitePieceColor;
1925 vFrom.size = strlen(appData.whitePieceColor);
1926 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1927 if (vTo.addr == NULL) {
1928 appData.monoMode = True;
1931 whitePieceColor = *(Pixel *) vTo.addr;
1934 if (!appData.monoMode) {
1935 vFrom.addr = (caddr_t) appData.blackPieceColor;
1936 vFrom.size = strlen(appData.blackPieceColor);
1937 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1938 if (vTo.addr == NULL) {
1939 appData.monoMode = True;
1942 blackPieceColor = *(Pixel *) vTo.addr;
1946 if (!appData.monoMode) {
1947 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1948 vFrom.size = strlen(appData.highlightSquareColor);
1949 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1950 if (vTo.addr == NULL) {
1951 appData.monoMode = True;
1954 highlightSquareColor = *(Pixel *) vTo.addr;
1958 if (!appData.monoMode) {
1959 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1960 vFrom.size = strlen(appData.premoveHighlightColor);
1961 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1962 if (vTo.addr == NULL) {
1963 appData.monoMode = True;
1966 premoveHighlightColor = *(Pixel *) vTo.addr;
1971 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1974 if (appData.bitmapDirectory == NULL ||
1975 appData.bitmapDirectory[0] == NULLCHAR)
1976 appData.bitmapDirectory = DEF_BITMAP_DIR;
1979 if (appData.lowTimeWarning && !appData.monoMode) {
1980 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
1981 vFrom.size = strlen(appData.lowTimeWarningColor);
1982 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1983 if (vTo.addr == NULL)
1984 appData.monoMode = True;
1986 lowTimeWarningColor = *(Pixel *) vTo.addr;
1989 if (appData.monoMode && appData.debugMode) {
1990 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1991 (unsigned long) XWhitePixel(xDisplay, xScreen),
1992 (unsigned long) XBlackPixel(xDisplay, xScreen));
1995 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1996 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1997 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1998 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1999 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2000 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2001 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2002 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2003 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2004 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2006 if (appData.colorize) {
2008 _("%s: can't parse color names; disabling colorization\n"),
2011 appData.colorize = FALSE;
2013 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2014 textColors[ColorNone].attr = 0;
2016 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2022 layoutName = "tinyLayout";
2023 } else if (smallLayout) {
2024 layoutName = "smallLayout";
2026 layoutName = "normalLayout";
2028 /* Outer layoutWidget is there only to provide a name for use in
2029 resources that depend on the layout style */
2031 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2032 layoutArgs, XtNumber(layoutArgs));
2034 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2035 formArgs, XtNumber(formArgs));
2036 XtSetArg(args[0], XtNdefaultDistance, &sep);
2037 XtGetValues(formWidget, args, 1);
2040 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2041 XtSetArg(args[0], XtNtop, XtChainTop);
2042 XtSetArg(args[1], XtNbottom, XtChainTop);
2043 XtSetArg(args[2], XtNright, XtChainLeft);
2044 XtSetValues(menuBarWidget, args, 3);
2046 widgetList[j++] = whiteTimerWidget =
2047 XtCreateWidget("whiteTime", labelWidgetClass,
2048 formWidget, timerArgs, XtNumber(timerArgs));
2049 XtSetArg(args[0], XtNfont, clockFontStruct);
2050 XtSetArg(args[1], XtNtop, XtChainTop);
2051 XtSetArg(args[2], XtNbottom, XtChainTop);
2052 XtSetValues(whiteTimerWidget, args, 3);
2054 widgetList[j++] = blackTimerWidget =
2055 XtCreateWidget("blackTime", labelWidgetClass,
2056 formWidget, timerArgs, XtNumber(timerArgs));
2057 XtSetArg(args[0], XtNfont, clockFontStruct);
2058 XtSetArg(args[1], XtNtop, XtChainTop);
2059 XtSetArg(args[2], XtNbottom, XtChainTop);
2060 XtSetValues(blackTimerWidget, args, 3);
2062 if (appData.titleInWindow) {
2063 widgetList[j++] = titleWidget =
2064 XtCreateWidget("title", labelWidgetClass, formWidget,
2065 titleArgs, XtNumber(titleArgs));
2066 XtSetArg(args[0], XtNtop, XtChainTop);
2067 XtSetArg(args[1], XtNbottom, XtChainTop);
2068 XtSetValues(titleWidget, args, 2);
2071 if (appData.showButtonBar) {
2072 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2073 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2074 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2075 XtSetArg(args[2], XtNtop, XtChainTop);
2076 XtSetArg(args[3], XtNbottom, XtChainTop);
2077 XtSetValues(buttonBarWidget, args, 4);
2080 widgetList[j++] = messageWidget =
2081 XtCreateWidget("message", labelWidgetClass, formWidget,
2082 messageArgs, XtNumber(messageArgs));
2083 XtSetArg(args[0], XtNtop, XtChainTop);
2084 XtSetArg(args[1], XtNbottom, XtChainTop);
2085 XtSetValues(messageWidget, args, 2);
2087 widgetList[j++] = boardWidget =
2088 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2089 XtNumber(boardArgs));
2091 XtManageChildren(widgetList, j);
2093 timerWidth = (boardWidth - sep) / 2;
2094 XtSetArg(args[0], XtNwidth, timerWidth);
2095 XtSetValues(whiteTimerWidget, args, 1);
2096 XtSetValues(blackTimerWidget, args, 1);
2098 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2099 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2100 XtGetValues(whiteTimerWidget, args, 2);
2102 if (appData.showButtonBar) {
2103 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2104 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2105 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2109 * formWidget uses these constraints but they are stored
2113 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2114 XtSetValues(menuBarWidget, args, i);
2115 if (appData.titleInWindow) {
2118 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2119 XtSetValues(whiteTimerWidget, args, i);
2121 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2122 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2123 XtSetValues(blackTimerWidget, args, i);
2125 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2126 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2127 XtSetValues(titleWidget, args, i);
2129 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2130 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2131 XtSetValues(messageWidget, args, i);
2132 if (appData.showButtonBar) {
2134 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2135 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2136 XtSetValues(buttonBarWidget, args, i);
2140 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2141 XtSetValues(whiteTimerWidget, args, i);
2143 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2144 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2145 XtSetValues(blackTimerWidget, args, i);
2147 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2148 XtSetValues(titleWidget, args, i);
2150 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2151 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2152 XtSetValues(messageWidget, args, i);
2153 if (appData.showButtonBar) {
2155 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2156 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2157 XtSetValues(buttonBarWidget, args, i);
2162 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2163 XtSetValues(whiteTimerWidget, args, i);
2165 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2166 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2167 XtSetValues(blackTimerWidget, args, i);
2169 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2170 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2171 XtSetValues(messageWidget, args, i);
2172 if (appData.showButtonBar) {
2174 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2175 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2176 XtSetValues(buttonBarWidget, args, i);
2180 XtSetArg(args[0], XtNfromVert, messageWidget);
2181 XtSetArg(args[1], XtNtop, XtChainTop);
2182 XtSetArg(args[2], XtNbottom, XtChainBottom);
2183 XtSetArg(args[3], XtNleft, XtChainLeft);
2184 XtSetArg(args[4], XtNright, XtChainRight);
2185 XtSetValues(boardWidget, args, 5);
2187 XtRealizeWidget(shellWidget);
2190 XtSetArg(args[0], XtNx, wpMain.x);
2191 XtSetArg(args[1], XtNy, wpMain.y);
2192 XtSetValues(shellWidget, args, 2);
2196 * Correct the width of the message and title widgets.
2197 * It is not known why some systems need the extra fudge term.
2198 * The value "2" is probably larger than needed.
2200 XawFormDoLayout(formWidget, False);
2202 #define WIDTH_FUDGE 2
2204 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2205 XtSetArg(args[i], XtNheight, &h); i++;
2206 XtGetValues(messageWidget, args, i);
2207 if (appData.showButtonBar) {
2209 XtSetArg(args[i], XtNwidth, &w); i++;
2210 XtGetValues(buttonBarWidget, args, i);
2211 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2213 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2216 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2217 if (gres != XtGeometryYes && appData.debugMode) {
2218 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2219 programName, gres, w, h, wr, hr);
2222 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2223 /* The size used for the child widget in layout lags one resize behind
2224 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2226 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2227 if (gres != XtGeometryYes && appData.debugMode) {
2228 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2229 programName, gres, w, h, wr, hr);
2232 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2233 XtSetArg(args[1], XtNright, XtChainRight);
2234 XtSetValues(messageWidget, args, 2);
2236 if (appData.titleInWindow) {
2238 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2239 XtSetArg(args[i], XtNheight, &h); i++;
2240 XtGetValues(titleWidget, args, i);
2242 w = boardWidth - 2*bor;
2244 XtSetArg(args[0], XtNwidth, &w);
2245 XtGetValues(menuBarWidget, args, 1);
2246 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2249 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2250 if (gres != XtGeometryYes && appData.debugMode) {
2252 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2253 programName, gres, w, h, wr, hr);
2256 XawFormDoLayout(formWidget, True);
2258 xBoardWindow = XtWindow(boardWidget);
2260 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2261 // not need to go into InitDrawingSizes().
2265 * Create X checkmark bitmap and initialize option menu checks.
2267 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2268 checkmark_bits, checkmark_width, checkmark_height);
2269 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2270 if (appData.alwaysPromoteToQueen) {
2271 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2274 if (appData.animateDragging) {
2275 XtSetValues(XtNameToWidget(menuBarWidget,
2276 "menuOptions.Animate Dragging"),
2279 if (appData.animate) {
2280 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2283 if (appData.autoComment) {
2284 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2287 if (appData.autoCallFlag) {
2288 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2291 if (appData.autoFlipView) {
2292 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2295 if (appData.autoObserve) {
2296 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2299 if (appData.autoRaiseBoard) {
2300 XtSetValues(XtNameToWidget(menuBarWidget,
2301 "menuOptions.Auto Raise Board"), args, 1);
2303 if (appData.autoSaveGames) {
2304 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2307 if (appData.saveGameFile[0] != NULLCHAR) {
2308 /* Can't turn this off from menu */
2309 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2311 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2315 if (appData.blindfold) {
2316 XtSetValues(XtNameToWidget(menuBarWidget,
2317 "menuOptions.Blindfold"), args, 1);
2319 if (appData.flashCount > 0) {
2320 XtSetValues(XtNameToWidget(menuBarWidget,
2321 "menuOptions.Flash Moves"),
2324 if (appData.getMoveList) {
2325 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2329 if (appData.highlightDragging) {
2330 XtSetValues(XtNameToWidget(menuBarWidget,
2331 "menuOptions.Highlight Dragging"),
2335 if (appData.highlightLastMove) {
2336 XtSetValues(XtNameToWidget(menuBarWidget,
2337 "menuOptions.Highlight Last Move"),
2340 if (appData.icsAlarm) {
2341 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2344 if (appData.ringBellAfterMoves) {
2345 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2348 if (appData.oldSaveStyle) {
2349 XtSetValues(XtNameToWidget(menuBarWidget,
2350 "menuOptions.Old Save Style"), args, 1);
2352 if (appData.periodicUpdates) {
2353 XtSetValues(XtNameToWidget(menuBarWidget,
2354 "menuOptions.Periodic Updates"), args, 1);
2356 if (appData.ponderNextMove) {
2357 XtSetValues(XtNameToWidget(menuBarWidget,
2358 "menuOptions.Ponder Next Move"), args, 1);
2360 if (appData.popupExitMessage) {
2361 XtSetValues(XtNameToWidget(menuBarWidget,
2362 "menuOptions.Popup Exit Message"), args, 1);
2364 if (appData.popupMoveErrors) {
2365 XtSetValues(XtNameToWidget(menuBarWidget,
2366 "menuOptions.Popup Move Errors"), args, 1);
2368 if (appData.premove) {
2369 XtSetValues(XtNameToWidget(menuBarWidget,
2370 "menuOptions.Premove"), args, 1);
2372 if (appData.quietPlay) {
2373 XtSetValues(XtNameToWidget(menuBarWidget,
2374 "menuOptions.Quiet Play"), args, 1);
2376 if (appData.showCoords) {
2377 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2380 if (appData.hideThinkingFromHuman) {
2381 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2384 if (appData.testLegality) {
2385 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2388 if (saveSettingsOnExit) {
2389 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2396 ReadBitmap(&wIconPixmap, "icon_white.bm",
2397 icon_white_bits, icon_white_width, icon_white_height);
2398 ReadBitmap(&bIconPixmap, "icon_black.bm",
2399 icon_black_bits, icon_black_width, icon_black_height);
2400 iconPixmap = wIconPixmap;
2402 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2403 XtSetValues(shellWidget, args, i);
2406 * Create a cursor for the board widget.
2408 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2409 XChangeWindowAttributes(xDisplay, xBoardWindow,
2410 CWCursor, &window_attributes);
2413 * Inhibit shell resizing.
2415 shellArgs[0].value = (XtArgVal) &w;
2416 shellArgs[1].value = (XtArgVal) &h;
2417 XtGetValues(shellWidget, shellArgs, 2);
2418 shellArgs[4].value = shellArgs[2].value = w;
2419 shellArgs[5].value = shellArgs[3].value = h;
2420 XtSetValues(shellWidget, &shellArgs[2], 4);
2421 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2422 marginH = h - boardHeight;
2424 CatchDeleteWindow(shellWidget, "QuitProc");
2429 if (appData.bitmapDirectory[0] != NULLCHAR) {
2436 /* Create regular pieces */
2437 if (!useImages) CreatePieces();
2442 if (appData.animate || appData.animateDragging)
2445 XtAugmentTranslations(formWidget,
2446 XtParseTranslationTable(globalTranslations));
2447 XtAugmentTranslations(boardWidget,
2448 XtParseTranslationTable(boardTranslations));
2449 XtAugmentTranslations(whiteTimerWidget,
2450 XtParseTranslationTable(whiteTranslations));
2451 XtAugmentTranslations(blackTimerWidget,
2452 XtParseTranslationTable(blackTranslations));
2454 /* Why is the following needed on some versions of X instead
2455 * of a translation? */
2456 XtAddEventHandler(boardWidget, ExposureMask, False,
2457 (XtEventHandler) EventProc, NULL);
2460 /* [AS] Restore layout */
2461 if( wpMoveHistory.visible ) {
2465 if( wpEvalGraph.visible )
2470 if( wpEngineOutput.visible ) {
2471 EngineOutputPopUp();
2476 if (errorExitStatus == -1) {
2477 if (appData.icsActive) {
2478 /* We now wait until we see "login:" from the ICS before
2479 sending the logon script (problems with timestamp otherwise) */
2480 /*ICSInitScript();*/
2481 if (appData.icsInputBox) ICSInputBoxPopUp();
2485 signal(SIGWINCH, TermSizeSigHandler);
2487 signal(SIGINT, IntSigHandler);
2488 signal(SIGTERM, IntSigHandler);
2489 if (*appData.cmailGameName != NULLCHAR) {
2490 signal(SIGUSR1, CmailSigHandler);
2493 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2496 XtAppMainLoop(appContext);
2497 if (appData.debugMode) fclose(debugFP); // [DM] debug
2504 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2505 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2507 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2508 unlink(gameCopyFilename);
2509 unlink(gamePasteFilename);
2512 RETSIGTYPE TermSizeSigHandler(int sig)
2525 CmailSigHandler(sig)
2531 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2533 /* Activate call-back function CmailSigHandlerCallBack() */
2534 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2536 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2540 CmailSigHandlerCallBack(isr, closure, message, count, error)
2548 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2550 /**** end signal code ****/
2560 f = fopen(appData.icsLogon, "r");
2566 strcat(buf, appData.icsLogon);
2567 f = fopen(buf, "r");
2571 ProcessICSInitScript(f);
2578 EditCommentPopDown();
2593 if (!menuBarWidget) return;
2594 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2596 DisplayError("menuStep.Revert", 0);
2598 XtSetSensitive(w, !grey);
2603 SetMenuEnables(enab)
2607 if (!menuBarWidget) return;
2608 while (enab->name != NULL) {
2609 w = XtNameToWidget(menuBarWidget, enab->name);
2611 DisplayError(enab->name, 0);
2613 XtSetSensitive(w, enab->value);
2619 Enables icsEnables[] = {
2620 { "menuFile.Mail Move", False },
2621 { "menuFile.Reload CMail Message", False },
2622 { "menuMode.Machine Black", False },
2623 { "menuMode.Machine White", False },
2624 { "menuMode.Analysis Mode", False },
2625 { "menuMode.Analyze File", False },
2626 { "menuMode.Two Machines", False },
2628 { "menuHelp.Hint", False },
2629 { "menuHelp.Book", False },
2630 { "menuStep.Move Now", False },
2631 { "menuOptions.Periodic Updates", False },
2632 { "menuOptions.Hide Thinking", False },
2633 { "menuOptions.Ponder Next Move", False },
2638 Enables ncpEnables[] = {
2639 { "menuFile.Mail Move", False },
2640 { "menuFile.Reload CMail Message", False },
2641 { "menuMode.Machine White", False },
2642 { "menuMode.Machine Black", False },
2643 { "menuMode.Analysis Mode", False },
2644 { "menuMode.Analyze File", False },
2645 { "menuMode.Two Machines", False },
2646 { "menuMode.ICS Client", False },
2647 { "menuMode.ICS Input Box", False },
2648 { "Action", False },
2649 { "menuStep.Revert", False },
2650 { "menuStep.Move Now", False },
2651 { "menuStep.Retract Move", False },
2652 { "menuOptions.Auto Comment", False },
2653 { "menuOptions.Auto Flag", False },
2654 { "menuOptions.Auto Flip View", False },
2655 { "menuOptions.Auto Observe", False },
2656 { "menuOptions.Auto Raise Board", False },
2657 { "menuOptions.Get Move List", False },
2658 { "menuOptions.ICS Alarm", False },
2659 { "menuOptions.Move Sound", False },
2660 { "menuOptions.Quiet Play", False },
2661 { "menuOptions.Hide Thinking", False },
2662 { "menuOptions.Periodic Updates", False },
2663 { "menuOptions.Ponder Next Move", False },
2664 { "menuHelp.Hint", False },
2665 { "menuHelp.Book", False },
2669 Enables gnuEnables[] = {
2670 { "menuMode.ICS Client", False },
2671 { "menuMode.ICS Input Box", False },
2672 { "menuAction.Accept", False },
2673 { "menuAction.Decline", False },
2674 { "menuAction.Rematch", False },
2675 { "menuAction.Adjourn", False },
2676 { "menuAction.Stop Examining", False },
2677 { "menuAction.Stop Observing", False },
2678 { "menuStep.Revert", False },
2679 { "menuOptions.Auto Comment", False },
2680 { "menuOptions.Auto Observe", False },
2681 { "menuOptions.Auto Raise Board", False },
2682 { "menuOptions.Get Move List", False },
2683 { "menuOptions.Premove", False },
2684 { "menuOptions.Quiet Play", False },
2686 /* The next two options rely on SetCmailMode being called *after* */
2687 /* SetGNUMode so that when GNU is being used to give hints these */
2688 /* menu options are still available */
2690 { "menuFile.Mail Move", False },
2691 { "menuFile.Reload CMail Message", False },
2695 Enables cmailEnables[] = {
2697 { "menuAction.Call Flag", False },
2698 { "menuAction.Draw", True },
2699 { "menuAction.Adjourn", False },
2700 { "menuAction.Abort", False },
2701 { "menuAction.Stop Observing", False },
2702 { "menuAction.Stop Examining", False },
2703 { "menuFile.Mail Move", True },
2704 { "menuFile.Reload CMail Message", True },
2708 Enables trainingOnEnables[] = {
2709 { "menuMode.Edit Comment", False },
2710 { "menuMode.Pause", False },
2711 { "menuStep.Forward", False },
2712 { "menuStep.Backward", False },
2713 { "menuStep.Forward to End", False },
2714 { "menuStep.Back to Start", False },
2715 { "menuStep.Move Now", False },
2716 { "menuStep.Truncate Game", False },
2720 Enables trainingOffEnables[] = {
2721 { "menuMode.Edit Comment", True },
2722 { "menuMode.Pause", True },
2723 { "menuStep.Forward", True },
2724 { "menuStep.Backward", True },
2725 { "menuStep.Forward to End", True },
2726 { "menuStep.Back to Start", True },
2727 { "menuStep.Move Now", True },
2728 { "menuStep.Truncate Game", True },
2732 Enables machineThinkingEnables[] = {
2733 { "menuFile.Load Game", False },
2734 { "menuFile.Load Next Game", False },
2735 { "menuFile.Load Previous Game", False },
2736 { "menuFile.Reload Same Game", False },
2737 { "menuFile.Paste Game", False },
2738 { "menuFile.Load Position", False },
2739 { "menuFile.Load Next Position", False },
2740 { "menuFile.Load Previous Position", False },
2741 { "menuFile.Reload Same Position", False },
2742 { "menuFile.Paste Position", False },
2743 { "menuMode.Machine White", False },
2744 { "menuMode.Machine Black", False },
2745 { "menuMode.Two Machines", False },
2746 { "menuStep.Retract Move", False },
2750 Enables userThinkingEnables[] = {
2751 { "menuFile.Load Game", True },
2752 { "menuFile.Load Next Game", True },
2753 { "menuFile.Load Previous Game", True },
2754 { "menuFile.Reload Same Game", True },
2755 { "menuFile.Paste Game", True },
2756 { "menuFile.Load Position", True },
2757 { "menuFile.Load Next Position", True },
2758 { "menuFile.Load Previous Position", True },
2759 { "menuFile.Reload Same Position", True },
2760 { "menuFile.Paste Position", True },
2761 { "menuMode.Machine White", True },
2762 { "menuMode.Machine Black", True },
2763 { "menuMode.Two Machines", True },
2764 { "menuStep.Retract Move", True },
2770 SetMenuEnables(icsEnables);
2773 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2774 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2781 SetMenuEnables(ncpEnables);
2787 SetMenuEnables(gnuEnables);
2793 SetMenuEnables(cmailEnables);
2799 SetMenuEnables(trainingOnEnables);
2800 if (appData.showButtonBar) {
2801 XtSetSensitive(buttonBarWidget, False);
2807 SetTrainingModeOff()
2809 SetMenuEnables(trainingOffEnables);
2810 if (appData.showButtonBar) {
2811 XtSetSensitive(buttonBarWidget, True);
2816 SetUserThinkingEnables()
2818 if (appData.noChessProgram) return;
2819 SetMenuEnables(userThinkingEnables);
2823 SetMachineThinkingEnables()
2825 if (appData.noChessProgram) return;
2826 SetMenuEnables(machineThinkingEnables);
2828 case MachinePlaysBlack:
2829 case MachinePlaysWhite:
2830 case TwoMachinesPlay:
2831 XtSetSensitive(XtNameToWidget(menuBarWidget,
2832 ModeToWidgetName(gameMode)), True);
2839 #define Abs(n) ((n)<0 ? -(n) : (n))
2842 * Find a font that matches "pattern" that is as close as
2843 * possible to the targetPxlSize. Prefer fonts that are k
2844 * pixels smaller to fonts that are k pixels larger. The
2845 * pattern must be in the X Consortium standard format,
2846 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2847 * The return value should be freed with XtFree when no
2850 char *FindFont(pattern, targetPxlSize)
2854 char **fonts, *p, *best, *scalable, *scalableTail;
2855 int i, j, nfonts, minerr, err, pxlSize;
2858 char **missing_list;
2860 char *def_string, *base_fnt_lst, strInt[3];
2862 XFontStruct **fnt_list;
2864 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2865 sprintf(strInt, "%d", targetPxlSize);
2866 p = strstr(pattern, "--");
2867 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2868 strcat(base_fnt_lst, strInt);
2869 strcat(base_fnt_lst, strchr(p + 2, '-'));
2871 if ((fntSet = XCreateFontSet(xDisplay,
2875 &def_string)) == NULL) {
2877 fprintf(stderr, _("Unable to create font set.\n"));
2881 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2883 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2885 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2886 programName, pattern);
2894 for (i=0; i<nfonts; i++) {
2897 if (*p != '-') continue;
2899 if (*p == NULLCHAR) break;
2900 if (*p++ == '-') j++;
2902 if (j < 7) continue;
2905 scalable = fonts[i];
2908 err = pxlSize - targetPxlSize;
2909 if (Abs(err) < Abs(minerr) ||
2910 (minerr > 0 && err < 0 && -err == minerr)) {
2916 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
2917 /* If the error is too big and there is a scalable font,
2918 use the scalable font. */
2919 int headlen = scalableTail - scalable;
2920 p = (char *) XtMalloc(strlen(scalable) + 10);
2921 while (isdigit(*scalableTail)) scalableTail++;
2922 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
2924 p = (char *) XtMalloc(strlen(best) + 1);
2927 if (appData.debugMode) {
2928 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
2929 pattern, targetPxlSize, p);
2932 if (missing_count > 0)
2933 XFreeStringList(missing_list);
2934 XFreeFontSet(xDisplay, fntSet);
2936 XFreeFontNames(fonts);
2943 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
2944 | GCBackground | GCFunction | GCPlaneMask;
2945 XGCValues gc_values;
2948 gc_values.plane_mask = AllPlanes;
2949 gc_values.line_width = lineGap;
2950 gc_values.line_style = LineSolid;
2951 gc_values.function = GXcopy;
2953 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2954 gc_values.background = XBlackPixel(xDisplay, xScreen);
2955 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2957 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2958 gc_values.background = XWhitePixel(xDisplay, xScreen);
2959 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
2960 XSetFont(xDisplay, coordGC, coordFontID);
2962 // [HGM] make font for holdings counts (white on black0
2963 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2964 gc_values.background = XBlackPixel(xDisplay, xScreen);
2965 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
2966 XSetFont(xDisplay, countGC, countFontID);
2968 if (appData.monoMode) {
2969 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2970 gc_values.background = XWhitePixel(xDisplay, xScreen);
2971 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2973 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2974 gc_values.background = XBlackPixel(xDisplay, xScreen);
2975 lightSquareGC = wbPieceGC
2976 = XtGetGC(shellWidget, value_mask, &gc_values);
2978 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2979 gc_values.background = XWhitePixel(xDisplay, xScreen);
2980 darkSquareGC = bwPieceGC
2981 = XtGetGC(shellWidget, value_mask, &gc_values);
2983 if (DefaultDepth(xDisplay, xScreen) == 1) {
2984 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
2985 gc_values.function = GXcopyInverted;
2986 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
2987 gc_values.function = GXcopy;
2988 if (XBlackPixel(xDisplay, xScreen) == 1) {
2989 bwPieceGC = darkSquareGC;
2990 wbPieceGC = copyInvertedGC;
2992 bwPieceGC = copyInvertedGC;
2993 wbPieceGC = lightSquareGC;
2997 gc_values.foreground = highlightSquareColor;
2998 gc_values.background = highlightSquareColor;
2999 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3001 gc_values.foreground = premoveHighlightColor;
3002 gc_values.background = premoveHighlightColor;
3003 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3005 gc_values.foreground = lightSquareColor;
3006 gc_values.background = darkSquareColor;
3007 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3009 gc_values.foreground = darkSquareColor;
3010 gc_values.background = lightSquareColor;
3011 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3013 gc_values.foreground = jailSquareColor;
3014 gc_values.background = jailSquareColor;
3015 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3017 gc_values.foreground = whitePieceColor;
3018 gc_values.background = darkSquareColor;
3019 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3021 gc_values.foreground = whitePieceColor;
3022 gc_values.background = lightSquareColor;
3023 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3025 gc_values.foreground = whitePieceColor;
3026 gc_values.background = jailSquareColor;
3027 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3029 gc_values.foreground = blackPieceColor;
3030 gc_values.background = darkSquareColor;
3031 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3033 gc_values.foreground = blackPieceColor;
3034 gc_values.background = lightSquareColor;
3035 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3037 gc_values.foreground = blackPieceColor;
3038 gc_values.background = jailSquareColor;
3039 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3043 void loadXIM(xim, xmask, filename, dest, mask)
3056 fp = fopen(filename, "rb");
3058 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3065 for (y=0; y<h; ++y) {
3066 for (x=0; x<h; ++x) {
3071 XPutPixel(xim, x, y, blackPieceColor);
3073 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3076 XPutPixel(xim, x, y, darkSquareColor);
3078 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3081 XPutPixel(xim, x, y, whitePieceColor);
3083 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3086 XPutPixel(xim, x, y, lightSquareColor);
3088 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3094 /* create Pixmap of piece */
3095 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3097 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3100 /* create Pixmap of clipmask
3101 Note: We assume the white/black pieces have the same
3102 outline, so we make only 6 masks. This is okay
3103 since the XPM clipmask routines do the same. */
3105 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3107 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3110 /* now create the 1-bit version */
3111 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3114 values.foreground = 1;
3115 values.background = 0;
3117 /* Don't use XtGetGC, not read only */
3118 maskGC = XCreateGC(xDisplay, *mask,
3119 GCForeground | GCBackground, &values);
3120 XCopyPlane(xDisplay, temp, *mask, maskGC,
3121 0, 0, squareSize, squareSize, 0, 0, 1);
3122 XFreePixmap(xDisplay, temp);
3127 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3129 void CreateXIMPieces()
3134 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3139 /* The XSynchronize calls were copied from CreatePieces.
3140 Not sure if needed, but can't hurt */
3141 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3144 /* temp needed by loadXIM() */
3145 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3146 0, 0, ss, ss, AllPlanes, XYPixmap);
3148 if (strlen(appData.pixmapDirectory) == 0) {
3152 if (appData.monoMode) {
3153 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3157 fprintf(stderr, _("\nLoading XIMs...\n"));
3159 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3160 fprintf(stderr, "%d", piece+1);
3161 for (kind=0; kind<4; kind++) {
3162 fprintf(stderr, ".");
3163 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3164 ExpandPathName(appData.pixmapDirectory),
3165 piece <= (int) WhiteKing ? "" : "w",
3166 pieceBitmapNames[piece],
3168 ximPieceBitmap[kind][piece] =
3169 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3170 0, 0, ss, ss, AllPlanes, XYPixmap);
3171 if (appData.debugMode)
3172 fprintf(stderr, _("(File:%s:) "), buf);
3173 loadXIM(ximPieceBitmap[kind][piece],
3175 &(xpmPieceBitmap2[kind][piece]),
3176 &(ximMaskPm2[piece]));
3177 if(piece <= (int)WhiteKing)
3178 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3180 fprintf(stderr," ");
3182 /* Load light and dark squares */
3183 /* If the LSQ and DSQ pieces don't exist, we will
3184 draw them with solid squares. */
3185 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3186 if (access(buf, 0) != 0) {
3190 fprintf(stderr, _("light square "));
3192 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3193 0, 0, ss, ss, AllPlanes, XYPixmap);
3194 if (appData.debugMode)
3195 fprintf(stderr, _("(File:%s:) "), buf);
3197 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3198 fprintf(stderr, _("dark square "));
3199 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3200 ExpandPathName(appData.pixmapDirectory), ss);
3201 if (appData.debugMode)
3202 fprintf(stderr, _("(File:%s:) "), buf);
3204 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3205 0, 0, ss, ss, AllPlanes, XYPixmap);
3206 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3207 xpmJailSquare = xpmLightSquare;
3209 fprintf(stderr, _("Done.\n"));
3211 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3215 void CreateXPMPieces()
3219 u_int ss = squareSize;
3221 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3222 XpmColorSymbol symbols[4];
3224 /* The XSynchronize calls were copied from CreatePieces.
3225 Not sure if needed, but can't hurt */
3226 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3228 /* Setup translations so piece colors match square colors */
3229 symbols[0].name = "light_piece";
3230 symbols[0].value = appData.whitePieceColor;
3231 symbols[1].name = "dark_piece";
3232 symbols[1].value = appData.blackPieceColor;
3233 symbols[2].name = "light_square";
3234 symbols[2].value = appData.lightSquareColor;
3235 symbols[3].name = "dark_square";
3236 symbols[3].value = appData.darkSquareColor;
3238 attr.valuemask = XpmColorSymbols;
3239 attr.colorsymbols = symbols;
3240 attr.numsymbols = 4;
3242 if (appData.monoMode) {
3243 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3247 if (strlen(appData.pixmapDirectory) == 0) {
3248 XpmPieces* pieces = builtInXpms;
3251 while (pieces->size != squareSize && pieces->size) pieces++;
3252 if (!pieces->size) {
3253 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3256 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3257 for (kind=0; kind<4; kind++) {
3259 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3260 pieces->xpm[piece][kind],
3261 &(xpmPieceBitmap2[kind][piece]),
3262 NULL, &attr)) != 0) {
3263 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3267 if(piece <= (int) WhiteKing)
3268 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3272 xpmJailSquare = xpmLightSquare;
3276 fprintf(stderr, _("\nLoading XPMs...\n"));
3279 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3280 fprintf(stderr, "%d ", piece+1);
3281 for (kind=0; kind<4; kind++) {
3282 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3283 ExpandPathName(appData.pixmapDirectory),
3284 piece > (int) WhiteKing ? "w" : "",
3285 pieceBitmapNames[piece],
3287 if (appData.debugMode) {
3288 fprintf(stderr, _("(File:%s:) "), buf);
3290 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3291 &(xpmPieceBitmap2[kind][piece]),
3292 NULL, &attr)) != 0) {
3293 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3294 // [HGM] missing: read of unorthodox piece failed; substitute King.
3295 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3296 ExpandPathName(appData.pixmapDirectory),
3298 if (appData.debugMode) {
3299 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3301 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3302 &(xpmPieceBitmap2[kind][piece]),
3306 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3311 if(piece <= (int) WhiteKing)
3312 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3315 /* Load light and dark squares */
3316 /* If the LSQ and DSQ pieces don't exist, we will
3317 draw them with solid squares. */
3318 fprintf(stderr, _("light square "));
3319 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3320 if (access(buf, 0) != 0) {
3324 if (appData.debugMode)
3325 fprintf(stderr, _("(File:%s:) "), buf);
3327 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3328 &xpmLightSquare, NULL, &attr)) != 0) {
3329 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3332 fprintf(stderr, _("dark square "));
3333 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3334 ExpandPathName(appData.pixmapDirectory), ss);
3335 if (appData.debugMode) {
3336 fprintf(stderr, _("(File:%s:) "), buf);
3338 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3339 &xpmDarkSquare, NULL, &attr)) != 0) {
3340 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3344 xpmJailSquare = xpmLightSquare;
3345 fprintf(stderr, _("Done.\n"));
3347 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3350 #endif /* HAVE_LIBXPM */
3353 /* No built-in bitmaps */
3358 u_int ss = squareSize;
3360 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3363 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3364 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3365 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3366 pieceBitmapNames[piece],
3367 ss, kind == SOLID ? 's' : 'o');
3368 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3369 if(piece <= (int)WhiteKing)
3370 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3374 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3378 /* With built-in bitmaps */
3381 BuiltInBits* bib = builtInBits;
3384 u_int ss = squareSize;
3386 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3389 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3391 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3392 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3393 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3394 pieceBitmapNames[piece],
3395 ss, kind == SOLID ? 's' : 'o');
3396 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3397 bib->bits[kind][piece], ss, ss);
3398 if(piece <= (int)WhiteKing)
3399 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3403 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3408 void ReadBitmap(pm, name, bits, wreq, hreq)
3411 unsigned char bits[];
3417 char msg[MSG_SIZ], fullname[MSG_SIZ];
3419 if (*appData.bitmapDirectory != NULLCHAR) {
3420 strcpy(fullname, appData.bitmapDirectory);
3421 strcat(fullname, "/");
3422 strcat(fullname, name);
3423 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3424 &w, &h, pm, &x_hot, &y_hot);
3425 fprintf(stderr, "load %s\n", name);
3426 if (errcode != BitmapSuccess) {
3428 case BitmapOpenFailed:
3429 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3431 case BitmapFileInvalid:
3432 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3434 case BitmapNoMemory:
3435 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3439 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3443 fprintf(stderr, _("%s: %s...using built-in\n"),
3445 } else if (w != wreq || h != hreq) {
3447 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3448 programName, fullname, w, h, wreq, hreq);
3454 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3463 if (lineGap == 0) return;
3465 /* [HR] Split this into 2 loops for non-square boards. */
3467 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3468 gridSegments[i].x1 = 0;
3469 gridSegments[i].x2 =
3470 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3471 gridSegments[i].y1 = gridSegments[i].y2
3472 = lineGap / 2 + (i * (squareSize + lineGap));
3475 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3476 gridSegments[j + i].y1 = 0;
3477 gridSegments[j + i].y2 =
3478 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3479 gridSegments[j + i].x1 = gridSegments[j + i].x2
3480 = lineGap / 2 + (j * (squareSize + lineGap));
3484 static void MenuBarSelect(w, addr, index)
3489 XtActionProc proc = (XtActionProc) addr;
3491 (proc)(NULL, NULL, NULL, NULL);
3494 void CreateMenuBarPopup(parent, name, mb)
3504 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3507 XtSetArg(args[j], XtNleftMargin, 20); j++;
3508 XtSetArg(args[j], XtNrightMargin, 20); j++;
3510 while (mi->string != NULL) {
3511 if (strcmp(mi->string, "----") == 0) {
3512 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3515 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3516 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3518 XtAddCallback(entry, XtNcallback,
3519 (XtCallbackProc) MenuBarSelect,
3520 (caddr_t) mi->proc);
3526 Widget CreateMenuBar(mb)
3530 Widget anchor, menuBar;
3532 char menuName[MSG_SIZ];
3535 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3536 XtSetArg(args[j], XtNvSpace, 0); j++;
3537 XtSetArg(args[j], XtNborderWidth, 0); j++;
3538 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3539 formWidget, args, j);
3541 while (mb->name != NULL) {
3542 strcpy(menuName, "menu");
3543 strcat(menuName, mb->name);
3545 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3548 shortName[0] = _(mb->name)[0];
3549 shortName[1] = NULLCHAR;
3550 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3553 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3556 XtSetArg(args[j], XtNborderWidth, 0); j++;
3557 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3559 CreateMenuBarPopup(menuBar, menuName, mb);
3565 Widget CreateButtonBar(mi)
3569 Widget button, buttonBar;
3573 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3575 XtSetArg(args[j], XtNhSpace, 0); j++;
3577 XtSetArg(args[j], XtNborderWidth, 0); j++;
3578 XtSetArg(args[j], XtNvSpace, 0); j++;
3579 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3580 formWidget, args, j);
3582 while (mi->string != NULL) {
3585 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3586 XtSetArg(args[j], XtNborderWidth, 0); j++;
3588 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3589 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3590 buttonBar, args, j);
3591 XtAddCallback(button, XtNcallback,
3592 (XtCallbackProc) MenuBarSelect,
3593 (caddr_t) mi->proc);
3600 CreatePieceMenu(name, color)
3607 ChessSquare selection;
3609 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3610 boardWidget, args, 0);
3612 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3613 String item = pieceMenuStrings[color][i];
3615 if (strcmp(item, "----") == 0) {
3616 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3619 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3620 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3622 selection = pieceMenuTranslation[color][i];
3623 XtAddCallback(entry, XtNcallback,
3624 (XtCallbackProc) PieceMenuSelect,
3625 (caddr_t) selection);
3626 if (selection == WhitePawn || selection == BlackPawn) {
3627 XtSetArg(args[0], XtNpopupOnEntry, entry);
3628 XtSetValues(menu, args, 1);
3641 ChessSquare selection;
3643 whitePieceMenu = CreatePieceMenu("menuW", 0);
3644 blackPieceMenu = CreatePieceMenu("menuB", 1);
3646 XtRegisterGrabAction(PieceMenuPopup, True,
3647 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3648 GrabModeAsync, GrabModeAsync);
3650 XtSetArg(args[0], XtNlabel, _("Drop"));
3651 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3652 boardWidget, args, 1);
3653 for (i = 0; i < DROP_MENU_SIZE; i++) {
3654 String item = dropMenuStrings[i];
3656 if (strcmp(item, "----") == 0) {
3657 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3660 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3661 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3663 selection = dropMenuTranslation[i];
3664 XtAddCallback(entry, XtNcallback,
3665 (XtCallbackProc) DropMenuSelect,
3666 (caddr_t) selection);
3671 void SetupDropMenu()
3679 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3680 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3681 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3682 dmEnables[i].piece);
3683 XtSetSensitive(entry, p != NULL || !appData.testLegality
3684 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3685 && !appData.icsActive));
3687 while (p && *p++ == dmEnables[i].piece) count++;
3688 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3690 XtSetArg(args[j], XtNlabel, label); j++;
3691 XtSetValues(entry, args, j);
3695 void PieceMenuPopup(w, event, params, num_params)
3699 Cardinal *num_params;
3702 if (event->type != ButtonPress) return;
3703 if (errorUp) ErrorPopDown();
3707 whichMenu = params[0];
3709 case IcsPlayingWhite:
3710 case IcsPlayingBlack:
3712 case MachinePlaysWhite:
3713 case MachinePlaysBlack:
3714 if (appData.testLegality &&
3715 gameInfo.variant != VariantBughouse &&
3716 gameInfo.variant != VariantCrazyhouse) return;
3718 whichMenu = "menuD";
3724 if (((pmFromX = EventToSquare(event->xbutton.x, BOARD_WIDTH)) < 0) ||
3725 ((pmFromY = EventToSquare(event->xbutton.y, BOARD_HEIGHT)) < 0)) {
3726 pmFromX = pmFromY = -1;
3730 pmFromX = BOARD_WIDTH - 1 - pmFromX;
3732 pmFromY = BOARD_HEIGHT - 1 - pmFromY;
3734 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3737 static void PieceMenuSelect(w, piece, junk)
3742 if (pmFromX < 0 || pmFromY < 0) return;
3743 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3746 static void DropMenuSelect(w, piece, junk)
3751 if (pmFromX < 0 || pmFromY < 0) return;
3752 DropMenuEvent(piece, pmFromX, pmFromY);
3755 void WhiteClock(w, event, prms, nprms)
3761 if (gameMode == EditPosition || gameMode == IcsExamining) {
3762 SetWhiteToPlayEvent();
3763 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3768 void BlackClock(w, event, prms, nprms)
3774 if (gameMode == EditPosition || gameMode == IcsExamining) {
3775 SetBlackToPlayEvent();
3776 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3783 * If the user selects on a border boundary, return -1; if off the board,
3784 * return -2. Otherwise map the event coordinate to the square.
3786 int EventToSquare(x, limit)
3794 if ((x % (squareSize + lineGap)) >= squareSize)
3796 x /= (squareSize + lineGap);
3802 static void do_flash_delay(msec)
3808 static void drawHighlight(file, rank, gc)
3814 if (lineGap == 0 || appData.blindfold) return;
3817 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3818 (squareSize + lineGap);
3819 y = lineGap/2 + rank * (squareSize + lineGap);
3821 x = lineGap/2 + file * (squareSize + lineGap);
3822 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3823 (squareSize + lineGap);
3826 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3827 squareSize+lineGap, squareSize+lineGap);
3830 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3831 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3834 SetHighlights(fromX, fromY, toX, toY)
3835 int fromX, fromY, toX, toY;
3837 if (hi1X != fromX || hi1Y != fromY) {
3838 if (hi1X >= 0 && hi1Y >= 0) {
3839 drawHighlight(hi1X, hi1Y, lineGC);
3841 if (fromX >= 0 && fromY >= 0) {
3842 drawHighlight(fromX, fromY, highlineGC);
3845 if (hi2X != toX || hi2Y != toY) {
3846 if (hi2X >= 0 && hi2Y >= 0) {
3847 drawHighlight(hi2X, hi2Y, lineGC);
3849 if (toX >= 0 && toY >= 0) {
3850 drawHighlight(toX, toY, highlineGC);
3862 SetHighlights(-1, -1, -1, -1);
3867 SetPremoveHighlights(fromX, fromY, toX, toY)
3868 int fromX, fromY, toX, toY;
3870 if (pm1X != fromX || pm1Y != fromY) {
3871 if (pm1X >= 0 && pm1Y >= 0) {
3872 drawHighlight(pm1X, pm1Y, lineGC);
3874 if (fromX >= 0 && fromY >= 0) {
3875 drawHighlight(fromX, fromY, prelineGC);
3878 if (pm2X != toX || pm2Y != toY) {
3879 if (pm2X >= 0 && pm2Y >= 0) {
3880 drawHighlight(pm2X, pm2Y, lineGC);
3882 if (toX >= 0 && toY >= 0) {
3883 drawHighlight(toX, toY, prelineGC);
3893 ClearPremoveHighlights()
3895 SetPremoveHighlights(-1, -1, -1, -1);
3898 static void BlankSquare(x, y, color, piece, dest)
3903 if (useImages && useImageSqs) {
3907 pm = xpmLightSquare;
3912 case 2: /* neutral */
3917 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
3918 squareSize, squareSize, x, y);
3928 case 2: /* neutral */
3933 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
3938 I split out the routines to draw a piece so that I could
3939 make a generic flash routine.
3941 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
3943 int square_color, x, y;
3946 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3947 switch (square_color) {
3949 case 2: /* neutral */
3951 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3952 ? *pieceToOutline(piece)
3953 : *pieceToSolid(piece),
3954 dest, bwPieceGC, 0, 0,
3955 squareSize, squareSize, x, y);
3958 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3959 ? *pieceToSolid(piece)
3960 : *pieceToOutline(piece),
3961 dest, wbPieceGC, 0, 0,
3962 squareSize, squareSize, x, y);
3967 static void monoDrawPiece(piece, square_color, x, y, dest)
3969 int square_color, x, y;
3972 switch (square_color) {
3974 case 2: /* neutral */
3976 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3977 ? *pieceToOutline(piece)
3978 : *pieceToSolid(piece),
3979 dest, bwPieceGC, 0, 0,
3980 squareSize, squareSize, x, y, 1);
3983 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3984 ? *pieceToSolid(piece)
3985 : *pieceToOutline(piece),
3986 dest, wbPieceGC, 0, 0,
3987 squareSize, squareSize, x, y, 1);
3992 static void colorDrawPiece(piece, square_color, x, y, dest)
3994 int square_color, x, y;
3997 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
3998 switch (square_color) {
4000 XCopyPlane(xDisplay, *pieceToSolid(piece),
4001 dest, (int) piece < (int) BlackPawn
4002 ? wlPieceGC : blPieceGC, 0, 0,
4003 squareSize, squareSize, x, y, 1);
4006 XCopyPlane(xDisplay, *pieceToSolid(piece),
4007 dest, (int) piece < (int) BlackPawn
4008 ? wdPieceGC : bdPieceGC, 0, 0,
4009 squareSize, squareSize, x, y, 1);
4011 case 2: /* neutral */
4013 XCopyPlane(xDisplay, *pieceToSolid(piece),
4014 dest, (int) piece < (int) BlackPawn
4015 ? wjPieceGC : bjPieceGC, 0, 0,
4016 squareSize, squareSize, x, y, 1);
4021 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4023 int square_color, x, y;
4028 switch (square_color) {
4030 case 2: /* neutral */
4032 if ((int)piece < (int) BlackPawn) {
4040 if ((int)piece < (int) BlackPawn) {
4048 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4049 dest, wlPieceGC, 0, 0,
4050 squareSize, squareSize, x, y);
4053 typedef void (*DrawFunc)();
4055 DrawFunc ChooseDrawFunc()
4057 if (appData.monoMode) {
4058 if (DefaultDepth(xDisplay, xScreen) == 1) {
4059 return monoDrawPiece_1bit;
4061 return monoDrawPiece;
4065 return colorDrawPieceImage;
4067 return colorDrawPiece;
4071 /* [HR] determine square color depending on chess variant. */
4072 static int SquareColor(row, column)
4077 if (gameInfo.variant == VariantXiangqi) {
4078 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4080 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4082 } else if (row <= 4) {
4088 square_color = ((column + row) % 2) == 1;
4091 /* [hgm] holdings: next line makes all holdings squares light */
4092 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4094 return square_color;
4097 void DrawSquare(row, column, piece, do_flash)
4098 int row, column, do_flash;
4101 int square_color, x, y, direction, font_ascent, font_descent;
4104 XCharStruct overall;
4108 /* Calculate delay in milliseconds (2-delays per complete flash) */
4109 flash_delay = 500 / appData.flashRate;
4112 x = lineGap + ((BOARD_WIDTH-1)-column) *
4113 (squareSize + lineGap);
4114 y = lineGap + row * (squareSize + lineGap);
4116 x = lineGap + column * (squareSize + lineGap);
4117 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4118 (squareSize + lineGap);
4121 square_color = SquareColor(row, column);
4123 if ( // [HGM] holdings: blank out area between board and holdings
4124 column == BOARD_LEFT-1 || column == BOARD_RGHT
4125 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4126 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4127 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4129 // [HGM] print piece counts next to holdings
4130 string[1] = NULLCHAR;
4131 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4132 string[0] = '0' + piece;
4133 XTextExtents(countFontStruct, string, 1, &direction,
4134 &font_ascent, &font_descent, &overall);
4135 if (appData.monoMode) {
4136 XDrawImageString(xDisplay, xBoardWindow, countGC,
4137 x + squareSize - overall.width - 2,
4138 y + font_ascent + 1, string, 1);
4140 XDrawString(xDisplay, xBoardWindow, countGC,
4141 x + squareSize - overall.width - 2,
4142 y + font_ascent + 1, string, 1);
4145 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4146 string[0] = '0' + piece;
4147 XTextExtents(countFontStruct, string, 1, &direction,
4148 &font_ascent, &font_descent, &overall);
4149 if (appData.monoMode) {
4150 XDrawImageString(xDisplay, xBoardWindow, countGC,
4151 x + 2, y + font_ascent + 1, string, 1);
4153 XDrawString(xDisplay, xBoardWindow, countGC,
4154 x + 2, y + font_ascent + 1, string, 1);
4158 if (piece == EmptySquare || appData.blindfold) {
4159 BlankSquare(x, y, square_color, piece, xBoardWindow);
4161 drawfunc = ChooseDrawFunc();
4162 if (do_flash && appData.flashCount > 0) {
4163 for (i=0; i<appData.flashCount; ++i) {
4165 drawfunc(piece, square_color, x, y, xBoardWindow);
4166 XSync(xDisplay, False);
4167 do_flash_delay(flash_delay);
4169 BlankSquare(x, y, square_color, piece, xBoardWindow);
4170 XSync(xDisplay, False);
4171 do_flash_delay(flash_delay);
4174 drawfunc(piece, square_color, x, y, xBoardWindow);
4178 string[1] = NULLCHAR;
4179 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4180 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4181 string[0] = 'a' + column - BOARD_LEFT;
4182 XTextExtents(coordFontStruct, string, 1, &direction,
4183 &font_ascent, &font_descent, &overall);
4184 if (appData.monoMode) {
4185 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4186 x + squareSize - overall.width - 2,
4187 y + squareSize - font_descent - 1, string, 1);
4189 XDrawString(xDisplay, xBoardWindow, coordGC,
4190 x + squareSize - overall.width - 2,
4191 y + squareSize - font_descent - 1, string, 1);
4194 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4195 string[0] = ONE + row;
4196 XTextExtents(coordFontStruct, string, 1, &direction,
4197 &font_ascent, &font_descent, &overall);
4198 if (appData.monoMode) {
4199 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4200 x + 2, y + font_ascent + 1, string, 1);
4202 XDrawString(xDisplay, xBoardWindow, coordGC,
4203 x + 2, y + font_ascent + 1, string, 1);
4209 /* Why is this needed on some versions of X? */
4210 void EventProc(widget, unused, event)
4215 if (!XtIsRealized(widget))
4218 switch (event->type) {
4220 if (event->xexpose.count > 0) return; /* no clipping is done */
4221 XDrawPosition(widget, True, NULL);
4229 void DrawPosition(fullRedraw, board)
4230 /*Boolean*/int fullRedraw;
4233 XDrawPosition(boardWidget, fullRedraw, board);
4236 /* Returns 1 if there are "too many" differences between b1 and b2
4237 (i.e. more than 1 move was made) */
4238 static int too_many_diffs(b1, b2)
4244 for (i=0; i<BOARD_HEIGHT; ++i) {
4245 for (j=0; j<BOARD_WIDTH; ++j) {
4246 if (b1[i][j] != b2[i][j]) {
4247 if (++c > 4) /* Castling causes 4 diffs */
4256 /* Matrix describing castling maneuvers */
4257 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4258 static int castling_matrix[4][5] = {
4259 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4260 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4261 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4262 { 7, 7, 4, 5, 6 } /* 0-0, black */
4265 /* Checks whether castling occurred. If it did, *rrow and *rcol
4266 are set to the destination (row,col) of the rook that moved.