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));
210 #define usleep(t) _sleep2(((t)+500)/1000)
214 # define _(s) gettext (s)
215 # define N_(s) gettext_noop (s)
231 int main P((int argc, char **argv));
232 RETSIGTYPE CmailSigHandler P((int sig));
233 RETSIGTYPE IntSigHandler P((int sig));
234 RETSIGTYPE TermSizeSigHandler P((int sig));
235 void CreateGCs P((void));
236 void CreateXIMPieces P((void));
237 void CreateXPMPieces P((void));
238 void CreatePieces P((void));
239 void CreatePieceMenus P((void));
240 Widget CreateMenuBar P((Menu *mb));
241 Widget CreateButtonBar P ((MenuItem *mi));
242 char *FindFont P((char *pattern, int targetPxlSize));
243 void PieceMenuPopup P((Widget w, XEvent *event,
244 String *params, Cardinal *num_params));
245 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
246 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
247 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
248 u_int wreq, u_int hreq));
249 void CreateGrid P((void));
250 int EventToSquare P((int x, int limit));
251 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
252 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
253 void HandleUserMove P((Widget w, XEvent *event,
254 String *prms, Cardinal *nprms));
255 void AnimateUserMove P((Widget w, XEvent * event,
256 String * params, Cardinal * nParams));
257 void WhiteClock P((Widget w, XEvent *event,
258 String *prms, Cardinal *nprms));
259 void BlackClock P((Widget w, XEvent *event,
260 String *prms, Cardinal *nprms));
261 void DrawPositionProc P((Widget w, XEvent *event,
262 String *prms, Cardinal *nprms));
263 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
265 void CommentPopUp P((char *title, char *label));
266 void CommentPopDown P((void));
267 void CommentCallback P((Widget w, XtPointer client_data,
268 XtPointer call_data));
269 void ICSInputBoxPopUp P((void));
270 void ICSInputBoxPopDown P((void));
271 void FileNamePopUp P((char *label, char *def,
272 FileProc proc, char *openMode));
273 void FileNamePopDown P((void));
274 void FileNameCallback P((Widget w, XtPointer client_data,
275 XtPointer call_data));
276 void FileNameAction P((Widget w, XEvent *event,
277 String *prms, Cardinal *nprms));
278 void AskQuestionReplyAction P((Widget w, XEvent *event,
279 String *prms, Cardinal *nprms));
280 void AskQuestionProc P((Widget w, XEvent *event,
281 String *prms, Cardinal *nprms));
282 void AskQuestionPopDown P((void));
283 void PromotionPopDown P((void));
284 void PromotionCallback P((Widget w, XtPointer client_data,
285 XtPointer call_data));
286 void EditCommentPopDown P((void));
287 void EditCommentCallback P((Widget w, XtPointer client_data,
288 XtPointer call_data));
289 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
290 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
291 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
292 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
294 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
296 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
298 void LoadPositionProc P((Widget w, XEvent *event,
299 String *prms, Cardinal *nprms));
300 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
302 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
304 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
306 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
308 void PastePositionProc P((Widget w, XEvent *event, String *prms,
310 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
311 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
312 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
313 void SavePositionProc P((Widget w, XEvent *event,
314 String *prms, Cardinal *nprms));
315 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
316 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
318 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
319 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
320 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
322 void MachineWhiteProc P((Widget w, XEvent *event,
323 String *prms, Cardinal *nprms));
324 void AnalyzeModeProc P((Widget w, XEvent *event,
325 String *prms, Cardinal *nprms));
326 void AnalyzeFileProc P((Widget w, XEvent *event,
327 String *prms, Cardinal *nprms));
328 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
330 void IcsClientProc P((Widget w, XEvent *event, String *prms,
332 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
333 void EditPositionProc P((Widget w, XEvent *event,
334 String *prms, Cardinal *nprms));
335 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
336 void EditCommentProc P((Widget w, XEvent *event,
337 String *prms, Cardinal *nprms));
338 void IcsInputBoxProc P((Widget w, XEvent *event,
339 String *prms, Cardinal *nprms));
340 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
341 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
342 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
343 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
344 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
345 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
346 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
347 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
348 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
349 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
350 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
351 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
352 void StopObservingProc P((Widget w, XEvent *event, String *prms,
354 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
356 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
357 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
358 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
363 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
365 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
368 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
370 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
372 void AutocommProc P((Widget w, XEvent *event, String *prms,
374 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
375 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
376 void AutobsProc P((Widget w, XEvent *event, String *prms,
378 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
379 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
380 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
383 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
384 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
386 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
388 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
390 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
391 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
392 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
394 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
396 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
398 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
400 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
402 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
403 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
404 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
406 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
408 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
410 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
412 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
413 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
414 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
415 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
416 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
417 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
418 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
419 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
420 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
421 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
422 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
423 void DisplayMove P((int moveNumber));
424 void DisplayTitle P((char *title));
425 void ICSInitScript P((void));
426 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
427 void ErrorPopUp P((char *title, char *text, int modal));
428 void ErrorPopDown P((void));
429 static char *ExpandPathName P((char *path));
430 static void CreateAnimVars P((void));
431 static void DragPieceMove P((int x, int y));
432 static void DrawDragPiece P((void));
433 char *ModeToWidgetName P((GameMode mode));
434 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
435 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
436 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void ShufflePopDown P(());
442 void EnginePopDown P(());
443 void UciPopDown P(());
444 void TimeControlPopDown P(());
445 void NewVariantPopDown P(());
446 void SettingsPopDown P(());
447 void update_ics_width P(());
448 int get_term_width P(());
450 * XBoard depends on Xt R4 or higher
452 int xtVersion = XtSpecificationRelease;
457 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
458 jailSquareColor, highlightSquareColor, premoveHighlightColor;
459 Pixel lowTimeWarningColor;
460 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
461 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
462 wjPieceGC, bjPieceGC, prelineGC, countGC;
463 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
464 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
465 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
466 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
467 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
468 ICSInputShell, fileNameShell, askQuestionShell;
469 Widget historyShell, evalGraphShell, gameListShell;
470 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
471 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
472 Font clockFontID, coordFontID, countFontID;
473 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
474 XtAppContext appContext;
476 char *oldICSInteractionTitle;
480 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
482 Position commentX = -1, commentY = -1;
483 Dimension commentW, commentH;
484 typedef unsigned int BoardSize;
486 Boolean chessProgram;
488 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
489 int squareSize, smallLayout = 0, tinyLayout = 0,
490 marginW, marginH, // [HGM] for run-time resizing
491 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
492 ICSInputBoxUp = False, askQuestionUp = False,
493 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
494 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
495 Pixel timerForegroundPixel, timerBackgroundPixel;
496 Pixel buttonForegroundPixel, buttonBackgroundPixel;
497 char *chessDir, *programName, *programVersion,
498 *gameCopyFilename, *gamePasteFilename;
499 Boolean alwaysOnTop = False;
500 Boolean saveSettingsOnExit;
501 char *settingsFileName;
502 char *icsTextMenuString;
504 char *firstChessProgramNames;
505 char *secondChessProgramNames;
507 WindowPlacement wpMain;
508 WindowPlacement wpConsole;
509 WindowPlacement wpComment;
510 WindowPlacement wpMoveHistory;
511 WindowPlacement wpEvalGraph;
512 WindowPlacement wpEngineOutput;
513 WindowPlacement wpGameList;
514 WindowPlacement wpTags;
518 Pixmap pieceBitmap[2][(int)BlackPawn];
519 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
520 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
521 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
522 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
523 int useImages, useImageSqs;
524 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
525 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
526 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
527 XImage *ximLightSquare, *ximDarkSquare;
530 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
531 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
533 #define White(piece) ((int)(piece) < (int)BlackPawn)
535 /* Variables for doing smooth animation. This whole thing
536 would be much easier if the board was double-buffered,
537 but that would require a fairly major rewrite. */
542 GC blitGC, pieceGC, outlineGC;
543 XPoint startSquare, prevFrame, mouseDelta;
547 int startBoardX, startBoardY;
550 /* There can be two pieces being animated at once: a player
551 can begin dragging a piece before the remote opponent has moved. */
553 static AnimState game, player;
555 /* Bitmaps for use as masks when drawing XPM pieces.
556 Need one for each black and white piece. */
557 static Pixmap xpmMask[BlackKing + 1];
559 /* This magic number is the number of intermediate frames used
560 in each half of the animation. For short moves it's reduced
561 by 1. The total number of frames will be factor * 2 + 1. */
564 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
566 MenuItem fileMenu[] = {
567 {N_("New Game"), ResetProc},
568 {N_("New Shuffle Game ..."), ShuffleMenuProc},
569 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
570 {"----", NothingProc},
571 {N_("Load Game"), LoadGameProc},
572 {N_("Load Next Game"), LoadNextGameProc},
573 {N_("Load Previous Game"), LoadPrevGameProc},
574 {N_("Reload Same Game"), ReloadGameProc},
575 {N_("Save Game"), SaveGameProc},
576 {"----", NothingProc},
577 {N_("Copy Game"), CopyGameProc},
578 {N_("Paste Game"), PasteGameProc},
579 {"----", NothingProc},
580 {N_("Load Position"), LoadPositionProc},
581 {N_("Load Next Position"), LoadNextPositionProc},
582 {N_("Load Previous Position"), LoadPrevPositionProc},
583 {N_("Reload Same Position"), ReloadPositionProc},
584 {N_("Save Position"), SavePositionProc},
585 {"----", NothingProc},
586 {N_("Copy Position"), CopyPositionProc},
587 {N_("Paste Position"), PastePositionProc},
588 {"----", NothingProc},
589 {N_("Mail Move"), MailMoveProc},
590 {N_("Reload CMail Message"), ReloadCmailMsgProc},
591 {"----", NothingProc},
592 {N_("Exit"), QuitProc},
596 MenuItem modeMenu[] = {
597 {N_("Machine White"), MachineWhiteProc},
598 {N_("Machine Black"), MachineBlackProc},
599 {N_("Two Machines"), TwoMachinesProc},
600 {N_("Analysis Mode"), AnalyzeModeProc},
601 {N_("Analyze File"), AnalyzeFileProc },
602 {N_("ICS Client"), IcsClientProc},
603 {N_("Edit Game"), EditGameProc},
604 {N_("Edit Position"), EditPositionProc},
605 {N_("Training"), TrainingProc},
606 {"----", NothingProc},
607 {N_("Show Engine Output"), EngineOutputProc},
608 {N_("Show Evaluation Graph"), NothingProc}, // [HGM] evalgr: not functional yet
609 {N_("Show Game List"), ShowGameListProc},
610 {"Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
611 {"----", NothingProc},
612 {N_("Edit Tags"), EditTagsProc},
613 {N_("Edit Comment"), EditCommentProc},
614 {N_("ICS Input Box"), IcsInputBoxProc},
615 {N_("Pause"), PauseProc},
619 MenuItem actionMenu[] = {
620 {N_("Accept"), AcceptProc},
621 {N_("Decline"), DeclineProc},
622 {N_("Rematch"), RematchProc},
623 {"----", NothingProc},
624 {N_("Call Flag"), CallFlagProc},
625 {N_("Draw"), DrawProc},
626 {N_("Adjourn"), AdjournProc},
627 {N_("Abort"), AbortProc},
628 {N_("Resign"), ResignProc},
629 {"----", NothingProc},
630 {N_("Stop Observing"), StopObservingProc},
631 {N_("Stop Examining"), StopExaminingProc},
632 {"----", NothingProc},
633 {N_("Adjudicate to White"), AdjuWhiteProc},
634 {N_("Adjudicate to Black"), AdjuBlackProc},
635 {N_("Adjudicate Draw"), AdjuDrawProc},
639 MenuItem stepMenu[] = {
640 {N_("Backward"), BackwardProc},
641 {N_("Forward"), ForwardProc},
642 {N_("Back to Start"), ToStartProc},
643 {N_("Forward to End"), ToEndProc},
644 {N_("Revert"), RevertProc},
645 {N_("Truncate Game"), TruncateGameProc},
646 {"----", NothingProc},
647 {N_("Move Now"), MoveNowProc},
648 {N_("Retract Move"), RetractMoveProc},
652 MenuItem optionsMenu[] = {
653 {N_("Flip View"), FlipViewProc},
654 {"----", NothingProc},
655 {N_("Adjudications ..."), EngineMenuProc},
656 {N_("General Settings ..."), UciMenuProc},
657 {N_("Engine #1 Settings ..."), FirstSettingsProc},
658 {N_("Engine #2 Settings ..."), SecondSettingsProc},
659 {N_("Time Control ..."), TimeControlProc},
660 {"----", NothingProc},
661 {N_("Always Queen"), AlwaysQueenProc},
662 {N_("Animate Dragging"), AnimateDraggingProc},
663 {N_("Animate Moving"), AnimateMovingProc},
664 {N_("Auto Comment"), AutocommProc},
665 {N_("Auto Flag"), AutoflagProc},
666 {N_("Auto Flip View"), AutoflipProc},
667 {N_("Auto Observe"), AutobsProc},
668 {N_("Auto Raise Board"), AutoraiseProc},
669 {N_("Auto Save"), AutosaveProc},
670 {N_("Blindfold"), BlindfoldProc},
671 {N_("Flash Moves"), FlashMovesProc},
672 {N_("Get Move List"), GetMoveListProc},
674 {N_("Highlight Dragging"), HighlightDraggingProc},
676 {N_("Highlight Last Move"), HighlightLastMoveProc},
677 {N_("Move Sound"), MoveSoundProc},
678 {N_("ICS Alarm"), IcsAlarmProc},
679 {N_("Old Save Style"), OldSaveStyleProc},
680 {N_("Periodic Updates"), PeriodicUpdatesProc},
681 {N_("Ponder Next Move"), PonderNextMoveProc},
682 {N_("Popup Exit Message"), PopupExitMessageProc},
683 {N_("Popup Move Errors"), PopupMoveErrorsProc},
684 {N_("Premove"), PremoveProc},
685 {N_("Quiet Play"), QuietPlayProc},
686 {N_("Show Coords"), ShowCoordsProc},
687 {N_("Hide Thinking"), HideThinkingProc},
688 {N_("Test Legality"), TestLegalityProc},
689 {"----", NothingProc},
690 {N_("Save Settings Now"), SaveSettingsProc},
691 {N_("Save Settings on Exit"), SaveOnExitProc},
695 MenuItem helpMenu[] = {
696 {N_("Info XBoard"), InfoProc},
697 {N_("Man XBoard"), ManProc},
698 {"----", NothingProc},
699 {N_("Hint"), HintProc},
700 {N_("Book"), BookProc},
701 {"----", NothingProc},
702 {N_("About XBoard"), AboutProc},
707 {N_("File"), fileMenu},
708 {N_("Mode"), modeMenu},
709 {N_("Action"), actionMenu},
710 {N_("Step"), stepMenu},
711 {N_("Options"), optionsMenu},
712 {N_("Help"), helpMenu},
716 #define PAUSE_BUTTON N_("P")
717 MenuItem buttonBar[] = {
720 {PAUSE_BUTTON, PauseProc},
726 #define PIECE_MENU_SIZE 18
727 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
728 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
729 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
730 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
731 N_("Empty square"), N_("Clear board") },
732 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
733 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
734 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
735 N_("Empty square"), N_("Clear board") }
737 /* must be in same order as PieceMenuStrings! */
738 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
739 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
740 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
741 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
742 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
743 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
744 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
745 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
746 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
749 #define DROP_MENU_SIZE 6
750 String dropMenuStrings[DROP_MENU_SIZE] = {
751 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
753 /* must be in same order as PieceMenuStrings! */
754 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
755 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
756 WhiteRook, WhiteQueen
764 DropMenuEnables dmEnables[] = {
782 { XtNborderWidth, 0 },
783 { XtNdefaultDistance, 0 },
787 { XtNborderWidth, 0 },
788 { XtNresizable, (XtArgVal) True },
792 { XtNborderWidth, 0 },
798 { XtNjustify, (XtArgVal) XtJustifyRight },
799 { XtNlabel, (XtArgVal) "..." },
800 { XtNresizable, (XtArgVal) True },
801 { XtNresize, (XtArgVal) False }
804 Arg messageArgs[] = {
805 { XtNjustify, (XtArgVal) XtJustifyLeft },
806 { XtNlabel, (XtArgVal) "..." },
807 { XtNresizable, (XtArgVal) True },
808 { XtNresize, (XtArgVal) False }
812 { XtNborderWidth, 0 },
813 { XtNjustify, (XtArgVal) XtJustifyLeft }
816 XtResource clientResources[] = {
817 { "flashCount", "flashCount", XtRInt, sizeof(int),
818 XtOffset(AppDataPtr, flashCount), XtRImmediate,
819 (XtPointer) FLASH_COUNT },
822 XrmOptionDescRec shellOptions[] = {
823 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
824 { "-flash", "flashCount", XrmoptionNoArg, "3" },
825 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
828 XtActionsRec boardActions[] = {
829 { "DrawPosition", DrawPositionProc },
830 { "HandleUserMove", HandleUserMove },
831 { "AnimateUserMove", AnimateUserMove },
832 { "FileNameAction", FileNameAction },
833 { "AskQuestionProc", AskQuestionProc },
834 { "AskQuestionReplyAction", AskQuestionReplyAction },
835 { "PieceMenuPopup", PieceMenuPopup },
836 { "WhiteClock", WhiteClock },
837 { "BlackClock", BlackClock },
838 { "Iconify", Iconify },
839 { "ResetProc", ResetProc },
840 { "LoadGameProc", LoadGameProc },
841 { "LoadNextGameProc", LoadNextGameProc },
842 { "LoadPrevGameProc", LoadPrevGameProc },
843 { "LoadSelectedProc", LoadSelectedProc },
844 { "ReloadGameProc", ReloadGameProc },
845 { "LoadPositionProc", LoadPositionProc },
846 { "LoadNextPositionProc", LoadNextPositionProc },
847 { "LoadPrevPositionProc", LoadPrevPositionProc },
848 { "ReloadPositionProc", ReloadPositionProc },
849 { "CopyPositionProc", CopyPositionProc },
850 { "PastePositionProc", PastePositionProc },
851 { "CopyGameProc", CopyGameProc },
852 { "PasteGameProc", PasteGameProc },
853 { "SaveGameProc", SaveGameProc },
854 { "SavePositionProc", SavePositionProc },
855 { "MailMoveProc", MailMoveProc },
856 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
857 { "QuitProc", QuitProc },
858 { "MachineWhiteProc", MachineWhiteProc },
859 { "MachineBlackProc", MachineBlackProc },
860 { "AnalysisModeProc", AnalyzeModeProc },
861 { "AnalyzeFileProc", AnalyzeFileProc },
862 { "TwoMachinesProc", TwoMachinesProc },
863 { "IcsClientProc", IcsClientProc },
864 { "EditGameProc", EditGameProc },
865 { "EditPositionProc", EditPositionProc },
866 { "TrainingProc", EditPositionProc },
867 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
868 { "ShowGameListProc", ShowGameListProc },
869 { "ShowMoveListProc", HistoryShowProc},
870 { "EditTagsProc", EditCommentProc },
871 { "EditCommentProc", EditCommentProc },
872 { "IcsAlarmProc", IcsAlarmProc },
873 { "IcsInputBoxProc", IcsInputBoxProc },
874 { "PauseProc", PauseProc },
875 { "AcceptProc", AcceptProc },
876 { "DeclineProc", DeclineProc },
877 { "RematchProc", RematchProc },
878 { "CallFlagProc", CallFlagProc },
879 { "DrawProc", DrawProc },
880 { "AdjournProc", AdjournProc },
881 { "AbortProc", AbortProc },
882 { "ResignProc", ResignProc },
883 { "AdjuWhiteProc", AdjuWhiteProc },
884 { "AdjuBlackProc", AdjuBlackProc },
885 { "AdjuDrawProc", AdjuDrawProc },
886 { "EnterKeyProc", EnterKeyProc },
887 { "StopObservingProc", StopObservingProc },
888 { "StopExaminingProc", StopExaminingProc },
889 { "BackwardProc", BackwardProc },
890 { "ForwardProc", ForwardProc },
891 { "ToStartProc", ToStartProc },
892 { "ToEndProc", ToEndProc },
893 { "RevertProc", RevertProc },
894 { "TruncateGameProc", TruncateGameProc },
895 { "MoveNowProc", MoveNowProc },
896 { "RetractMoveProc", RetractMoveProc },
897 { "AlwaysQueenProc", AlwaysQueenProc },
898 { "AnimateDraggingProc", AnimateDraggingProc },
899 { "AnimateMovingProc", AnimateMovingProc },
900 { "AutoflagProc", AutoflagProc },
901 { "AutoflipProc", AutoflipProc },
902 { "AutobsProc", AutobsProc },
903 { "AutoraiseProc", AutoraiseProc },
904 { "AutosaveProc", AutosaveProc },
905 { "BlindfoldProc", BlindfoldProc },
906 { "FlashMovesProc", FlashMovesProc },
907 { "FlipViewProc", FlipViewProc },
908 { "GetMoveListProc", GetMoveListProc },
910 { "HighlightDraggingProc", HighlightDraggingProc },
912 { "HighlightLastMoveProc", HighlightLastMoveProc },
913 { "IcsAlarmProc", IcsAlarmProc },
914 { "MoveSoundProc", MoveSoundProc },
915 { "OldSaveStyleProc", OldSaveStyleProc },
916 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
917 { "PonderNextMoveProc", PonderNextMoveProc },
918 { "PopupExitMessageProc", PopupExitMessageProc },
919 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
920 { "PremoveProc", PremoveProc },
921 { "QuietPlayProc", QuietPlayProc },
922 { "ShowCoordsProc", ShowCoordsProc },
923 { "ShowThinkingProc", ShowThinkingProc },
924 { "HideThinkingProc", HideThinkingProc },
925 { "TestLegalityProc", TestLegalityProc },
926 { "SaveSettingsProc", SaveSettingsProc },
927 { "SaveOnExitProc", SaveOnExitProc },
928 { "InfoProc", InfoProc },
929 { "ManProc", ManProc },
930 { "HintProc", HintProc },
931 { "BookProc", BookProc },
932 { "AboutGameProc", AboutGameProc },
933 { "AboutProc", AboutProc },
934 { "DebugProc", DebugProc },
935 { "NothingProc", NothingProc },
936 { "CommentPopDown", (XtActionProc) CommentPopDown },
937 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
938 { "TagsPopDown", (XtActionProc) TagsPopDown },
939 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
940 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
941 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
942 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
943 { "GameListPopDown", (XtActionProc) GameListPopDown },
944 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
945 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
946 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
947 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
948 { "EnginePopDown", (XtActionProc) EnginePopDown },
949 { "UciPopDown", (XtActionProc) UciPopDown },
950 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
951 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
952 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
955 char globalTranslations[] =
956 ":<Key>R: ResignProc() \n \
957 :<Key>r: ResetProc() \n \
958 :<Key>g: LoadGameProc() \n \
959 :<Key>N: LoadNextGameProc() \n \
960 :<Key>P: LoadPrevGameProc() \n \
961 :<Key>Q: QuitProc() \n \
962 :<Key>F: ToEndProc() \n \
963 :<Key>f: ForwardProc() \n \
964 :<Key>B: ToStartProc() \n \
965 :<Key>b: BackwardProc() \n \
966 :<Key>p: PauseProc() \n \
967 :<Key>d: DrawProc() \n \
968 :<Key>t: CallFlagProc() \n \
969 :<Key>i: Iconify() \n \
970 :<Key>c: Iconify() \n \
971 :<Key>v: FlipViewProc() \n \
972 <KeyDown>Control_L: BackwardProc() \n \
973 <KeyUp>Control_L: ForwardProc() \n \
974 <KeyDown>Control_R: BackwardProc() \n \
975 <KeyUp>Control_R: ForwardProc() \n \
976 Shift<Key>1: AskQuestionProc(\"Direct command\",\
977 \"Send to chess program:\",,1) \n \
978 Shift<Key>2: AskQuestionProc(\"Direct command\",\
979 \"Send to second chess program:\",,2) \n";
981 char boardTranslations[] =
982 "<Btn1Down>: HandleUserMove() \n \
983 <Btn1Up>: HandleUserMove() \n \
984 <Btn1Motion>: AnimateUserMove() \n \
985 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
986 PieceMenuPopup(menuB) \n \
987 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
988 PieceMenuPopup(menuW) \n \
989 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
990 PieceMenuPopup(menuW) \n \
991 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
992 PieceMenuPopup(menuB) \n";
994 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
995 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
997 char ICSInputTranslations[] =
998 "<Key>Return: EnterKeyProc() \n";
1000 String xboardResources[] = {
1001 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1002 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1003 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1008 /* Max possible square size */
1009 #define MAXSQSIZE 256
1011 static int xpm_avail[MAXSQSIZE];
1013 #ifdef HAVE_DIR_STRUCT
1015 /* Extract piece size from filename */
1017 xpm_getsize(name, len, ext)
1028 if ((p=strchr(name, '.')) == NULL ||
1029 StrCaseCmp(p+1, ext) != 0)
1035 while (*p && isdigit(*p))
1042 /* Setup xpm_avail */
1044 xpm_getavail(dirname, ext)
1052 for (i=0; i<MAXSQSIZE; ++i)
1055 if (appData.debugMode)
1056 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1058 dir = opendir(dirname);
1061 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1062 programName, dirname);
1066 while ((ent=readdir(dir)) != NULL) {
1067 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1068 if (i > 0 && i < MAXSQSIZE)
1078 xpm_print_avail(fp, ext)
1084 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1085 for (i=1; i<MAXSQSIZE; ++i) {
1091 /* Return XPM piecesize closest to size */
1093 xpm_closest_to(dirname, size, ext)
1099 int sm_diff = MAXSQSIZE;
1103 xpm_getavail(dirname, ext);
1105 if (appData.debugMode)
1106 xpm_print_avail(stderr, ext);
1108 for (i=1; i<MAXSQSIZE; ++i) {
1111 diff = (diff<0) ? -diff : diff;
1112 if (diff < sm_diff) {
1120 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1126 #else /* !HAVE_DIR_STRUCT */
1127 /* If we are on a system without a DIR struct, we can't
1128 read the directory, so we can't collect a list of
1129 filenames, etc., so we can't do any size-fitting. */
1131 xpm_closest_to(dirname, size, ext)
1136 fprintf(stderr, _("\
1137 Warning: No DIR structure found on this system --\n\
1138 Unable to autosize for XPM/XIM pieces.\n\
1139 Please report this error to frankm@hiwaay.net.\n\
1140 Include system type & operating system in message.\n"));
1143 #endif /* HAVE_DIR_STRUCT */
1145 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1146 "magenta", "cyan", "white" };
1150 TextColors textColors[(int)NColorClasses];
1152 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1154 parse_color(str, which)
1158 char *p, buf[100], *d;
1161 if (strlen(str) > 99) /* watch bounds on buf */
1166 for (i=0; i<which; ++i) {
1173 /* Could be looking at something like:
1175 .. in which case we want to stop on a comma also */
1176 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1180 return -1; /* Use default for empty field */
1183 if (which == 2 || isdigit(*p))
1186 while (*p && isalpha(*p))
1191 for (i=0; i<8; ++i) {
1192 if (!StrCaseCmp(buf, cnames[i]))
1193 return which? (i+40) : (i+30);
1195 if (!StrCaseCmp(buf, "default")) return -1;
1197 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1202 parse_cpair(cc, str)
1206 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1207 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1212 /* bg and attr are optional */
1213 textColors[(int)cc].bg = parse_color(str, 1);
1214 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1215 textColors[(int)cc].attr = 0;
1221 /* Arrange to catch delete-window events */
1222 Atom wm_delete_window;
1224 CatchDeleteWindow(Widget w, String procname)
1227 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1228 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1229 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1236 XtSetArg(args[0], XtNiconic, False);
1237 XtSetValues(shellWidget, args, 1);
1239 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1242 //---------------------------------------------------------------------------------------------------------
1243 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1246 #define CW_USEDEFAULT (1<<31)
1247 #define ICS_TEXT_MENU_SIZE 90
1248 #define SetCurrentDirectory chdir
1249 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1251 // these two must some day move to frontend.h, when they are implemented
1252 Boolean EvalGraphIsUp();
1253 Boolean MoveHistoryIsUp();
1254 Boolean GameListIsUp();
1256 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1259 // front-end part of option handling
1261 // [HGM] This platform-dependent table provides the location for storing the color info
1264 &appData.whitePieceColor,
1265 &appData.blackPieceColor,
1266 &appData.lightSquareColor,
1267 &appData.darkSquareColor,
1268 &appData.highlightSquareColor,
1269 &appData.premoveHighlightColor,
1282 ParseFont(char *name, int number)
1283 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1285 case 0: // CLOCK_FONT
1286 appData.clockFont = strdup(name);
1288 case 1: // MESSAGE_FONT
1289 appData.font = strdup(name);
1291 case 2: // COORD_FONT
1292 appData.coordFont = strdup(name);
1301 { // only 2 fonts currently
1302 appData.clockFont = CLOCK_FONT_NAME;
1303 appData.coordFont = COORD_FONT_NAME;
1304 appData.font = DEFAULT_FONT_NAME;
1309 { // no-op, until we identify the code for this already in XBoard and move it here
1313 ParseColor(int n, char *name)
1314 { // in XBoard, just copy the color-name string
1315 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1319 ParseTextAttribs(ColorClass cc, char *s)
1321 (&appData.colorShout)[cc] = strdup(s);
1325 ParseBoardSize(void *addr, char *name)
1327 appData.boardSize = strdup(name);
1332 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1336 SetCommPortDefaults()
1337 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1340 // [HGM] args: these three cases taken out to stay in front-end
1342 SaveFontArg(FILE *f, ArgDescriptor *ad)
1345 switch((int)ad->argLoc) {
1346 case 0: // CLOCK_FONT
1347 name = appData.clockFont;
1349 case 1: // MESSAGE_FONT
1350 name = appData.font;
1352 case 2: // COORD_FONT
1353 name = appData.coordFont;
1358 fprintf(f, "/%s=%s\n", ad->argName, name);
1363 { // nothing to do, as the sounds are at all times represented by their text-string names already
1367 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1368 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1369 fprintf(f, "/%s=%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1373 SaveColor(FILE *f, ArgDescriptor *ad)
1374 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1375 if(colorVariable[(int)ad->argLoc])
1376 fprintf(f, "/%s=%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1380 SaveBoardSize(FILE *f, char *name, void *addr)
1381 { // wrapper to shield back-end from BoardSize & sizeInfo
1382 fprintf(f, "/%s=%s\n", name, appData.boardSize);
1386 ParseCommPortSettings(char *s)
1387 { // no such option in XBoard (yet)
1390 extern Widget engineOutputShell;
1391 extern Widget tagsShell, editTagsShell;
1393 GetActualPlacement(Widget wg, WindowPlacement *wp)
1403 XtSetArg(args[i], XtNx, &x); i++;
1404 XtSetArg(args[i], XtNy, &y); i++;
1405 XtSetArg(args[i], XtNwidth, &w); i++;
1406 XtSetArg(args[i], XtNheight, &h); i++;
1407 XtGetValues(wg, args, i);
1416 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1417 // In XBoard this will have to wait until awareness of window parameters is implemented
1418 GetActualPlacement(shellWidget, &wpMain);
1419 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1420 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1421 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1422 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1423 else GetActualPlacement(editShell, &wpComment);
1424 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1425 else GetActualPlacement(editTagsShell, &wpTags);
1427 GetActualPlacement(hwndConsole, &wpConsole);
1428 GetActualPlacement(evalGraphDialog, &wpEvalGraph);
1433 PrintCommPortSettings(FILE *f, char *name)
1434 { // This option does not exist in XBoard
1438 MySearchPath(char *installDir, char *name, char *fullname)
1439 { // just append installDir and name. Perhaps ExpandPath should be used here?
1440 name = ExpandPathName(name);
1441 if(name && name[0] == '/') strcpy(fullname, name); else {
1442 sprintf(fullname, "%s%c%s", installDir, '/', name);
1448 MyGetFullPathName(char *name, char *fullname)
1449 { // should use ExpandPath?
1450 name = ExpandPathName(name);
1451 strcpy(fullname, name);
1456 EnsureOnScreen(int *x, int *y, int minX, int minY)
1469 { // [HGM] args: allows testing if main window is realized from back-end
1470 return xBoardWindow != 0;
1474 PopUpStartupDialog()
1475 { // start menu not implemented in XBoard
1478 ConvertToLine(int argc, char **argv)
1480 static char line[128*1024], buf[1024];
1484 for(i=1; i<argc; i++) {
1485 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1486 && argv[i][0] != '{' )
1487 sprintf(buf, "{%s} ", argv[i]);
1488 else sprintf(buf, "%s ", argv[i]);
1491 line[strlen(line)-1] = NULLCHAR;
1495 //--------------------------------------------------------------------------------------------
1498 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1500 #define BoardSize int
1501 void InitDrawingSizes(BoardSize boardSize, int flags)
1502 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1503 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1505 XtGeometryResult gres;
1508 if(!formWidget) return;
1511 * Enable shell resizing.
1513 shellArgs[0].value = (XtArgVal) &w;
1514 shellArgs[1].value = (XtArgVal) &h;
1515 XtGetValues(shellWidget, shellArgs, 2);
1517 shellArgs[4].value = 2*w; shellArgs[2].value = 10;
1518 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1519 XtSetValues(shellWidget, &shellArgs[2], 4);
1521 XtSetArg(args[0], XtNdefaultDistance, &sep);
1522 XtGetValues(formWidget, args, 1);
1524 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1525 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1528 XtSetArg(args[0], XtNwidth, boardWidth);
1529 XtSetArg(args[1], XtNheight, boardHeight);
1530 XtSetValues(boardWidget, args, 2);
1532 timerWidth = (boardWidth - sep) / 2;
1533 XtSetArg(args[0], XtNwidth, timerWidth);
1534 XtSetValues(whiteTimerWidget, args, 1);
1535 XtSetValues(blackTimerWidget, args, 1);
1537 XawFormDoLayout(formWidget, False);
1539 if (appData.titleInWindow) {
1541 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1542 XtSetArg(args[i], XtNheight, &h); i++;
1543 XtGetValues(titleWidget, args, i);
1545 w = boardWidth - 2*bor;
1547 XtSetArg(args[0], XtNwidth, &w);
1548 XtGetValues(menuBarWidget, args, 1);
1549 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1552 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1553 if (gres != XtGeometryYes && appData.debugMode) {
1555 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1556 programName, gres, w, h, wr, hr);
1560 XawFormDoLayout(formWidget, True);
1563 * Inhibit shell resizing.
1565 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW;
1566 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1567 shellArgs[4].value = shellArgs[2].value = w;
1568 shellArgs[5].value = shellArgs[3].value = h;
1569 XtSetValues(shellWidget, &shellArgs[0], 6);
1571 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1574 for(i=0; i<4; i++) {
1576 for(p=0; p<=(int)WhiteKing; p++)
1577 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1578 if(gameInfo.variant == VariantShogi) {
1579 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1580 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1581 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1582 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1583 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1586 if(gameInfo.variant == VariantGothic) {
1587 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1591 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1592 for(p=0; p<=(int)WhiteKing; p++)
1593 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1594 if(gameInfo.variant == VariantShogi) {
1595 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1596 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1597 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1598 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1599 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1602 if(gameInfo.variant == VariantGothic) {
1603 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1609 for(i=0; i<2; i++) {
1611 for(p=0; p<=(int)WhiteKing; p++)
1612 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1613 if(gameInfo.variant == VariantShogi) {
1614 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1615 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1616 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1617 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1618 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1621 if(gameInfo.variant == VariantGothic) {
1622 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1633 void EscapeExpand(char *p, char *q)
1634 { // [HGM] initstring: routine to shape up string arguments
1635 while(*p++ = *q++) if(p[-1] == '\\')
1637 case 'n': p[-1] = '\n'; break;
1638 case 'r': p[-1] = '\r'; break;
1639 case 't': p[-1] = '\t'; break;
1640 case '\\': p[-1] = '\\'; break;
1641 case 0: *p = 0; return;
1642 default: p[-1] = q[-1]; break;
1651 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1652 XSetWindowAttributes window_attributes;
1654 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1655 XrmValue vFrom, vTo;
1656 XtGeometryResult gres;
1659 int forceMono = False;
1660 //define INDIRECTION
1662 // [HGM] before anything else, expand any indirection files amongst options
1663 char *argvCopy[1000]; // 1000 seems enough
1664 char newArgs[10000]; // holds actual characters
1667 srandom(time(0)); // [HGM] book: make random truly random
1670 for(i=0; i<argc; i++) {
1671 if(j >= 1000-2) { printf(_("too many arguments\n")); exit(-1); }
1672 //fprintf(stderr, "arg %s\n", argv[i]);
1673 if(argv[i][0] != '@') argvCopy[j++] = argv[i]; else {
1675 FILE *f = fopen(argv[i]+1, "rb");
1676 if(f == NULL) { fprintf(stderr, _("ignore %s\n"), argv[i]); continue; } // do not expand non-existing
1677 argvCopy[j++] = newArgs + k; // get ready for first argument from file
1678 while((c = fgetc(f)) != EOF) { // each line of file inserts 1 argument in the list
1680 if(j >= 1000-2) { printf(_("too many arguments\n")); exit(-1); }
1681 newArgs[k++] = 0; // terminate current arg
1682 if(k >= 10000-1) { printf(_("too long arguments\n")); exit(-1); }
1683 argvCopy[j++] = newArgs + k; // get ready for next
1685 if(k >= 10000-1) { printf(_("too long arguments\n")); exit(-1); }
1699 setbuf(stdout, NULL);
1700 setbuf(stderr, NULL);
1703 programName = strrchr(argv[0], '/');
1704 if (programName == NULL)
1705 programName = argv[0];
1710 XtSetLanguageProc(NULL, NULL, NULL);
1711 bindtextdomain(PACKAGE, LOCALEDIR);
1712 textdomain(PACKAGE);
1716 XtAppInitialize(&appContext, "XBoard", shellOptions,
1717 XtNumber(shellOptions),
1718 &argc, argv, xboardResources, NULL, 0);
1719 appData.boardSize = "";
1720 InitAppData(ConvertToLine(argc, argv));
1722 if (p == NULL) p = "/tmp";
1723 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1724 gameCopyFilename = (char*) malloc(i);
1725 gamePasteFilename = (char*) malloc(i);
1726 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1727 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1729 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1730 clientResources, XtNumber(clientResources),
1733 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1734 static char buf[MSG_SIZ];
1735 EscapeExpand(buf, appData.initString);
1736 appData.initString = strdup(buf);
1737 EscapeExpand(buf, appData.secondInitString);
1738 appData.secondInitString = strdup(buf);
1739 EscapeExpand(buf, appData.firstComputerString);
1740 appData.firstComputerString = strdup(buf);
1741 EscapeExpand(buf, appData.secondComputerString);
1742 appData.secondComputerString = strdup(buf);
1745 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1748 if (chdir(chessDir) != 0) {
1749 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1755 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1756 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1757 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1758 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1761 setbuf(debugFP, NULL);
1764 /* [HGM,HR] make sure board size is acceptable */
1765 if(appData.NrFiles > BOARD_FILES ||
1766 appData.NrRanks > BOARD_RANKS )
1767 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1770 /* This feature does not work; animation needs a rewrite */
1771 appData.highlightDragging = FALSE;
1775 xDisplay = XtDisplay(shellWidget);
1776 xScreen = DefaultScreen(xDisplay);
1777 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1779 gameInfo.variant = StringToVariant(appData.variant);
1780 InitPosition(FALSE);
1783 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1785 if (isdigit(appData.boardSize[0])) {
1786 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1787 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1788 &fontPxlSize, &smallLayout, &tinyLayout);
1790 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1791 programName, appData.boardSize);
1795 /* Find some defaults; use the nearest known size */
1796 SizeDefaults *szd, *nearest;
1797 int distance = 99999;
1798 nearest = szd = sizeDefaults;
1799 while (szd->name != NULL) {
1800 if (abs(szd->squareSize - squareSize) < distance) {
1802 distance = abs(szd->squareSize - squareSize);
1803 if (distance == 0) break;
1807 if (i < 2) lineGap = nearest->lineGap;
1808 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1809 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1810 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1811 if (i < 6) smallLayout = nearest->smallLayout;
1812 if (i < 7) tinyLayout = nearest->tinyLayout;
1815 SizeDefaults *szd = sizeDefaults;
1816 if (*appData.boardSize == NULLCHAR) {
1817 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1818 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1821 if (szd->name == NULL) szd--;
1822 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1824 while (szd->name != NULL &&
1825 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1826 if (szd->name == NULL) {
1827 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1828 programName, appData.boardSize);
1832 squareSize = szd->squareSize;
1833 lineGap = szd->lineGap;
1834 clockFontPxlSize = szd->clockFontPxlSize;
1835 coordFontPxlSize = szd->coordFontPxlSize;
1836 fontPxlSize = szd->fontPxlSize;
1837 smallLayout = szd->smallLayout;
1838 tinyLayout = szd->tinyLayout;
1841 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1842 if (strlen(appData.pixmapDirectory) > 0) {
1843 p = ExpandPathName(appData.pixmapDirectory);
1845 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1846 appData.pixmapDirectory);
1849 if (appData.debugMode) {
1850 fprintf(stderr, _("\
1851 XBoard square size (hint): %d\n\
1852 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1854 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1855 if (appData.debugMode) {
1856 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1860 /* [HR] height treated separately (hacked) */
1861 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1862 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1863 if (appData.showJail == 1) {
1864 /* Jail on top and bottom */
1865 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1866 XtSetArg(boardArgs[2], XtNheight,
1867 boardHeight + 2*(lineGap + squareSize));
1868 } else if (appData.showJail == 2) {
1870 XtSetArg(boardArgs[1], XtNwidth,
1871 boardWidth + 2*(lineGap + squareSize));
1872 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1875 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1876 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1880 * Determine what fonts to use.
1882 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1883 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1884 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1885 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1886 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1887 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1888 appData.font = FindFont(appData.font, fontPxlSize);
1889 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1890 countFontStruct = XQueryFont(xDisplay, countFontID);
1891 // appData.font = FindFont(appData.font, fontPxlSize);
1893 xdb = XtDatabase(xDisplay);
1894 XrmPutStringResource(&xdb, "*font", appData.font);
1897 * Detect if there are not enough colors available and adapt.
1899 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1900 appData.monoMode = True;
1903 if (!appData.monoMode) {
1904 vFrom.addr = (caddr_t) appData.lightSquareColor;
1905 vFrom.size = strlen(appData.lightSquareColor);
1906 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1907 if (vTo.addr == NULL) {
1908 appData.monoMode = True;
1911 lightSquareColor = *(Pixel *) vTo.addr;
1914 if (!appData.monoMode) {
1915 vFrom.addr = (caddr_t) appData.darkSquareColor;
1916 vFrom.size = strlen(appData.darkSquareColor);
1917 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1918 if (vTo.addr == NULL) {
1919 appData.monoMode = True;
1922 darkSquareColor = *(Pixel *) vTo.addr;
1925 if (!appData.monoMode) {
1926 vFrom.addr = (caddr_t) appData.whitePieceColor;
1927 vFrom.size = strlen(appData.whitePieceColor);
1928 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1929 if (vTo.addr == NULL) {
1930 appData.monoMode = True;
1933 whitePieceColor = *(Pixel *) vTo.addr;
1936 if (!appData.monoMode) {
1937 vFrom.addr = (caddr_t) appData.blackPieceColor;
1938 vFrom.size = strlen(appData.blackPieceColor);
1939 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1940 if (vTo.addr == NULL) {
1941 appData.monoMode = True;
1944 blackPieceColor = *(Pixel *) vTo.addr;
1948 if (!appData.monoMode) {
1949 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1950 vFrom.size = strlen(appData.highlightSquareColor);
1951 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1952 if (vTo.addr == NULL) {
1953 appData.monoMode = True;
1956 highlightSquareColor = *(Pixel *) vTo.addr;
1960 if (!appData.monoMode) {
1961 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1962 vFrom.size = strlen(appData.premoveHighlightColor);
1963 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1964 if (vTo.addr == NULL) {
1965 appData.monoMode = True;
1968 premoveHighlightColor = *(Pixel *) vTo.addr;
1973 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1976 if (appData.bitmapDirectory == NULL ||
1977 appData.bitmapDirectory[0] == NULLCHAR)
1978 appData.bitmapDirectory = DEF_BITMAP_DIR;
1981 if (appData.lowTimeWarning && !appData.monoMode) {
1982 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
1983 vFrom.size = strlen(appData.lowTimeWarningColor);
1984 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1985 if (vTo.addr == NULL)
1986 appData.monoMode = True;
1988 lowTimeWarningColor = *(Pixel *) vTo.addr;
1991 if (appData.monoMode && appData.debugMode) {
1992 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1993 (unsigned long) XWhitePixel(xDisplay, xScreen),
1994 (unsigned long) XBlackPixel(xDisplay, xScreen));
1997 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1998 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1999 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2000 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2001 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2002 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2003 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2004 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2005 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2006 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2008 if (appData.colorize) {
2010 _("%s: can't parse color names; disabling colorization\n"),
2013 appData.colorize = FALSE;
2015 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2016 textColors[ColorNone].attr = 0;
2018 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2024 layoutName = "tinyLayout";
2025 } else if (smallLayout) {
2026 layoutName = "smallLayout";
2028 layoutName = "normalLayout";
2030 /* Outer layoutWidget is there only to provide a name for use in
2031 resources that depend on the layout style */
2033 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2034 layoutArgs, XtNumber(layoutArgs));
2036 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2037 formArgs, XtNumber(formArgs));
2038 XtSetArg(args[0], XtNdefaultDistance, &sep);
2039 XtGetValues(formWidget, args, 1);
2042 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2043 XtSetArg(args[0], XtNtop, XtChainTop);
2044 XtSetArg(args[1], XtNbottom, XtChainTop);
2045 XtSetArg(args[2], XtNright, XtChainLeft);
2046 XtSetValues(menuBarWidget, args, 3);
2048 widgetList[j++] = whiteTimerWidget =
2049 XtCreateWidget("whiteTime", labelWidgetClass,
2050 formWidget, timerArgs, XtNumber(timerArgs));
2051 XtSetArg(args[0], XtNfont, clockFontStruct);
2052 XtSetArg(args[1], XtNtop, XtChainTop);
2053 XtSetArg(args[2], XtNbottom, XtChainTop);
2054 XtSetValues(whiteTimerWidget, args, 3);
2056 widgetList[j++] = blackTimerWidget =
2057 XtCreateWidget("blackTime", labelWidgetClass,
2058 formWidget, timerArgs, XtNumber(timerArgs));
2059 XtSetArg(args[0], XtNfont, clockFontStruct);
2060 XtSetArg(args[1], XtNtop, XtChainTop);
2061 XtSetArg(args[2], XtNbottom, XtChainTop);
2062 XtSetValues(blackTimerWidget, args, 3);
2064 if (appData.titleInWindow) {
2065 widgetList[j++] = titleWidget =
2066 XtCreateWidget("title", labelWidgetClass, formWidget,
2067 titleArgs, XtNumber(titleArgs));
2068 XtSetArg(args[0], XtNtop, XtChainTop);
2069 XtSetArg(args[1], XtNbottom, XtChainTop);
2070 XtSetValues(titleWidget, args, 2);
2073 if (appData.showButtonBar) {
2074 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2075 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2076 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2077 XtSetArg(args[2], XtNtop, XtChainTop);
2078 XtSetArg(args[3], XtNbottom, XtChainTop);
2079 XtSetValues(buttonBarWidget, args, 4);
2082 widgetList[j++] = messageWidget =
2083 XtCreateWidget("message", labelWidgetClass, formWidget,
2084 messageArgs, XtNumber(messageArgs));
2085 XtSetArg(args[0], XtNtop, XtChainTop);
2086 XtSetArg(args[1], XtNbottom, XtChainTop);
2087 XtSetValues(messageWidget, args, 2);
2089 widgetList[j++] = boardWidget =
2090 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2091 XtNumber(boardArgs));
2093 XtManageChildren(widgetList, j);
2095 timerWidth = (boardWidth - sep) / 2;
2096 XtSetArg(args[0], XtNwidth, timerWidth);
2097 XtSetValues(whiteTimerWidget, args, 1);
2098 XtSetValues(blackTimerWidget, args, 1);
2100 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2101 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2102 XtGetValues(whiteTimerWidget, args, 2);
2104 if (appData.showButtonBar) {
2105 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2106 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2107 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2111 * formWidget uses these constraints but they are stored
2115 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2116 XtSetValues(menuBarWidget, args, i);
2117 if (appData.titleInWindow) {
2120 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2121 XtSetValues(whiteTimerWidget, args, i);
2123 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2124 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2125 XtSetValues(blackTimerWidget, args, i);
2127 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2128 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2129 XtSetValues(titleWidget, args, i);
2131 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2132 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2133 XtSetValues(messageWidget, args, i);
2134 if (appData.showButtonBar) {
2136 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2137 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2138 XtSetValues(buttonBarWidget, args, i);
2142 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2143 XtSetValues(whiteTimerWidget, args, i);
2145 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2146 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2147 XtSetValues(blackTimerWidget, args, i);
2149 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2150 XtSetValues(titleWidget, args, i);
2152 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2153 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2154 XtSetValues(messageWidget, args, i);
2155 if (appData.showButtonBar) {
2157 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2158 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2159 XtSetValues(buttonBarWidget, args, i);
2164 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2165 XtSetValues(whiteTimerWidget, args, i);
2167 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2168 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2169 XtSetValues(blackTimerWidget, args, i);
2171 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2172 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2173 XtSetValues(messageWidget, args, i);
2174 if (appData.showButtonBar) {
2176 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2177 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2178 XtSetValues(buttonBarWidget, args, i);
2182 XtSetArg(args[0], XtNfromVert, messageWidget);
2183 XtSetArg(args[1], XtNtop, XtChainTop);
2184 XtSetArg(args[2], XtNbottom, XtChainBottom);
2185 XtSetArg(args[3], XtNleft, XtChainLeft);
2186 XtSetArg(args[4], XtNright, XtChainRight);
2187 XtSetValues(boardWidget, args, 5);
2189 XtRealizeWidget(shellWidget);
2192 XtSetArg(args[0], XtNx, wpMain.x);
2193 XtSetArg(args[1], XtNy, wpMain.y);
2194 XtSetValues(shellWidget, args, 2);
2198 * Correct the width of the message and title widgets.
2199 * It is not known why some systems need the extra fudge term.
2200 * The value "2" is probably larger than needed.
2202 XawFormDoLayout(formWidget, False);
2204 #define WIDTH_FUDGE 2
2206 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2207 XtSetArg(args[i], XtNheight, &h); i++;
2208 XtGetValues(messageWidget, args, i);
2209 if (appData.showButtonBar) {
2211 XtSetArg(args[i], XtNwidth, &w); i++;
2212 XtGetValues(buttonBarWidget, args, i);
2213 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2215 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2218 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2219 if (gres != XtGeometryYes && appData.debugMode) {
2220 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2221 programName, gres, w, h, wr, hr);
2224 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2225 /* The size used for the child widget in layout lags one resize behind
2226 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2228 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2229 if (gres != XtGeometryYes && appData.debugMode) {
2230 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2231 programName, gres, w, h, wr, hr);
2234 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2235 XtSetArg(args[1], XtNright, XtChainRight);
2236 XtSetValues(messageWidget, args, 2);
2238 if (appData.titleInWindow) {
2240 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2241 XtSetArg(args[i], XtNheight, &h); i++;
2242 XtGetValues(titleWidget, args, i);
2244 w = boardWidth - 2*bor;
2246 XtSetArg(args[0], XtNwidth, &w);
2247 XtGetValues(menuBarWidget, args, 1);
2248 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2251 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2252 if (gres != XtGeometryYes && appData.debugMode) {
2254 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2255 programName, gres, w, h, wr, hr);
2258 XawFormDoLayout(formWidget, True);
2260 xBoardWindow = XtWindow(boardWidget);
2262 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2263 // not need to go into InitDrawingSizes().
2267 * Create X checkmark bitmap and initialize option menu checks.
2269 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2270 checkmark_bits, checkmark_width, checkmark_height);
2271 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2272 if (appData.alwaysPromoteToQueen) {
2273 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2276 if (appData.animateDragging) {
2277 XtSetValues(XtNameToWidget(menuBarWidget,
2278 "menuOptions.Animate Dragging"),
2281 if (appData.animate) {
2282 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2285 if (appData.autoComment) {
2286 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2289 if (appData.autoCallFlag) {
2290 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2293 if (appData.autoFlipView) {
2294 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2297 if (appData.autoObserve) {
2298 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2301 if (appData.autoRaiseBoard) {
2302 XtSetValues(XtNameToWidget(menuBarWidget,
2303 "menuOptions.Auto Raise Board"), args, 1);
2305 if (appData.autoSaveGames) {
2306 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2309 if (appData.saveGameFile[0] != NULLCHAR) {
2310 /* Can't turn this off from menu */
2311 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2313 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2317 if (appData.blindfold) {
2318 XtSetValues(XtNameToWidget(menuBarWidget,
2319 "menuOptions.Blindfold"), args, 1);
2321 if (appData.flashCount > 0) {
2322 XtSetValues(XtNameToWidget(menuBarWidget,
2323 "menuOptions.Flash Moves"),
2326 if (appData.getMoveList) {
2327 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2331 if (appData.highlightDragging) {
2332 XtSetValues(XtNameToWidget(menuBarWidget,
2333 "menuOptions.Highlight Dragging"),
2337 if (appData.highlightLastMove) {
2338 XtSetValues(XtNameToWidget(menuBarWidget,
2339 "menuOptions.Highlight Last Move"),
2342 if (appData.icsAlarm) {
2343 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2346 if (appData.ringBellAfterMoves) {
2347 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2350 if (appData.oldSaveStyle) {
2351 XtSetValues(XtNameToWidget(menuBarWidget,
2352 "menuOptions.Old Save Style"), args, 1);
2354 if (appData.periodicUpdates) {
2355 XtSetValues(XtNameToWidget(menuBarWidget,
2356 "menuOptions.Periodic Updates"), args, 1);
2358 if (appData.ponderNextMove) {
2359 XtSetValues(XtNameToWidget(menuBarWidget,
2360 "menuOptions.Ponder Next Move"), args, 1);
2362 if (appData.popupExitMessage) {
2363 XtSetValues(XtNameToWidget(menuBarWidget,
2364 "menuOptions.Popup Exit Message"), args, 1);
2366 if (appData.popupMoveErrors) {
2367 XtSetValues(XtNameToWidget(menuBarWidget,
2368 "menuOptions.Popup Move Errors"), args, 1);
2370 if (appData.premove) {
2371 XtSetValues(XtNameToWidget(menuBarWidget,
2372 "menuOptions.Premove"), args, 1);
2374 if (appData.quietPlay) {
2375 XtSetValues(XtNameToWidget(menuBarWidget,
2376 "menuOptions.Quiet Play"), args, 1);
2378 if (appData.showCoords) {
2379 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2382 if (appData.hideThinkingFromHuman) {
2383 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2386 if (appData.testLegality) {
2387 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2390 if (saveSettingsOnExit) {
2391 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2398 ReadBitmap(&wIconPixmap, "icon_white.bm",
2399 icon_white_bits, icon_white_width, icon_white_height);
2400 ReadBitmap(&bIconPixmap, "icon_black.bm",
2401 icon_black_bits, icon_black_width, icon_black_height);
2402 iconPixmap = wIconPixmap;
2404 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2405 XtSetValues(shellWidget, args, i);
2408 * Create a cursor for the board widget.
2410 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2411 XChangeWindowAttributes(xDisplay, xBoardWindow,
2412 CWCursor, &window_attributes);
2415 * Inhibit shell resizing.
2417 shellArgs[0].value = (XtArgVal) &w;
2418 shellArgs[1].value = (XtArgVal) &h;
2419 XtGetValues(shellWidget, shellArgs, 2);
2420 shellArgs[4].value = shellArgs[2].value = w;
2421 shellArgs[5].value = shellArgs[3].value = h;
2422 XtSetValues(shellWidget, &shellArgs[2], 4);
2423 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2424 marginH = h - boardHeight;
2426 CatchDeleteWindow(shellWidget, "QuitProc");
2431 if (appData.bitmapDirectory[0] != NULLCHAR) {
2438 /* Create regular pieces */
2439 if (!useImages) CreatePieces();
2444 if (appData.animate || appData.animateDragging)
2447 XtAugmentTranslations(formWidget,
2448 XtParseTranslationTable(globalTranslations));
2449 XtAugmentTranslations(boardWidget,
2450 XtParseTranslationTable(boardTranslations));
2451 XtAugmentTranslations(whiteTimerWidget,
2452 XtParseTranslationTable(whiteTranslations));
2453 XtAugmentTranslations(blackTimerWidget,
2454 XtParseTranslationTable(blackTranslations));
2456 /* Why is the following needed on some versions of X instead
2457 * of a translation? */
2458 XtAddEventHandler(boardWidget, ExposureMask, False,
2459 (XtEventHandler) EventProc, NULL);
2464 if (errorExitStatus == -1) {
2465 if (appData.icsActive) {
2466 /* We now wait until we see "login:" from the ICS before
2467 sending the logon script (problems with timestamp otherwise) */
2468 /*ICSInitScript();*/
2469 if (appData.icsInputBox) ICSInputBoxPopUp();
2473 signal(SIGWINCH, TermSizeSigHandler);
2475 signal(SIGINT, IntSigHandler);
2476 signal(SIGTERM, IntSigHandler);
2477 if (*appData.cmailGameName != NULLCHAR) {
2478 signal(SIGUSR1, CmailSigHandler);
2481 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2484 XtAppMainLoop(appContext);
2485 if (appData.debugMode) fclose(debugFP); // [DM] debug
2492 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2493 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2495 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2496 unlink(gameCopyFilename);
2497 unlink(gamePasteFilename);
2500 RETSIGTYPE TermSizeSigHandler(int sig)
2513 CmailSigHandler(sig)
2519 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2521 /* Activate call-back function CmailSigHandlerCallBack() */
2522 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2524 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2528 CmailSigHandlerCallBack(isr, closure, message, count, error)
2536 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2538 /**** end signal code ****/
2548 f = fopen(appData.icsLogon, "r");
2554 strcat(buf, appData.icsLogon);
2555 f = fopen(buf, "r");
2559 ProcessICSInitScript(f);
2566 EditCommentPopDown();
2581 if (!menuBarWidget) return;
2582 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2584 DisplayError("menuStep.Revert", 0);
2586 XtSetSensitive(w, !grey);
2591 SetMenuEnables(enab)
2595 if (!menuBarWidget) return;
2596 while (enab->name != NULL) {
2597 w = XtNameToWidget(menuBarWidget, enab->name);
2599 DisplayError(enab->name, 0);
2601 XtSetSensitive(w, enab->value);
2607 Enables icsEnables[] = {
2608 { "menuFile.Mail Move", False },
2609 { "menuFile.Reload CMail Message", False },
2610 { "menuMode.Machine Black", False },
2611 { "menuMode.Machine White", False },
2612 { "menuMode.Analysis Mode", False },
2613 { "menuMode.Analyze File", False },
2614 { "menuMode.Two Machines", False },
2616 { "menuHelp.Hint", False },
2617 { "menuHelp.Book", False },
2618 { "menuStep.Move Now", False },
2619 { "menuOptions.Periodic Updates", False },
2620 { "menuOptions.Hide Thinking", False },
2621 { "menuOptions.Ponder Next Move", False },
2626 Enables ncpEnables[] = {
2627 { "menuFile.Mail Move", False },
2628 { "menuFile.Reload CMail Message", False },
2629 { "menuMode.Machine White", False },
2630 { "menuMode.Machine Black", False },
2631 { "menuMode.Analysis Mode", False },
2632 { "menuMode.Analyze File", False },
2633 { "menuMode.Two Machines", False },
2634 { "menuMode.ICS Client", False },
2635 { "menuMode.ICS Input Box", False },
2636 { "Action", False },
2637 { "menuStep.Revert", False },
2638 { "menuStep.Move Now", False },
2639 { "menuStep.Retract Move", False },
2640 { "menuOptions.Auto Comment", False },
2641 { "menuOptions.Auto Flag", False },
2642 { "menuOptions.Auto Flip View", False },
2643 { "menuOptions.Auto Observe", False },
2644 { "menuOptions.Auto Raise Board", False },
2645 { "menuOptions.Get Move List", False },
2646 { "menuOptions.ICS Alarm", False },
2647 { "menuOptions.Move Sound", False },
2648 { "menuOptions.Quiet Play", False },
2649 { "menuOptions.Hide Thinking", False },
2650 { "menuOptions.Periodic Updates", False },
2651 { "menuOptions.Ponder Next Move", False },
2652 { "menuHelp.Hint", False },
2653 { "menuHelp.Book", False },
2657 Enables gnuEnables[] = {
2658 { "menuMode.ICS Client", False },
2659 { "menuMode.ICS Input Box", False },
2660 { "menuAction.Accept", False },
2661 { "menuAction.Decline", False },
2662 { "menuAction.Rematch", False },
2663 { "menuAction.Adjourn", False },
2664 { "menuAction.Stop Examining", False },
2665 { "menuAction.Stop Observing", False },
2666 { "menuStep.Revert", False },
2667 { "menuOptions.Auto Comment", False },
2668 { "menuOptions.Auto Observe", False },
2669 { "menuOptions.Auto Raise Board", False },
2670 { "menuOptions.Get Move List", False },
2671 { "menuOptions.Premove", False },
2672 { "menuOptions.Quiet Play", False },
2674 /* The next two options rely on SetCmailMode being called *after* */
2675 /* SetGNUMode so that when GNU is being used to give hints these */
2676 /* menu options are still available */
2678 { "menuFile.Mail Move", False },
2679 { "menuFile.Reload CMail Message", False },
2683 Enables cmailEnables[] = {
2685 { "menuAction.Call Flag", False },
2686 { "menuAction.Draw", True },
2687 { "menuAction.Adjourn", False },
2688 { "menuAction.Abort", False },
2689 { "menuAction.Stop Observing", False },
2690 { "menuAction.Stop Examining", False },
2691 { "menuFile.Mail Move", True },
2692 { "menuFile.Reload CMail Message", True },
2696 Enables trainingOnEnables[] = {
2697 { "menuMode.Edit Comment", False },
2698 { "menuMode.Pause", False },
2699 { "menuStep.Forward", False },
2700 { "menuStep.Backward", False },
2701 { "menuStep.Forward to End", False },
2702 { "menuStep.Back to Start", False },
2703 { "menuStep.Move Now", False },
2704 { "menuStep.Truncate Game", False },
2708 Enables trainingOffEnables[] = {
2709 { "menuMode.Edit Comment", True },
2710 { "menuMode.Pause", True },
2711 { "menuStep.Forward", True },
2712 { "menuStep.Backward", True },
2713 { "menuStep.Forward to End", True },
2714 { "menuStep.Back to Start", True },
2715 { "menuStep.Move Now", True },
2716 { "menuStep.Truncate Game", True },
2720 Enables machineThinkingEnables[] = {
2721 { "menuFile.Load Game", False },
2722 { "menuFile.Load Next Game", False },
2723 { "menuFile.Load Previous Game", False },
2724 { "menuFile.Reload Same Game", False },
2725 { "menuFile.Paste Game", False },
2726 { "menuFile.Load Position", False },
2727 { "menuFile.Load Next Position", False },
2728 { "menuFile.Load Previous Position", False },
2729 { "menuFile.Reload Same Position", False },
2730 { "menuFile.Paste Position", False },
2731 { "menuMode.Machine White", False },
2732 { "menuMode.Machine Black", False },
2733 { "menuMode.Two Machines", False },
2734 { "menuStep.Retract Move", False },
2738 Enables userThinkingEnables[] = {
2739 { "menuFile.Load Game", True },
2740 { "menuFile.Load Next Game", True },
2741 { "menuFile.Load Previous Game", True },
2742 { "menuFile.Reload Same Game", True },
2743 { "menuFile.Paste Game", True },
2744 { "menuFile.Load Position", True },
2745 { "menuFile.Load Next Position", True },
2746 { "menuFile.Load Previous Position", True },
2747 { "menuFile.Reload Same Position", True },
2748 { "menuFile.Paste Position", True },
2749 { "menuMode.Machine White", True },
2750 { "menuMode.Machine Black", True },
2751 { "menuMode.Two Machines", True },
2752 { "menuStep.Retract Move", True },
2758 SetMenuEnables(icsEnables);
2761 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2762 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2769 SetMenuEnables(ncpEnables);
2775 SetMenuEnables(gnuEnables);
2781 SetMenuEnables(cmailEnables);
2787 SetMenuEnables(trainingOnEnables);
2788 if (appData.showButtonBar) {
2789 XtSetSensitive(buttonBarWidget, False);
2795 SetTrainingModeOff()
2797 SetMenuEnables(trainingOffEnables);
2798 if (appData.showButtonBar) {
2799 XtSetSensitive(buttonBarWidget, True);
2804 SetUserThinkingEnables()
2806 if (appData.noChessProgram) return;
2807 SetMenuEnables(userThinkingEnables);
2811 SetMachineThinkingEnables()
2813 if (appData.noChessProgram) return;
2814 SetMenuEnables(machineThinkingEnables);
2816 case MachinePlaysBlack:
2817 case MachinePlaysWhite:
2818 case TwoMachinesPlay:
2819 XtSetSensitive(XtNameToWidget(menuBarWidget,
2820 ModeToWidgetName(gameMode)), True);
2827 #define Abs(n) ((n)<0 ? -(n) : (n))
2830 * Find a font that matches "pattern" that is as close as
2831 * possible to the targetPxlSize. Prefer fonts that are k
2832 * pixels smaller to fonts that are k pixels larger. The
2833 * pattern must be in the X Consortium standard format,
2834 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2835 * The return value should be freed with XtFree when no
2838 char *FindFont(pattern, targetPxlSize)
2842 char **fonts, *p, *best, *scalable, *scalableTail;
2843 int i, j, nfonts, minerr, err, pxlSize;
2846 char **missing_list;
2848 char *def_string, *base_fnt_lst, strInt[3];
2850 XFontStruct **fnt_list;
2852 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2853 sprintf(strInt, "%d", targetPxlSize);
2854 p = strstr(pattern, "--");
2855 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2856 strcat(base_fnt_lst, strInt);
2857 strcat(base_fnt_lst, strchr(p + 2, '-'));
2859 if ((fntSet = XCreateFontSet(xDisplay,
2863 &def_string)) == NULL) {
2865 fprintf(stderr, _("Unable to create font set.\n"));
2869 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2871 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2873 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2874 programName, pattern);
2882 for (i=0; i<nfonts; i++) {
2885 if (*p != '-') continue;
2887 if (*p == NULLCHAR) break;
2888 if (*p++ == '-') j++;
2890 if (j < 7) continue;
2893 scalable = fonts[i];
2896 err = pxlSize - targetPxlSize;
2897 if (Abs(err) < Abs(minerr) ||
2898 (minerr > 0 && err < 0 && -err == minerr)) {
2904 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
2905 /* If the error is too big and there is a scalable font,
2906 use the scalable font. */
2907 int headlen = scalableTail - scalable;
2908 p = (char *) XtMalloc(strlen(scalable) + 10);
2909 while (isdigit(*scalableTail)) scalableTail++;
2910 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
2912 p = (char *) XtMalloc(strlen(best) + 1);
2915 if (appData.debugMode) {
2916 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
2917 pattern, targetPxlSize, p);
2920 if (missing_count > 0)
2921 XFreeStringList(missing_list);
2922 XFreeFontSet(xDisplay, fntSet);
2924 XFreeFontNames(fonts);
2931 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
2932 | GCBackground | GCFunction | GCPlaneMask;
2933 XGCValues gc_values;
2936 gc_values.plane_mask = AllPlanes;
2937 gc_values.line_width = lineGap;
2938 gc_values.line_style = LineSolid;
2939 gc_values.function = GXcopy;
2941 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2942 gc_values.background = XBlackPixel(xDisplay, xScreen);
2943 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2945 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2946 gc_values.background = XWhitePixel(xDisplay, xScreen);
2947 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
2948 XSetFont(xDisplay, coordGC, coordFontID);
2950 // [HGM] make font for holdings counts (white on black0
2951 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2952 gc_values.background = XBlackPixel(xDisplay, xScreen);
2953 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
2954 XSetFont(xDisplay, countGC, countFontID);
2956 if (appData.monoMode) {
2957 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2958 gc_values.background = XWhitePixel(xDisplay, xScreen);
2959 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2961 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2962 gc_values.background = XBlackPixel(xDisplay, xScreen);
2963 lightSquareGC = wbPieceGC
2964 = XtGetGC(shellWidget, value_mask, &gc_values);
2966 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2967 gc_values.background = XWhitePixel(xDisplay, xScreen);
2968 darkSquareGC = bwPieceGC
2969 = XtGetGC(shellWidget, value_mask, &gc_values);
2971 if (DefaultDepth(xDisplay, xScreen) == 1) {
2972 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
2973 gc_values.function = GXcopyInverted;
2974 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
2975 gc_values.function = GXcopy;
2976 if (XBlackPixel(xDisplay, xScreen) == 1) {
2977 bwPieceGC = darkSquareGC;
2978 wbPieceGC = copyInvertedGC;
2980 bwPieceGC = copyInvertedGC;
2981 wbPieceGC = lightSquareGC;
2985 gc_values.foreground = highlightSquareColor;
2986 gc_values.background = highlightSquareColor;
2987 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2989 gc_values.foreground = premoveHighlightColor;
2990 gc_values.background = premoveHighlightColor;
2991 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2993 gc_values.foreground = lightSquareColor;
2994 gc_values.background = darkSquareColor;
2995 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2997 gc_values.foreground = darkSquareColor;
2998 gc_values.background = lightSquareColor;
2999 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3001 gc_values.foreground = jailSquareColor;
3002 gc_values.background = jailSquareColor;
3003 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3005 gc_values.foreground = whitePieceColor;
3006 gc_values.background = darkSquareColor;
3007 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3009 gc_values.foreground = whitePieceColor;
3010 gc_values.background = lightSquareColor;
3011 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3013 gc_values.foreground = whitePieceColor;
3014 gc_values.background = jailSquareColor;
3015 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3017 gc_values.foreground = blackPieceColor;
3018 gc_values.background = darkSquareColor;
3019 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3021 gc_values.foreground = blackPieceColor;
3022 gc_values.background = lightSquareColor;
3023 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3025 gc_values.foreground = blackPieceColor;
3026 gc_values.background = jailSquareColor;
3027 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3031 void loadXIM(xim, xmask, filename, dest, mask)
3044 fp = fopen(filename, "rb");
3046 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3053 for (y=0; y<h; ++y) {
3054 for (x=0; x<h; ++x) {
3059 XPutPixel(xim, x, y, blackPieceColor);
3061 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3064 XPutPixel(xim, x, y, darkSquareColor);
3066 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3069 XPutPixel(xim, x, y, whitePieceColor);
3071 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3074 XPutPixel(xim, x, y, lightSquareColor);
3076 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3082 /* create Pixmap of piece */
3083 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3085 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3088 /* create Pixmap of clipmask
3089 Note: We assume the white/black pieces have the same
3090 outline, so we make only 6 masks. This is okay
3091 since the XPM clipmask routines do the same. */
3093 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3095 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3098 /* now create the 1-bit version */
3099 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3102 values.foreground = 1;
3103 values.background = 0;
3105 /* Don't use XtGetGC, not read only */
3106 maskGC = XCreateGC(xDisplay, *mask,
3107 GCForeground | GCBackground, &values);
3108 XCopyPlane(xDisplay, temp, *mask, maskGC,
3109 0, 0, squareSize, squareSize, 0, 0, 1);
3110 XFreePixmap(xDisplay, temp);
3115 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3117 void CreateXIMPieces()
3122 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3127 /* The XSynchronize calls were copied from CreatePieces.
3128 Not sure if needed, but can't hurt */
3129 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3132 /* temp needed by loadXIM() */
3133 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3134 0, 0, ss, ss, AllPlanes, XYPixmap);
3136 if (strlen(appData.pixmapDirectory) == 0) {
3140 if (appData.monoMode) {
3141 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3145 fprintf(stderr, _("\nLoading XIMs...\n"));
3147 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3148 fprintf(stderr, "%d", piece+1);
3149 for (kind=0; kind<4; kind++) {
3150 fprintf(stderr, ".");
3151 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3152 ExpandPathName(appData.pixmapDirectory),
3153 piece <= (int) WhiteKing ? "" : "w",
3154 pieceBitmapNames[piece],
3156 ximPieceBitmap[kind][piece] =
3157 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3158 0, 0, ss, ss, AllPlanes, XYPixmap);
3159 if (appData.debugMode)
3160 fprintf(stderr, _("(File:%s:) "), buf);
3161 loadXIM(ximPieceBitmap[kind][piece],
3163 &(xpmPieceBitmap2[kind][piece]),
3164 &(ximMaskPm2[piece]));
3165 if(piece <= (int)WhiteKing)
3166 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3168 fprintf(stderr," ");
3170 /* Load light and dark squares */
3171 /* If the LSQ and DSQ pieces don't exist, we will
3172 draw them with solid squares. */
3173 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3174 if (access(buf, 0) != 0) {
3178 fprintf(stderr, _("light square "));
3180 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3181 0, 0, ss, ss, AllPlanes, XYPixmap);
3182 if (appData.debugMode)
3183 fprintf(stderr, _("(File:%s:) "), buf);
3185 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3186 fprintf(stderr, _("dark square "));
3187 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3188 ExpandPathName(appData.pixmapDirectory), ss);
3189 if (appData.debugMode)
3190 fprintf(stderr, _("(File:%s:) "), buf);
3192 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3193 0, 0, ss, ss, AllPlanes, XYPixmap);
3194 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3195 xpmJailSquare = xpmLightSquare;
3197 fprintf(stderr, _("Done.\n"));
3199 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3203 void CreateXPMPieces()
3207 u_int ss = squareSize;
3209 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3210 XpmColorSymbol symbols[4];
3212 /* The XSynchronize calls were copied from CreatePieces.
3213 Not sure if needed, but can't hurt */
3214 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3216 /* Setup translations so piece colors match square colors */
3217 symbols[0].name = "light_piece";
3218 symbols[0].value = appData.whitePieceColor;
3219 symbols[1].name = "dark_piece";
3220 symbols[1].value = appData.blackPieceColor;
3221 symbols[2].name = "light_square";
3222 symbols[2].value = appData.lightSquareColor;
3223 symbols[3].name = "dark_square";
3224 symbols[3].value = appData.darkSquareColor;
3226 attr.valuemask = XpmColorSymbols;
3227 attr.colorsymbols = symbols;
3228 attr.numsymbols = 4;
3230 if (appData.monoMode) {
3231 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3235 if (strlen(appData.pixmapDirectory) == 0) {
3236 XpmPieces* pieces = builtInXpms;
3239 while (pieces->size != squareSize && pieces->size) pieces++;
3240 if (!pieces->size) {
3241 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3244 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3245 for (kind=0; kind<4; kind++) {
3247 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3248 pieces->xpm[piece][kind],
3249 &(xpmPieceBitmap2[kind][piece]),
3250 NULL, &attr)) != 0) {
3251 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3255 if(piece <= (int) WhiteKing)
3256 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3260 xpmJailSquare = xpmLightSquare;
3264 fprintf(stderr, _("\nLoading XPMs...\n"));
3267 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3268 fprintf(stderr, "%d ", piece+1);
3269 for (kind=0; kind<4; kind++) {
3270 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3271 ExpandPathName(appData.pixmapDirectory),
3272 piece > (int) WhiteKing ? "w" : "",
3273 pieceBitmapNames[piece],
3275 if (appData.debugMode) {
3276 fprintf(stderr, _("(File:%s:) "), buf);
3278 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3279 &(xpmPieceBitmap2[kind][piece]),
3280 NULL, &attr)) != 0) {
3281 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3282 // [HGM] missing: read of unorthodox piece failed; substitute King.
3283 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3284 ExpandPathName(appData.pixmapDirectory),
3286 if (appData.debugMode) {
3287 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3289 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3290 &(xpmPieceBitmap2[kind][piece]),
3294 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3299 if(piece <= (int) WhiteKing)
3300 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3303 /* Load light and dark squares */
3304 /* If the LSQ and DSQ pieces don't exist, we will
3305 draw them with solid squares. */
3306 fprintf(stderr, _("light square "));
3307 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3308 if (access(buf, 0) != 0) {
3312 if (appData.debugMode)
3313 fprintf(stderr, _("(File:%s:) "), buf);
3315 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3316 &xpmLightSquare, NULL, &attr)) != 0) {
3317 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3320 fprintf(stderr, _("dark square "));
3321 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3322 ExpandPathName(appData.pixmapDirectory), ss);
3323 if (appData.debugMode) {
3324 fprintf(stderr, _("(File:%s:) "), buf);
3326 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3327 &xpmDarkSquare, NULL, &attr)) != 0) {
3328 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3332 xpmJailSquare = xpmLightSquare;
3333 fprintf(stderr, _("Done.\n"));
3335 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3338 #endif /* HAVE_LIBXPM */
3341 /* No built-in bitmaps */
3346 u_int ss = squareSize;
3348 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3351 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3352 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3353 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3354 pieceBitmapNames[piece],
3355 ss, kind == SOLID ? 's' : 'o');
3356 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3357 if(piece <= (int)WhiteKing)
3358 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3362 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3366 /* With built-in bitmaps */
3369 BuiltInBits* bib = builtInBits;
3372 u_int ss = squareSize;
3374 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3377 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3379 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3380 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3381 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3382 pieceBitmapNames[piece],
3383 ss, kind == SOLID ? 's' : 'o');
3384 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3385 bib->bits[kind][piece], ss, ss);
3386 if(piece <= (int)WhiteKing)
3387 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3391 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3396 void ReadBitmap(pm, name, bits, wreq, hreq)
3399 unsigned char bits[];
3405 char msg[MSG_SIZ], fullname[MSG_SIZ];
3407 if (*appData.bitmapDirectory != NULLCHAR) {
3408 strcpy(fullname, appData.bitmapDirectory);
3409 strcat(fullname, "/");
3410 strcat(fullname, name);
3411 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3412 &w, &h, pm, &x_hot, &y_hot);
3413 fprintf(stderr, "load %s\n", name);
3414 if (errcode != BitmapSuccess) {
3416 case BitmapOpenFailed:
3417 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3419 case BitmapFileInvalid:
3420 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3422 case BitmapNoMemory:
3423 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3427 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3431 fprintf(stderr, _("%s: %s...using built-in\n"),
3433 } else if (w != wreq || h != hreq) {
3435 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3436 programName, fullname, w, h, wreq, hreq);
3442 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3451 if (lineGap == 0) return;
3453 /* [HR] Split this into 2 loops for non-square boards. */
3455 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3456 gridSegments[i].x1 = 0;
3457 gridSegments[i].x2 =
3458 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3459 gridSegments[i].y1 = gridSegments[i].y2
3460 = lineGap / 2 + (i * (squareSize + lineGap));
3463 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3464 gridSegments[j + i].y1 = 0;
3465 gridSegments[j + i].y2 =
3466 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3467 gridSegments[j + i].x1 = gridSegments[j + i].x2
3468 = lineGap / 2 + (j * (squareSize + lineGap));
3472 static void MenuBarSelect(w, addr, index)
3477 XtActionProc proc = (XtActionProc) addr;
3479 (proc)(NULL, NULL, NULL, NULL);
3482 void CreateMenuBarPopup(parent, name, mb)
3492 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3495 XtSetArg(args[j], XtNleftMargin, 20); j++;
3496 XtSetArg(args[j], XtNrightMargin, 20); j++;
3498 while (mi->string != NULL) {
3499 if (strcmp(mi->string, "----") == 0) {
3500 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3503 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3504 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3506 XtAddCallback(entry, XtNcallback,
3507 (XtCallbackProc) MenuBarSelect,
3508 (caddr_t) mi->proc);
3514 Widget CreateMenuBar(mb)
3518 Widget anchor, menuBar;
3520 char menuName[MSG_SIZ];
3523 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3524 XtSetArg(args[j], XtNvSpace, 0); j++;
3525 XtSetArg(args[j], XtNborderWidth, 0); j++;
3526 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3527 formWidget, args, j);
3529 while (mb->name != NULL) {
3530 strcpy(menuName, "menu");
3531 strcat(menuName, mb->name);
3533 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3536 shortName[0] = _(mb->name)[0];
3537 shortName[1] = NULLCHAR;
3538 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3541 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3544 XtSetArg(args[j], XtNborderWidth, 0); j++;
3545 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3547 CreateMenuBarPopup(menuBar, menuName, mb);
3553 Widget CreateButtonBar(mi)
3557 Widget button, buttonBar;
3561 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3563 XtSetArg(args[j], XtNhSpace, 0); j++;
3565 XtSetArg(args[j], XtNborderWidth, 0); j++;
3566 XtSetArg(args[j], XtNvSpace, 0); j++;
3567 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3568 formWidget, args, j);
3570 while (mi->string != NULL) {
3573 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3574 XtSetArg(args[j], XtNborderWidth, 0); j++;
3576 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3577 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3578 buttonBar, args, j);
3579 XtAddCallback(button, XtNcallback,
3580 (XtCallbackProc) MenuBarSelect,
3581 (caddr_t) mi->proc);
3588 CreatePieceMenu(name, color)
3595 ChessSquare selection;
3597 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3598 boardWidget, args, 0);
3600 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3601 String item = pieceMenuStrings[color][i];
3603 if (strcmp(item, "----") == 0) {
3604 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3607 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3608 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3610 selection = pieceMenuTranslation[color][i];
3611 XtAddCallback(entry, XtNcallback,
3612 (XtCallbackProc) PieceMenuSelect,
3613 (caddr_t) selection);
3614 if (selection == WhitePawn || selection == BlackPawn) {
3615 XtSetArg(args[0], XtNpopupOnEntry, entry);
3616 XtSetValues(menu, args, 1);
3629 ChessSquare selection;
3631 whitePieceMenu = CreatePieceMenu("menuW", 0);
3632 blackPieceMenu = CreatePieceMenu("menuB", 1);
3634 XtRegisterGrabAction(PieceMenuPopup, True,
3635 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3636 GrabModeAsync, GrabModeAsync);
3638 XtSetArg(args[0], XtNlabel, _("Drop"));
3639 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3640 boardWidget, args, 1);
3641 for (i = 0; i < DROP_MENU_SIZE; i++) {
3642 String item = dropMenuStrings[i];
3644 if (strcmp(item, "----") == 0) {
3645 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3648 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3649 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3651 selection = dropMenuTranslation[i];
3652 XtAddCallback(entry, XtNcallback,
3653 (XtCallbackProc) DropMenuSelect,
3654 (caddr_t) selection);
3659 void SetupDropMenu()
3667 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3668 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3669 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3670 dmEnables[i].piece);
3671 XtSetSensitive(entry, p != NULL || !appData.testLegality
3672 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3673 && !appData.icsActive));
3675 while (p && *p++ == dmEnables[i].piece) count++;
3676 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3678 XtSetArg(args[j], XtNlabel, label); j++;
3679 XtSetValues(entry, args, j);
3683 void PieceMenuPopup(w, event, params, num_params)
3687 Cardinal *num_params;
3690 if (event->type != ButtonPress) return;
3691 if (errorUp) ErrorPopDown();
3695 whichMenu = params[0];
3697 case IcsPlayingWhite:
3698 case IcsPlayingBlack:
3700 case MachinePlaysWhite:
3701 case MachinePlaysBlack:
3702 if (appData.testLegality &&
3703 gameInfo.variant != VariantBughouse &&
3704 gameInfo.variant != VariantCrazyhouse) return;
3706 whichMenu = "menuD";
3712 if (((pmFromX = EventToSquare(event->xbutton.x, BOARD_WIDTH)) < 0) ||
3713 ((pmFromY = EventToSquare(event->xbutton.y, BOARD_HEIGHT)) < 0)) {
3714 pmFromX = pmFromY = -1;
3718 pmFromX = BOARD_WIDTH - 1 - pmFromX;
3720 pmFromY = BOARD_HEIGHT - 1 - pmFromY;
3722 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3725 static void PieceMenuSelect(w, piece, junk)
3730 if (pmFromX < 0 || pmFromY < 0) return;
3731 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3734 static void DropMenuSelect(w, piece, junk)
3739 if (pmFromX < 0 || pmFromY < 0) return;
3740 DropMenuEvent(piece, pmFromX, pmFromY);
3743 void WhiteClock(w, event, prms, nprms)
3749 if (gameMode == EditPosition || gameMode == IcsExamining) {
3750 SetWhiteToPlayEvent();
3751 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3756 void BlackClock(w, event, prms, nprms)
3762 if (gameMode == EditPosition || gameMode == IcsExamining) {
3763 SetBlackToPlayEvent();
3764 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3771 * If the user selects on a border boundary, return -1; if off the board,
3772 * return -2. Otherwise map the event coordinate to the square.
3774 int EventToSquare(x, limit)
3782 if ((x % (squareSize + lineGap)) >= squareSize)
3784 x /= (squareSize + lineGap);
3790 static void do_flash_delay(msec)
3796 static void drawHighlight(file, rank, gc)
3802 if (lineGap == 0 || appData.blindfold) return;
3805 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3806 (squareSize + lineGap);
3807 y = lineGap/2 + rank * (squareSize + lineGap);
3809 x = lineGap/2 + file * (squareSize + lineGap);
3810 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3811 (squareSize + lineGap);
3814 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3815 squareSize+lineGap, squareSize+lineGap);
3818 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3819 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3822 SetHighlights(fromX, fromY, toX, toY)
3823 int fromX, fromY, toX, toY;
3825 if (hi1X != fromX || hi1Y != fromY) {
3826 if (hi1X >= 0 && hi1Y >= 0) {
3827 drawHighlight(hi1X, hi1Y, lineGC);
3829 if (fromX >= 0 && fromY >= 0) {
3830 drawHighlight(fromX, fromY, highlineGC);
3833 if (hi2X != toX || hi2Y != toY) {
3834 if (hi2X >= 0 && hi2Y >= 0) {
3835 drawHighlight(hi2X, hi2Y, lineGC);
3837 if (toX >= 0 && toY >= 0) {
3838 drawHighlight(toX, toY, highlineGC);
3850 SetHighlights(-1, -1, -1, -1);
3855 SetPremoveHighlights(fromX, fromY, toX, toY)
3856 int fromX, fromY, toX, toY;
3858 if (pm1X != fromX || pm1Y != fromY) {
3859 if (pm1X >= 0 && pm1Y >= 0) {
3860 drawHighlight(pm1X, pm1Y, lineGC);
3862 if (fromX >= 0 && fromY >= 0) {
3863 drawHighlight(fromX, fromY, prelineGC);
3866 if (pm2X != toX || pm2Y != toY) {
3867 if (pm2X >= 0 && pm2Y >= 0) {
3868 drawHighlight(pm2X, pm2Y, lineGC);
3870 if (toX >= 0 && toY >= 0) {
3871 drawHighlight(toX, toY, prelineGC);
3881 ClearPremoveHighlights()
3883 SetPremoveHighlights(-1, -1, -1, -1);
3886 static void BlankSquare(x, y, color, piece, dest)
3891 if (useImages && useImageSqs) {
3895 pm = xpmLightSquare;
3900 case 2: /* neutral */
3905 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
3906 squareSize, squareSize, x, y);
3916 case 2: /* neutral */
3921 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
3926 I split out the routines to draw a piece so that I could
3927 make a generic flash routine.
3929 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
3931 int square_color, x, y;
3934 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3935 switch (square_color) {
3937 case 2: /* neutral */
3939 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3940 ? *pieceToOutline(piece)
3941 : *pieceToSolid(piece),
3942 dest, bwPieceGC, 0, 0,
3943 squareSize, squareSize, x, y);
3946 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3947 ? *pieceToSolid(piece)
3948 : *pieceToOutline(piece),
3949 dest, wbPieceGC, 0, 0,
3950 squareSize, squareSize, x, y);
3955 static void monoDrawPiece(piece, square_color, x, y, dest)
3957 int square_color, x, y;
3960 switch (square_color) {
3962 case 2: /* neutral */
3964 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3965 ? *pieceToOutline(piece)
3966 : *pieceToSolid(piece),
3967 dest, bwPieceGC, 0, 0,
3968 squareSize, squareSize, x, y, 1);
3971 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3972 ? *pieceToSolid(piece)
3973 : *pieceToOutline(piece),
3974 dest, wbPieceGC, 0, 0,
3975 squareSize, squareSize, x, y, 1);
3980 static void colorDrawPiece(piece, square_color, x, y, dest)
3982 int square_color, x, y;
3985 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
3986 switch (square_color) {
3988 XCopyPlane(xDisplay, *pieceToSolid(piece),
3989 dest, (int) piece < (int) BlackPawn
3990 ? wlPieceGC : blPieceGC, 0, 0,
3991 squareSize, squareSize, x, y, 1);
3994 XCopyPlane(xDisplay, *pieceToSolid(piece),
3995 dest, (int) piece < (int) BlackPawn
3996 ? wdPieceGC : bdPieceGC, 0, 0,
3997 squareSize, squareSize, x, y, 1);
3999 case 2: /* neutral */
4001 XCopyPlane(xDisplay, *pieceToSolid(piece),
4002 dest, (int) piece < (int) BlackPawn
4003 ? wjPieceGC : bjPieceGC, 0, 0,
4004 squareSize, squareSize, x, y, 1);
4009 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4011 int square_color, x, y;
4016 switch (square_color) {
4018 case 2: /* neutral */
4020 if ((int)piece < (int) BlackPawn) {
4028 if ((int)piece < (int) BlackPawn) {
4036 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4037 dest, wlPieceGC, 0, 0,
4038 squareSize, squareSize, x, y);
4041 typedef void (*DrawFunc)();
4043 DrawFunc ChooseDrawFunc()
4045 if (appData.monoMode) {
4046 if (DefaultDepth(xDisplay, xScreen) == 1) {
4047 return monoDrawPiece_1bit;
4049 return monoDrawPiece;
4053 return colorDrawPieceImage;
4055 return colorDrawPiece;
4059 /* [HR] determine square color depending on chess variant. */
4060 static int SquareColor(row, column)
4065 if (gameInfo.variant == VariantXiangqi) {
4066 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4068 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4070 } else if (row <= 4) {
4076 square_color = ((column + row) % 2) == 1;
4079 /* [hgm] holdings: next line makes all holdings squares light */
4080 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4082 return square_color;
4085 void DrawSquare(row, column, piece, do_flash)
4086 int row, column, do_flash;
4089 int square_color, x, y, direction, font_ascent, font_descent;
4092 XCharStruct overall;
4096 /* Calculate delay in milliseconds (2-delays per complete flash) */
4097 flash_delay = 500 / appData.flashRate;
4100 x = lineGap + ((BOARD_WIDTH-1)-column) *
4101 (squareSize + lineGap);
4102 y = lineGap + row * (squareSize + lineGap);
4104 x = lineGap + column * (squareSize + lineGap);
4105 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4106 (squareSize + lineGap);
4109 square_color = SquareColor(row, column);
4111 if ( // [HGM] holdings: blank out area between board and holdings
4112 column == BOARD_LEFT-1 || column == BOARD_RGHT
4113 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4114 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4115 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4117 // [HGM] print piece counts next to holdings
4118 string[1] = NULLCHAR;
4119 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4120 string[0] = '0' + piece;
4121 XTextExtents(countFontStruct, string, 1, &direction,
4122 &font_ascent, &font_descent, &overall);
4123 if (appData.monoMode) {
4124 XDrawImageString(xDisplay, xBoardWindow, countGC,
4125 x + squareSize - overall.width - 2,
4126 y + font_ascent + 1, string, 1);
4128 XDrawString(xDisplay, xBoardWindow, countGC,
4129 x + squareSize - overall.width - 2,
4130 y + font_ascent + 1, string, 1);
4133 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4134 string[0] = '0' + piece;
4135 XTextExtents(countFontStruct, string, 1, &direction,
4136 &font_ascent, &font_descent, &overall);
4137 if (appData.monoMode) {
4138 XDrawImageString(xDisplay, xBoardWindow, countGC,
4139 x + 2, y + font_ascent + 1, string, 1);
4141 XDrawString(xDisplay, xBoardWindow, countGC,
4142 x + 2, y + font_ascent + 1, string, 1);
4146 if (piece == EmptySquare || appData.blindfold) {
4147 BlankSquare(x, y, square_color, piece, xBoardWindow);
4149 drawfunc = ChooseDrawFunc();
4150 if (do_flash && appData.flashCount > 0) {
4151 for (i=0; i<appData.flashCount; ++i) {
4153 drawfunc(piece, square_color, x, y, xBoardWindow);
4154 XSync(xDisplay, False);
4155 do_flash_delay(flash_delay);
4157 BlankSquare(x, y, square_color, piece, xBoardWindow);
4158 XSync(xDisplay, False);
4159 do_flash_delay(flash_delay);
4162 drawfunc(piece, square_color, x, y, xBoardWindow);
4166 string[1] = NULLCHAR;
4167 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4168 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4169 string[0] = 'a' + column - BOARD_LEFT;
4170 XTextExtents(coordFontStruct, string, 1, &direction,
4171 &font_ascent, &font_descent, &overall);
4172 if (appData.monoMode) {
4173 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4174 x + squareSize - overall.width - 2,
4175 y + squareSize - font_descent - 1, string, 1);
4177 XDrawString(xDisplay, xBoardWindow, coordGC,
4178 x + squareSize - overall.width - 2,
4179 y + squareSize - font_descent - 1, string, 1);
4182 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4183 string[0] = ONE + row;
4184 XTextExtents(coordFontStruct, string, 1, &direction,
4185 &font_ascent, &font_descent, &overall);
4186 if (appData.monoMode) {
4187 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4188 x + 2, y + font_ascent + 1, string, 1);
4190 XDrawString(xDisplay, xBoardWindow, coordGC,
4191 x + 2, y + font_ascent + 1, string, 1);
4197 /* Why is this needed on some versions of X? */
4198 void EventProc(widget, unused, event)
4203 if (!XtIsRealized(widget))
4206 switch (event->type) {
4208 if (event->xexpose.count > 0) return; /* no clipping is done */
4209 XDrawPosition(widget, True, NULL);
4217 void DrawPosition(fullRedraw, board)
4218 /*Boolean*/int fullRedraw;
4221 XDrawPosition(boardWidget, fullRedraw, board);
4224 /* Returns 1 if there are "too many" differences between b1 and b2
4225 (i.e. more than 1 move was made) */
4226 static int too_many_diffs(b1, b2)
4232 for (i=0; i<BOARD_HEIGHT; ++i) {
4233 for (j=0; j<BOARD_WIDTH; ++j) {
4234 if (b1[i][j] != b2[i][j]) {
4235 if (++c > 4) /* Castling causes 4 diffs */
4244 /* Matrix describing castling maneuvers */
4245 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4246 static int castling_matrix[4][5] = {
4247 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4248 { 0, 7, 4, 5, 6 }, /* 0-0, white */