2 * xboard.c -- X front end for XBoard
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
8 * 2007, 2008, 2009 Free Software Foundation, Inc.
10 * The following terms apply to Digital Equipment Corporation's copyright
12 * ------------------------------------------------------------------------
15 * Permission to use, copy, modify, and distribute this software and its
16 * documentation for any purpose and without fee is hereby granted,
17 * provided that the above copyright notice appear in all copies and that
18 * both that copyright notice and this permission notice appear in
19 * supporting documentation, and that the name of Digital not be
20 * used in advertising or publicity pertaining to distribution of the
21 * software without specific, written prior permission.
23 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
30 * ------------------------------------------------------------------------
32 * The following terms apply to the enhanced version of XBoard
33 * distributed by the Free Software Foundation:
34 * ------------------------------------------------------------------------
36 * GNU XBoard is free software: you can redistribute it and/or modify
37 * it under the terms of the GNU General Public License as published by
38 * the Free Software Foundation, either version 3 of the License, or (at
39 * your option) any later version.
41 * GNU XBoard is distributed in the hope that it will be useful, but
42 * WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44 * General Public License for more details.
46 * You should have received a copy of the GNU General Public License
47 * along with this program. If not, see http://www.gnu.org/licenses/. *
49 *------------------------------------------------------------------------
50 ** See the file ChangeLog for a revision history. */
58 #include <sys/types.h>
63 # if HAVE_SYS_SOCKET_H
64 # include <sys/socket.h>
65 # include <netinet/in.h>
67 # else /* not HAVE_SYS_SOCKET_H */
68 # if HAVE_LAN_SOCKET_H
69 # include <lan/socket.h>
71 # include <lan/netdb.h>
72 # else /* not HAVE_LAN_SOCKET_H */
73 # define OMIT_SOCKETS 1
74 # endif /* not HAVE_LAN_SOCKET_H */
75 # endif /* not HAVE_SYS_SOCKET_H */
76 #endif /* !OMIT_SOCKETS */
81 #else /* not STDC_HEADERS */
82 extern char *getenv();
85 # else /* not HAVE_STRING_H */
87 # endif /* not HAVE_STRING_H */
88 #endif /* not STDC_HEADERS */
91 # include <sys/fcntl.h>
92 #else /* not HAVE_SYS_FCNTL_H */
95 # endif /* HAVE_FCNTL_H */
96 #endif /* not HAVE_SYS_FCNTL_H */
98 #if HAVE_SYS_SYSTEMINFO_H
99 # include <sys/systeminfo.h>
100 #endif /* HAVE_SYS_SYSTEMINFO_H */
102 #if TIME_WITH_SYS_TIME
103 # include <sys/time.h>
107 # include <sys/time.h>
118 # include <sys/wait.h>
123 # define NAMLEN(dirent) strlen((dirent)->d_name)
124 # define HAVE_DIR_STRUCT
126 # define dirent direct
127 # define NAMLEN(dirent) (dirent)->d_namlen
129 # include <sys/ndir.h>
130 # define HAVE_DIR_STRUCT
133 # include <sys/dir.h>
134 # define HAVE_DIR_STRUCT
138 # define HAVE_DIR_STRUCT
142 #include <X11/Intrinsic.h>
143 #include <X11/StringDefs.h>
144 #include <X11/Shell.h>
145 #include <X11/cursorfont.h>
146 #include <X11/Xatom.h>
147 #include <X11/Xmu/Atoms.h>
149 #include <X11/Xaw3d/Dialog.h>
150 #include <X11/Xaw3d/Form.h>
151 #include <X11/Xaw3d/List.h>
152 #include <X11/Xaw3d/Label.h>
153 #include <X11/Xaw3d/SimpleMenu.h>
154 #include <X11/Xaw3d/SmeBSB.h>
155 #include <X11/Xaw3d/SmeLine.h>
156 #include <X11/Xaw3d/Box.h>
157 #include <X11/Xaw3d/MenuButton.h>
158 #include <X11/Xaw3d/Text.h>
159 #include <X11/Xaw3d/AsciiText.h>
161 #include <X11/Xaw/Dialog.h>
162 #include <X11/Xaw/Form.h>
163 #include <X11/Xaw/List.h>
164 #include <X11/Xaw/Label.h>
165 #include <X11/Xaw/SimpleMenu.h>
166 #include <X11/Xaw/SmeBSB.h>
167 #include <X11/Xaw/SmeLine.h>
168 #include <X11/Xaw/Box.h>
169 #include <X11/Xaw/MenuButton.h>
170 #include <X11/Xaw/Text.h>
171 #include <X11/Xaw/AsciiText.h>
174 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
179 #include "pixmaps/pixmaps.h"
180 #define IMAGE_EXT "xpm"
182 #define IMAGE_EXT "xim"
183 #include "bitmaps/bitmaps.h"
186 #include "bitmaps/icon_white.bm"
187 #include "bitmaps/icon_black.bm"
188 #include "bitmaps/checkmark.bm"
190 #include "frontend.h"
195 #include "xgamelist.h"
196 #include "xhistory.h"
197 #include "xedittags.h"
200 // must be moved to xengineoutput.h
202 void EngineOutputProc P((Widget w, XEvent *event,
203 String *prms, Cardinal *nprms));
204 void EvalGraphProc P((Widget w, XEvent *event,
205 String *prms, Cardinal *nprms));
212 #define usleep(t) _sleep2(((t)+500)/1000)
216 # define _(s) gettext (s)
217 # define N_(s) gettext_noop (s)
233 int main P((int argc, char **argv));
234 RETSIGTYPE CmailSigHandler P((int sig));
235 RETSIGTYPE IntSigHandler P((int sig));
236 RETSIGTYPE TermSizeSigHandler P((int sig));
237 void CreateGCs P((void));
238 void CreateXIMPieces P((void));
239 void CreateXPMPieces P((void));
240 void CreatePieces P((void));
241 void CreatePieceMenus P((void));
242 Widget CreateMenuBar P((Menu *mb));
243 Widget CreateButtonBar P ((MenuItem *mi));
244 char *FindFont P((char *pattern, int targetPxlSize));
245 void PieceMenuPopup P((Widget w, XEvent *event,
246 String *params, Cardinal *num_params));
247 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
248 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
249 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
250 u_int wreq, u_int hreq));
251 void CreateGrid P((void));
252 int EventToSquare P((int x, int limit));
253 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
254 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
255 void HandleUserMove P((Widget w, XEvent *event,
256 String *prms, Cardinal *nprms));
257 void AnimateUserMove P((Widget w, XEvent * event,
258 String * params, Cardinal * nParams));
259 void WhiteClock P((Widget w, XEvent *event,
260 String *prms, Cardinal *nprms));
261 void BlackClock P((Widget w, XEvent *event,
262 String *prms, Cardinal *nprms));
263 void DrawPositionProc P((Widget w, XEvent *event,
264 String *prms, Cardinal *nprms));
265 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
267 void CommentPopUp P((char *title, char *label));
268 void CommentPopDown P((void));
269 void CommentCallback P((Widget w, XtPointer client_data,
270 XtPointer call_data));
271 void ICSInputBoxPopUp P((void));
272 void ICSInputBoxPopDown P((void));
273 void FileNamePopUp P((char *label, char *def,
274 FileProc proc, char *openMode));
275 void FileNamePopDown P((void));
276 void FileNameCallback P((Widget w, XtPointer client_data,
277 XtPointer call_data));
278 void FileNameAction P((Widget w, XEvent *event,
279 String *prms, Cardinal *nprms));
280 void AskQuestionReplyAction P((Widget w, XEvent *event,
281 String *prms, Cardinal *nprms));
282 void AskQuestionProc P((Widget w, XEvent *event,
283 String *prms, Cardinal *nprms));
284 void AskQuestionPopDown P((void));
285 void PromotionPopDown P((void));
286 void PromotionCallback P((Widget w, XtPointer client_data,
287 XtPointer call_data));
288 void EditCommentPopDown P((void));
289 void EditCommentCallback P((Widget w, XtPointer client_data,
290 XtPointer call_data));
291 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
292 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
293 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
294 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
296 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
298 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
300 void LoadPositionProc P((Widget w, XEvent *event,
301 String *prms, Cardinal *nprms));
302 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
304 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
306 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
308 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
310 void PastePositionProc P((Widget w, XEvent *event, String *prms,
312 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
313 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
314 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
315 void SavePositionProc P((Widget w, XEvent *event,
316 String *prms, Cardinal *nprms));
317 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
318 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
320 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
321 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
322 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
324 void MachineWhiteProc P((Widget w, XEvent *event,
325 String *prms, Cardinal *nprms));
326 void AnalyzeModeProc P((Widget w, XEvent *event,
327 String *prms, Cardinal *nprms));
328 void AnalyzeFileProc P((Widget w, XEvent *event,
329 String *prms, Cardinal *nprms));
330 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
332 void IcsClientProc P((Widget w, XEvent *event, String *prms,
334 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
335 void EditPositionProc P((Widget w, XEvent *event,
336 String *prms, Cardinal *nprms));
337 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
338 void EditCommentProc P((Widget w, XEvent *event,
339 String *prms, Cardinal *nprms));
340 void IcsInputBoxProc P((Widget w, XEvent *event,
341 String *prms, Cardinal *nprms));
342 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
343 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
344 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
345 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
346 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
347 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
348 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
349 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
350 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
351 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
352 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
353 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
354 void StopObservingProc P((Widget w, XEvent *event, String *prms,
356 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
358 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
365 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
367 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
370 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
372 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
374 void AutocommProc P((Widget w, XEvent *event, String *prms,
376 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
377 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void AutobsProc P((Widget w, XEvent *event, String *prms,
380 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
385 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
386 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
388 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
390 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
392 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
393 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
394 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
396 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
398 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
400 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
402 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
404 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
405 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
406 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
408 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
410 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
412 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
414 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
415 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
416 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
417 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
418 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
419 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
420 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
421 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
422 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
423 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
424 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
425 void DisplayMove P((int moveNumber));
426 void DisplayTitle P((char *title));
427 void ICSInitScript P((void));
428 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
429 void ErrorPopUp P((char *title, char *text, int modal));
430 void ErrorPopDown P((void));
431 static char *ExpandPathName P((char *path));
432 static void CreateAnimVars P((void));
433 static void DragPieceMove P((int x, int y));
434 static void DrawDragPiece P((void));
435 char *ModeToWidgetName P((GameMode mode));
436 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
442 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
443 void ShufflePopDown P(());
444 void EnginePopDown P(());
445 void UciPopDown P(());
446 void TimeControlPopDown P(());
447 void NewVariantPopDown P(());
448 void SettingsPopDown P(());
449 void update_ics_width P(());
450 int get_term_width P(());
452 * XBoard depends on Xt R4 or higher
454 int xtVersion = XtSpecificationRelease;
459 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
460 jailSquareColor, highlightSquareColor, premoveHighlightColor;
461 Pixel lowTimeWarningColor;
462 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
463 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
464 wjPieceGC, bjPieceGC, prelineGC, countGC;
465 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
466 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
467 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
468 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
469 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
470 ICSInputShell, fileNameShell, askQuestionShell;
471 Widget historyShell, evalGraphShell, gameListShell;
472 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
473 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
474 Font clockFontID, coordFontID, countFontID;
475 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
476 XtAppContext appContext;
478 char *oldICSInteractionTitle;
482 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
484 Position commentX = -1, commentY = -1;
485 Dimension commentW, commentH;
486 typedef unsigned int BoardSize;
488 Boolean chessProgram;
490 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
491 int squareSize, smallLayout = 0, tinyLayout = 0,
492 marginW, marginH, // [HGM] for run-time resizing
493 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
494 ICSInputBoxUp = False, askQuestionUp = False,
495 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
496 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
497 Pixel timerForegroundPixel, timerBackgroundPixel;
498 Pixel buttonForegroundPixel, buttonBackgroundPixel;
499 char *chessDir, *programName, *programVersion,
500 *gameCopyFilename, *gamePasteFilename;
501 Boolean alwaysOnTop = False;
502 Boolean saveSettingsOnExit;
503 char *settingsFileName;
504 char *icsTextMenuString;
506 char *firstChessProgramNames;
507 char *secondChessProgramNames;
509 WindowPlacement wpMain;
510 WindowPlacement wpConsole;
511 WindowPlacement wpComment;
512 WindowPlacement wpMoveHistory;
513 WindowPlacement wpEvalGraph;
514 WindowPlacement wpEngineOutput;
515 WindowPlacement wpGameList;
516 WindowPlacement wpTags;
520 Pixmap pieceBitmap[2][(int)BlackPawn];
521 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
522 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
523 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
524 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
525 int useImages, useImageSqs;
526 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
527 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
528 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
529 XImage *ximLightSquare, *ximDarkSquare;
532 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
533 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
535 #define White(piece) ((int)(piece) < (int)BlackPawn)
537 /* Variables for doing smooth animation. This whole thing
538 would be much easier if the board was double-buffered,
539 but that would require a fairly major rewrite. */
544 GC blitGC, pieceGC, outlineGC;
545 XPoint startSquare, prevFrame, mouseDelta;
549 int startBoardX, startBoardY;
552 /* There can be two pieces being animated at once: a player
553 can begin dragging a piece before the remote opponent has moved. */
555 static AnimState game, player;
557 /* Bitmaps for use as masks when drawing XPM pieces.
558 Need one for each black and white piece. */
559 static Pixmap xpmMask[BlackKing + 1];
561 /* This magic number is the number of intermediate frames used
562 in each half of the animation. For short moves it's reduced
563 by 1. The total number of frames will be factor * 2 + 1. */
566 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
568 MenuItem fileMenu[] = {
569 {N_("New Game"), ResetProc},
570 {N_("New Shuffle Game ..."), ShuffleMenuProc},
571 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
572 {"----", NothingProc},
573 {N_("Load Game"), LoadGameProc},
574 {N_("Load Next Game"), LoadNextGameProc},
575 {N_("Load Previous Game"), LoadPrevGameProc},
576 {N_("Reload Same Game"), ReloadGameProc},
577 {N_("Save Game"), SaveGameProc},
578 {"----", NothingProc},
579 {N_("Copy Game"), CopyGameProc},
580 {N_("Paste Game"), PasteGameProc},
581 {"----", NothingProc},
582 {N_("Load Position"), LoadPositionProc},
583 {N_("Load Next Position"), LoadNextPositionProc},
584 {N_("Load Previous Position"), LoadPrevPositionProc},
585 {N_("Reload Same Position"), ReloadPositionProc},
586 {N_("Save Position"), SavePositionProc},
587 {"----", NothingProc},
588 {N_("Copy Position"), CopyPositionProc},
589 {N_("Paste Position"), PastePositionProc},
590 {"----", NothingProc},
591 {N_("Mail Move"), MailMoveProc},
592 {N_("Reload CMail Message"), ReloadCmailMsgProc},
593 {"----", NothingProc},
594 {N_("Exit"), QuitProc},
598 MenuItem modeMenu[] = {
599 {N_("Machine White"), MachineWhiteProc},
600 {N_("Machine Black"), MachineBlackProc},
601 {N_("Two Machines"), TwoMachinesProc},
602 {N_("Analysis Mode"), AnalyzeModeProc},
603 {N_("Analyze File"), AnalyzeFileProc },
604 {N_("ICS Client"), IcsClientProc},
605 {N_("Edit Game"), EditGameProc},
606 {N_("Edit Position"), EditPositionProc},
607 {N_("Training"), TrainingProc},
608 {"----", NothingProc},
609 {N_("Show Engine Output"), EngineOutputProc},
610 {N_("Show Evaluation Graph"), EvalGraphProc},
611 {N_("Show Game List"), ShowGameListProc},
612 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
613 {"----", NothingProc},
614 {N_("Edit Tags"), EditTagsProc},
615 {N_("Edit Comment"), EditCommentProc},
616 {N_("ICS Input Box"), IcsInputBoxProc},
617 {N_("Pause"), PauseProc},
621 MenuItem actionMenu[] = {
622 {N_("Accept"), AcceptProc},
623 {N_("Decline"), DeclineProc},
624 {N_("Rematch"), RematchProc},
625 {"----", NothingProc},
626 {N_("Call Flag"), CallFlagProc},
627 {N_("Draw"), DrawProc},
628 {N_("Adjourn"), AdjournProc},
629 {N_("Abort"), AbortProc},
630 {N_("Resign"), ResignProc},
631 {"----", NothingProc},
632 {N_("Stop Observing"), StopObservingProc},
633 {N_("Stop Examining"), StopExaminingProc},
634 {"----", NothingProc},
635 {N_("Adjudicate to White"), AdjuWhiteProc},
636 {N_("Adjudicate to Black"), AdjuBlackProc},
637 {N_("Adjudicate Draw"), AdjuDrawProc},
641 MenuItem stepMenu[] = {
642 {N_("Backward"), BackwardProc},
643 {N_("Forward"), ForwardProc},
644 {N_("Back to Start"), ToStartProc},
645 {N_("Forward to End"), ToEndProc},
646 {N_("Revert"), RevertProc},
647 {N_("Truncate Game"), TruncateGameProc},
648 {"----", NothingProc},
649 {N_("Move Now"), MoveNowProc},
650 {N_("Retract Move"), RetractMoveProc},
654 MenuItem optionsMenu[] = {
655 {N_("Flip View"), FlipViewProc},
656 {"----", NothingProc},
657 {N_("Adjudications ..."), EngineMenuProc},
658 {N_("General Settings ..."), UciMenuProc},
659 {N_("Engine #1 Settings ..."), FirstSettingsProc},
660 {N_("Engine #2 Settings ..."), SecondSettingsProc},
661 {N_("Time Control ..."), TimeControlProc},
662 {"----", NothingProc},
663 {N_("Always Queen"), AlwaysQueenProc},
664 {N_("Animate Dragging"), AnimateDraggingProc},
665 {N_("Animate Moving"), AnimateMovingProc},
666 {N_("Auto Comment"), AutocommProc},
667 {N_("Auto Flag"), AutoflagProc},
668 {N_("Auto Flip View"), AutoflipProc},
669 {N_("Auto Observe"), AutobsProc},
670 {N_("Auto Raise Board"), AutoraiseProc},
671 {N_("Auto Save"), AutosaveProc},
672 {N_("Blindfold"), BlindfoldProc},
673 {N_("Flash Moves"), FlashMovesProc},
674 {N_("Get Move List"), GetMoveListProc},
676 {N_("Highlight Dragging"), HighlightDraggingProc},
678 {N_("Highlight Last Move"), HighlightLastMoveProc},
679 {N_("Move Sound"), MoveSoundProc},
680 {N_("ICS Alarm"), IcsAlarmProc},
681 {N_("Old Save Style"), OldSaveStyleProc},
682 {N_("Periodic Updates"), PeriodicUpdatesProc},
683 {N_("Ponder Next Move"), PonderNextMoveProc},
684 {N_("Popup Exit Message"), PopupExitMessageProc},
685 {N_("Popup Move Errors"), PopupMoveErrorsProc},
686 {N_("Premove"), PremoveProc},
687 {N_("Quiet Play"), QuietPlayProc},
688 {N_("Show Coords"), ShowCoordsProc},
689 {N_("Hide Thinking"), HideThinkingProc},
690 {N_("Test Legality"), TestLegalityProc},
691 {"----", NothingProc},
692 {N_("Save Settings Now"), SaveSettingsProc},
693 {N_("Save Settings on Exit"), SaveOnExitProc},
697 MenuItem helpMenu[] = {
698 {N_("Info XBoard"), InfoProc},
699 {N_("Man XBoard"), ManProc},
700 {"----", NothingProc},
701 {N_("Hint"), HintProc},
702 {N_("Book"), BookProc},
703 {"----", NothingProc},
704 {N_("About XBoard"), AboutProc},
709 {N_("File"), fileMenu},
710 {N_("Mode"), modeMenu},
711 {N_("Action"), actionMenu},
712 {N_("Step"), stepMenu},
713 {N_("Options"), optionsMenu},
714 {N_("Help"), helpMenu},
718 #define PAUSE_BUTTON N_("P")
719 MenuItem buttonBar[] = {
722 {PAUSE_BUTTON, PauseProc},
728 #define PIECE_MENU_SIZE 18
729 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
730 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
731 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
732 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
733 N_("Empty square"), N_("Clear board") },
734 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
735 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
736 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
737 N_("Empty square"), N_("Clear board") }
739 /* must be in same order as PieceMenuStrings! */
740 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
741 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
742 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
743 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
744 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
745 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
746 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
747 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
748 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
751 #define DROP_MENU_SIZE 6
752 String dropMenuStrings[DROP_MENU_SIZE] = {
753 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
755 /* must be in same order as PieceMenuStrings! */
756 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
757 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
758 WhiteRook, WhiteQueen
766 DropMenuEnables dmEnables[] = {
784 { XtNborderWidth, 0 },
785 { XtNdefaultDistance, 0 },
789 { XtNborderWidth, 0 },
790 { XtNresizable, (XtArgVal) True },
794 { XtNborderWidth, 0 },
800 { XtNjustify, (XtArgVal) XtJustifyRight },
801 { XtNlabel, (XtArgVal) "..." },
802 { XtNresizable, (XtArgVal) True },
803 { XtNresize, (XtArgVal) False }
806 Arg messageArgs[] = {
807 { XtNjustify, (XtArgVal) XtJustifyLeft },
808 { XtNlabel, (XtArgVal) "..." },
809 { XtNresizable, (XtArgVal) True },
810 { XtNresize, (XtArgVal) False }
814 { XtNborderWidth, 0 },
815 { XtNjustify, (XtArgVal) XtJustifyLeft }
818 XtResource clientResources[] = {
819 { "flashCount", "flashCount", XtRInt, sizeof(int),
820 XtOffset(AppDataPtr, flashCount), XtRImmediate,
821 (XtPointer) FLASH_COUNT },
824 XrmOptionDescRec shellOptions[] = {
825 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
826 { "-flash", "flashCount", XrmoptionNoArg, "3" },
827 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
830 XtActionsRec boardActions[] = {
831 { "DrawPosition", DrawPositionProc },
832 { "HandleUserMove", HandleUserMove },
833 { "AnimateUserMove", AnimateUserMove },
834 { "FileNameAction", FileNameAction },
835 { "AskQuestionProc", AskQuestionProc },
836 { "AskQuestionReplyAction", AskQuestionReplyAction },
837 { "PieceMenuPopup", PieceMenuPopup },
838 { "WhiteClock", WhiteClock },
839 { "BlackClock", BlackClock },
840 { "Iconify", Iconify },
841 { "ResetProc", ResetProc },
842 { "LoadGameProc", LoadGameProc },
843 { "LoadNextGameProc", LoadNextGameProc },
844 { "LoadPrevGameProc", LoadPrevGameProc },
845 { "LoadSelectedProc", LoadSelectedProc },
846 { "ReloadGameProc", ReloadGameProc },
847 { "LoadPositionProc", LoadPositionProc },
848 { "LoadNextPositionProc", LoadNextPositionProc },
849 { "LoadPrevPositionProc", LoadPrevPositionProc },
850 { "ReloadPositionProc", ReloadPositionProc },
851 { "CopyPositionProc", CopyPositionProc },
852 { "PastePositionProc", PastePositionProc },
853 { "CopyGameProc", CopyGameProc },
854 { "PasteGameProc", PasteGameProc },
855 { "SaveGameProc", SaveGameProc },
856 { "SavePositionProc", SavePositionProc },
857 { "MailMoveProc", MailMoveProc },
858 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
859 { "QuitProc", QuitProc },
860 { "MachineWhiteProc", MachineWhiteProc },
861 { "MachineBlackProc", MachineBlackProc },
862 { "AnalysisModeProc", AnalyzeModeProc },
863 { "AnalyzeFileProc", AnalyzeFileProc },
864 { "TwoMachinesProc", TwoMachinesProc },
865 { "IcsClientProc", IcsClientProc },
866 { "EditGameProc", EditGameProc },
867 { "EditPositionProc", EditPositionProc },
868 { "TrainingProc", EditPositionProc },
869 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
870 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
871 { "ShowGameListProc", ShowGameListProc },
872 { "ShowMoveListProc", HistoryShowProc},
873 { "EditTagsProc", EditCommentProc },
874 { "EditCommentProc", EditCommentProc },
875 { "IcsAlarmProc", IcsAlarmProc },
876 { "IcsInputBoxProc", IcsInputBoxProc },
877 { "PauseProc", PauseProc },
878 { "AcceptProc", AcceptProc },
879 { "DeclineProc", DeclineProc },
880 { "RematchProc", RematchProc },
881 { "CallFlagProc", CallFlagProc },
882 { "DrawProc", DrawProc },
883 { "AdjournProc", AdjournProc },
884 { "AbortProc", AbortProc },
885 { "ResignProc", ResignProc },
886 { "AdjuWhiteProc", AdjuWhiteProc },
887 { "AdjuBlackProc", AdjuBlackProc },
888 { "AdjuDrawProc", AdjuDrawProc },
889 { "EnterKeyProc", EnterKeyProc },
890 { "StopObservingProc", StopObservingProc },
891 { "StopExaminingProc", StopExaminingProc },
892 { "BackwardProc", BackwardProc },
893 { "ForwardProc", ForwardProc },
894 { "ToStartProc", ToStartProc },
895 { "ToEndProc", ToEndProc },
896 { "RevertProc", RevertProc },
897 { "TruncateGameProc", TruncateGameProc },
898 { "MoveNowProc", MoveNowProc },
899 { "RetractMoveProc", RetractMoveProc },
900 { "AlwaysQueenProc", AlwaysQueenProc },
901 { "AnimateDraggingProc", AnimateDraggingProc },
902 { "AnimateMovingProc", AnimateMovingProc },
903 { "AutoflagProc", AutoflagProc },
904 { "AutoflipProc", AutoflipProc },
905 { "AutobsProc", AutobsProc },
906 { "AutoraiseProc", AutoraiseProc },
907 { "AutosaveProc", AutosaveProc },
908 { "BlindfoldProc", BlindfoldProc },
909 { "FlashMovesProc", FlashMovesProc },
910 { "FlipViewProc", FlipViewProc },
911 { "GetMoveListProc", GetMoveListProc },
913 { "HighlightDraggingProc", HighlightDraggingProc },
915 { "HighlightLastMoveProc", HighlightLastMoveProc },
916 { "IcsAlarmProc", IcsAlarmProc },
917 { "MoveSoundProc", MoveSoundProc },
918 { "OldSaveStyleProc", OldSaveStyleProc },
919 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
920 { "PonderNextMoveProc", PonderNextMoveProc },
921 { "PopupExitMessageProc", PopupExitMessageProc },
922 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
923 { "PremoveProc", PremoveProc },
924 { "QuietPlayProc", QuietPlayProc },
925 { "ShowCoordsProc", ShowCoordsProc },
926 { "ShowThinkingProc", ShowThinkingProc },
927 { "HideThinkingProc", HideThinkingProc },
928 { "TestLegalityProc", TestLegalityProc },
929 { "SaveSettingsProc", SaveSettingsProc },
930 { "SaveOnExitProc", SaveOnExitProc },
931 { "InfoProc", InfoProc },
932 { "ManProc", ManProc },
933 { "HintProc", HintProc },
934 { "BookProc", BookProc },
935 { "AboutGameProc", AboutGameProc },
936 { "AboutProc", AboutProc },
937 { "DebugProc", DebugProc },
938 { "NothingProc", NothingProc },
939 { "CommentPopDown", (XtActionProc) CommentPopDown },
940 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
941 { "TagsPopDown", (XtActionProc) TagsPopDown },
942 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
943 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
944 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
945 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
946 { "GameListPopDown", (XtActionProc) GameListPopDown },
947 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
948 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
949 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
950 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
951 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
952 { "EnginePopDown", (XtActionProc) EnginePopDown },
953 { "UciPopDown", (XtActionProc) UciPopDown },
954 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
955 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
956 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
959 char globalTranslations[] =
960 ":<Key>R: ResignProc() \n \
961 :<Key>r: ResetProc() \n \
962 :<Key>g: LoadGameProc() \n \
963 :<Key>N: LoadNextGameProc() \n \
964 :<Key>P: LoadPrevGameProc() \n \
965 :<Key>Q: QuitProc() \n \
966 :<Key>F: ToEndProc() \n \
967 :<Key>f: ForwardProc() \n \
968 :<Key>B: ToStartProc() \n \
969 :<Key>b: BackwardProc() \n \
970 :<Key>p: PauseProc() \n \
971 :<Key>d: DrawProc() \n \
972 :<Key>t: CallFlagProc() \n \
973 :<Key>i: Iconify() \n \
974 :<Key>c: Iconify() \n \
975 :<Key>v: FlipViewProc() \n \
976 <KeyDown>Control_L: BackwardProc() \n \
977 <KeyUp>Control_L: ForwardProc() \n \
978 <KeyDown>Control_R: BackwardProc() \n \
979 <KeyUp>Control_R: ForwardProc() \n \
980 Shift<Key>1: AskQuestionProc(\"Direct command\",\
981 \"Send to chess program:\",,1) \n \
982 Shift<Key>2: AskQuestionProc(\"Direct command\",\
983 \"Send to second chess program:\",,2) \n";
985 char boardTranslations[] =
986 "<Btn1Down>: HandleUserMove() \n \
987 <Btn1Up>: HandleUserMove() \n \
988 <Btn1Motion>: AnimateUserMove() \n \
989 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
990 PieceMenuPopup(menuB) \n \
991 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
992 PieceMenuPopup(menuW) \n \
993 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
994 PieceMenuPopup(menuW) \n \
995 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
996 PieceMenuPopup(menuB) \n";
998 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
999 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1001 char ICSInputTranslations[] =
1002 "<Key>Return: EnterKeyProc() \n";
1004 String xboardResources[] = {
1005 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1006 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1007 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1012 /* Max possible square size */
1013 #define MAXSQSIZE 256
1015 static int xpm_avail[MAXSQSIZE];
1017 #ifdef HAVE_DIR_STRUCT
1019 /* Extract piece size from filename */
1021 xpm_getsize(name, len, ext)
1032 if ((p=strchr(name, '.')) == NULL ||
1033 StrCaseCmp(p+1, ext) != 0)
1039 while (*p && isdigit(*p))
1046 /* Setup xpm_avail */
1048 xpm_getavail(dirname, ext)
1056 for (i=0; i<MAXSQSIZE; ++i)
1059 if (appData.debugMode)
1060 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1062 dir = opendir(dirname);
1065 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1066 programName, dirname);
1070 while ((ent=readdir(dir)) != NULL) {
1071 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1072 if (i > 0 && i < MAXSQSIZE)
1082 xpm_print_avail(fp, ext)
1088 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1089 for (i=1; i<MAXSQSIZE; ++i) {
1095 /* Return XPM piecesize closest to size */
1097 xpm_closest_to(dirname, size, ext)
1103 int sm_diff = MAXSQSIZE;
1107 xpm_getavail(dirname, ext);
1109 if (appData.debugMode)
1110 xpm_print_avail(stderr, ext);
1112 for (i=1; i<MAXSQSIZE; ++i) {
1115 diff = (diff<0) ? -diff : diff;
1116 if (diff < sm_diff) {
1124 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1130 #else /* !HAVE_DIR_STRUCT */
1131 /* If we are on a system without a DIR struct, we can't
1132 read the directory, so we can't collect a list of
1133 filenames, etc., so we can't do any size-fitting. */
1135 xpm_closest_to(dirname, size, ext)
1140 fprintf(stderr, _("\
1141 Warning: No DIR structure found on this system --\n\
1142 Unable to autosize for XPM/XIM pieces.\n\
1143 Please report this error to frankm@hiwaay.net.\n\
1144 Include system type & operating system in message.\n"));
1147 #endif /* HAVE_DIR_STRUCT */
1149 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1150 "magenta", "cyan", "white" };
1154 TextColors textColors[(int)NColorClasses];
1156 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1158 parse_color(str, which)
1162 char *p, buf[100], *d;
1165 if (strlen(str) > 99) /* watch bounds on buf */
1170 for (i=0; i<which; ++i) {
1177 /* Could be looking at something like:
1179 .. in which case we want to stop on a comma also */
1180 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1184 return -1; /* Use default for empty field */
1187 if (which == 2 || isdigit(*p))
1190 while (*p && isalpha(*p))
1195 for (i=0; i<8; ++i) {
1196 if (!StrCaseCmp(buf, cnames[i]))
1197 return which? (i+40) : (i+30);
1199 if (!StrCaseCmp(buf, "default")) return -1;
1201 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1206 parse_cpair(cc, str)
1210 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1211 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1216 /* bg and attr are optional */
1217 textColors[(int)cc].bg = parse_color(str, 1);
1218 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1219 textColors[(int)cc].attr = 0;
1225 /* Arrange to catch delete-window events */
1226 Atom wm_delete_window;
1228 CatchDeleteWindow(Widget w, String procname)
1231 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1232 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1233 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1240 XtSetArg(args[0], XtNiconic, False);
1241 XtSetValues(shellWidget, args, 1);
1243 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1246 //---------------------------------------------------------------------------------------------------------
1247 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1250 #define CW_USEDEFAULT (1<<31)
1251 #define ICS_TEXT_MENU_SIZE 90
1252 #define SetCurrentDirectory chdir
1253 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1257 // these two must some day move to frontend.h, when they are implemented
1258 Boolean MoveHistoryIsUp();
1259 Boolean GameListIsUp();
1261 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1264 // front-end part of option handling
1266 // [HGM] This platform-dependent table provides the location for storing the color info
1267 extern char *crWhite, * crBlack;
1271 &appData.whitePieceColor,
1272 &appData.blackPieceColor,
1273 &appData.lightSquareColor,
1274 &appData.darkSquareColor,
1275 &appData.highlightSquareColor,
1276 &appData.premoveHighlightColor,
1289 ParseFont(char *name, int number)
1290 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1292 case 0: // CLOCK_FONT
1293 appData.clockFont = strdup(name);
1295 case 1: // MESSAGE_FONT
1296 appData.font = strdup(name);
1298 case 2: // COORD_FONT
1299 appData.coordFont = strdup(name);
1308 { // only 2 fonts currently
1309 appData.clockFont = CLOCK_FONT_NAME;
1310 appData.coordFont = COORD_FONT_NAME;
1311 appData.font = DEFAULT_FONT_NAME;
1316 { // no-op, until we identify the code for this already in XBoard and move it here
1320 ParseColor(int n, char *name)
1321 { // in XBoard, just copy the color-name string
1322 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1326 ParseTextAttribs(ColorClass cc, char *s)
1328 (&appData.colorShout)[cc] = strdup(s);
1332 ParseBoardSize(void *addr, char *name)
1334 appData.boardSize = strdup(name);
1339 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1343 SetCommPortDefaults()
1344 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1347 // [HGM] args: these three cases taken out to stay in front-end
1349 SaveFontArg(FILE *f, ArgDescriptor *ad)
1352 switch((int)ad->argLoc) {
1353 case 0: // CLOCK_FONT
1354 name = appData.clockFont;
1356 case 1: // MESSAGE_FONT
1357 name = appData.font;
1359 case 2: // COORD_FONT
1360 name = appData.coordFont;
1365 // Do not save fonts for now, as the saved font would be board-size specific
1366 // and not suitable for a re-start at another board size
1367 // fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, name);
1372 { // nothing to do, as the sounds are at all times represented by their text-string names already
1376 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1377 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1378 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1382 SaveColor(FILE *f, ArgDescriptor *ad)
1383 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1384 if(colorVariable[(int)ad->argLoc])
1385 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1389 SaveBoardSize(FILE *f, char *name, void *addr)
1390 { // wrapper to shield back-end from BoardSize & sizeInfo
1391 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1395 ParseCommPortSettings(char *s)
1396 { // no such option in XBoard (yet)
1399 extern Widget engineOutputShell;
1400 extern Widget tagsShell, editTagsShell;
1402 GetActualPlacement(Widget wg, WindowPlacement *wp)
1412 XtSetArg(args[i], XtNx, &x); i++;
1413 XtSetArg(args[i], XtNy, &y); i++;
1414 XtSetArg(args[i], XtNwidth, &w); i++;
1415 XtSetArg(args[i], XtNheight, &h); i++;
1416 XtGetValues(wg, args, i);
1425 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1426 // In XBoard this will have to wait until awareness of window parameters is implemented
1427 GetActualPlacement(shellWidget, &wpMain);
1428 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1429 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1430 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1431 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1432 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1433 else GetActualPlacement(editShell, &wpComment);
1434 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1435 else GetActualPlacement(editTagsShell, &wpTags);
1439 PrintCommPortSettings(FILE *f, char *name)
1440 { // This option does not exist in XBoard
1444 MySearchPath(char *installDir, char *name, char *fullname)
1445 { // just append installDir and name. Perhaps ExpandPath should be used here?
1446 name = ExpandPathName(name);
1447 if(name && name[0] == '/') strcpy(fullname, name); else {
1448 sprintf(fullname, "%s%c%s", installDir, '/', name);
1454 MyGetFullPathName(char *name, char *fullname)
1455 { // should use ExpandPath?
1456 name = ExpandPathName(name);
1457 strcpy(fullname, name);
1462 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);
2462 /* [AS] Restore layout */
2463 if( wpMoveHistory.visible ) {
2467 if( wpEvalGraph.visible )
2472 if( wpEngineOutput.visible ) {
2473 EngineOutputPopUp();
2478 if (errorExitStatus == -1) {
2479 if (appData.icsActive) {
2480 /* We now wait until we see "login:" from the ICS before
2481 sending the logon script (problems with timestamp otherwise) */
2482 /*ICSInitScript();*/
2483 if (appData.icsInputBox) ICSInputBoxPopUp();
2487 signal(SIGWINCH, TermSizeSigHandler);
2489 signal(SIGINT, IntSigHandler);
2490 signal(SIGTERM, IntSigHandler);
2491 if (*appData.cmailGameName != NULLCHAR) {
2492 signal(SIGUSR1, CmailSigHandler);
2495 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2498 XtAppMainLoop(appContext);
2499 if (appData.debugMode) fclose(debugFP); // [DM] debug
2506 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2507 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2509 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2510 unlink(gameCopyFilename);
2511 unlink(gamePasteFilename);
2514 RETSIGTYPE TermSizeSigHandler(int sig)
2527 CmailSigHandler(sig)
2533 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2535 /* Activate call-back function CmailSigHandlerCallBack() */
2536 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2538 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2542 CmailSigHandlerCallBack(isr, closure, message, count, error)
2550 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2552 /**** end signal code ****/
2562 f = fopen(appData.icsLogon, "r");
2568 strcat(buf, appData.icsLogon);
2569 f = fopen(buf, "r");
2573 ProcessICSInitScript(f);
2580 EditCommentPopDown();
2595 if (!menuBarWidget) return;
2596 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2598 DisplayError("menuStep.Revert", 0);
2600 XtSetSensitive(w, !grey);
2605 SetMenuEnables(enab)
2609 if (!menuBarWidget) return;
2610 while (enab->name != NULL) {
2611 w = XtNameToWidget(menuBarWidget, enab->name);
2613 DisplayError(enab->name, 0);
2615 XtSetSensitive(w, enab->value);
2621 Enables icsEnables[] = {
2622 { "menuFile.Mail Move", False },
2623 { "menuFile.Reload CMail Message", False },
2624 { "menuMode.Machine Black", False },
2625 { "menuMode.Machine White", False },
2626 { "menuMode.Analysis Mode", False },
2627 { "menuMode.Analyze File", False },
2628 { "menuMode.Two Machines", False },
2630 { "menuHelp.Hint", False },
2631 { "menuHelp.Book", False },
2632 { "menuStep.Move Now", False },
2633 { "menuOptions.Periodic Updates", False },
2634 { "menuOptions.Hide Thinking", False },
2635 { "menuOptions.Ponder Next Move", False },
2640 Enables ncpEnables[] = {
2641 { "menuFile.Mail Move", False },
2642 { "menuFile.Reload CMail Message", False },
2643 { "menuMode.Machine White", False },
2644 { "menuMode.Machine Black", False },
2645 { "menuMode.Analysis Mode", False },
2646 { "menuMode.Analyze File", False },
2647 { "menuMode.Two Machines", False },
2648 { "menuMode.ICS Client", False },
2649 { "menuMode.ICS Input Box", False },
2650 { "Action", False },
2651 { "menuStep.Revert", False },
2652 { "menuStep.Move Now", False },
2653 { "menuStep.Retract Move", False },
2654 { "menuOptions.Auto Comment", False },
2655 { "menuOptions.Auto Flag", False },
2656 { "menuOptions.Auto Flip View", False },
2657 { "menuOptions.Auto Observe", False },
2658 { "menuOptions.Auto Raise Board", False },
2659 { "menuOptions.Get Move List", False },
2660 { "menuOptions.ICS Alarm", False },
2661 { "menuOptions.Move Sound", False },
2662 { "menuOptions.Quiet Play", False },
2663 { "menuOptions.Hide Thinking", False },
2664 { "menuOptions.Periodic Updates", False },
2665 { "menuOptions.Ponder Next Move", False },
2666 { "menuHelp.Hint", False },
2667 { "menuHelp.Book", False },
2671 Enables gnuEnables[] = {
2672 { "menuMode.ICS Client", False },
2673 { "menuMode.ICS Input Box", False },
2674 { "menuAction.Accept", False },
2675 { "menuAction.Decline", False },
2676 { "menuAction.Rematch", False },
2677 { "menuAction.Adjourn", False },
2678 { "menuAction.Stop Examining", False },
2679 { "menuAction.Stop Observing", False },
2680 { "menuStep.Revert", False },
2681 { "menuOptions.Auto Comment", False },
2682 { "menuOptions.Auto Observe", False },
2683 { "menuOptions.Auto Raise Board", False },
2684 { "menuOptions.Get Move List", False },
2685 { "menuOptions.Premove", False },
2686 { "menuOptions.Quiet Play", False },
2688 /* The next two options rely on SetCmailMode being called *after* */
2689 /* SetGNUMode so that when GNU is being used to give hints these */
2690 /* menu options are still available */
2692 { "menuFile.Mail Move", False },
2693 { "menuFile.Reload CMail Message", False },
2697 Enables cmailEnables[] = {
2699 { "menuAction.Call Flag", False },
2700 { "menuAction.Draw", True },
2701 { "menuAction.Adjourn", False },
2702 { "menuAction.Abort", False },
2703 { "menuAction.Stop Observing", False },
2704 { "menuAction.Stop Examining", False },
2705 { "menuFile.Mail Move", True },
2706 { "menuFile.Reload CMail Message", True },
2710 Enables trainingOnEnables[] = {
2711 { "menuMode.Edit Comment", False },
2712 { "menuMode.Pause", False },
2713 { "menuStep.Forward", False },
2714 { "menuStep.Backward", False },
2715 { "menuStep.Forward to End", False },
2716 { "menuStep.Back to Start", False },
2717 { "menuStep.Move Now", False },
2718 { "menuStep.Truncate Game", False },
2722 Enables trainingOffEnables[] = {
2723 { "menuMode.Edit Comment", True },
2724 { "menuMode.Pause", True },
2725 { "menuStep.Forward", True },
2726 { "menuStep.Backward", True },
2727 { "menuStep.Forward to End", True },
2728 { "menuStep.Back to Start", True },
2729 { "menuStep.Move Now", True },
2730 { "menuStep.Truncate Game", True },
2734 Enables machineThinkingEnables[] = {
2735 { "menuFile.Load Game", False },
2736 { "menuFile.Load Next Game", False },
2737 { "menuFile.Load Previous Game", False },
2738 { "menuFile.Reload Same Game", False },
2739 { "menuFile.Paste Game", False },
2740 { "menuFile.Load Position", False },
2741 { "menuFile.Load Next Position", False },
2742 { "menuFile.Load Previous Position", False },
2743 { "menuFile.Reload Same Position", False },
2744 { "menuFile.Paste Position", False },
2745 { "menuMode.Machine White", False },
2746 { "menuMode.Machine Black", False },
2747 { "menuMode.Two Machines", False },
2748 { "menuStep.Retract Move", False },
2752 Enables userThinkingEnables[] = {
2753 { "menuFile.Load Game", True },
2754 { "menuFile.Load Next Game", True },
2755 { "menuFile.Load Previous Game", True },
2756 { "menuFile.Reload Same Game", True },
2757 { "menuFile.Paste Game", True },
2758 { "menuFile.Load Position", True },
2759 { "menuFile.Load Next Position", True },
2760 { "menuFile.Load Previous Position", True },
2761 { "menuFile.Reload Same Position", True },
2762 { "menuFile.Paste Position", True },
2763 { "menuMode.Machine White", True },
2764 { "menuMode.Machine Black", True },
2765 { "menuMode.Two Machines", True },
2766 { "menuStep.Retract Move", True },
2772 SetMenuEnables(icsEnables);
2775 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2776 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2783 SetMenuEnables(ncpEnables);
2789 SetMenuEnables(gnuEnables);
2795 SetMenuEnables(cmailEnables);
2801 SetMenuEnables(trainingOnEnables);
2802 if (appData.showButtonBar) {
2803 XtSetSensitive(buttonBarWidget, False);
2809 SetTrainingModeOff()
2811 SetMenuEnables(trainingOffEnables);
2812 if (appData.showButtonBar) {
2813 XtSetSensitive(buttonBarWidget, True);
2818 SetUserThinkingEnables()
2820 if (appData.noChessProgram) return;
2821 SetMenuEnables(userThinkingEnables);
2825 SetMachineThinkingEnables()
2827 if (appData.noChessProgram) return;
2828 SetMenuEnables(machineThinkingEnables);
2830 case MachinePlaysBlack:
2831 case MachinePlaysWhite:
2832 case TwoMachinesPlay:
2833 XtSetSensitive(XtNameToWidget(menuBarWidget,
2834 ModeToWidgetName(gameMode)), True);
2841 #define Abs(n) ((n)<0 ? -(n) : (n))
2844 * Find a font that matches "pattern" that is as close as
2845 * possible to the targetPxlSize. Prefer fonts that are k
2846 * pixels smaller to fonts that are k pixels larger. The
2847 * pattern must be in the X Consortium standard format,
2848 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2849 * The return value should be freed with XtFree when no
2852 char *FindFont(pattern, targetPxlSize)
2856 char **fonts, *p, *best, *scalable, *scalableTail;
2857 int i, j, nfonts, minerr, err, pxlSize;
2860 char **missing_list;
2862 char *def_string, *base_fnt_lst, strInt[3];
2864 XFontStruct **fnt_list;
2866 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2867 sprintf(strInt, "%d", targetPxlSize);
2868 p = strstr(pattern, "--");
2869 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2870 strcat(base_fnt_lst, strInt);
2871 strcat(base_fnt_lst, strchr(p + 2, '-'));
2873 if ((fntSet = XCreateFontSet(xDisplay,
2877 &def_string)) == NULL) {
2879 fprintf(stderr, _("Unable to create font set.\n"));
2883 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2885 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2887 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2888 programName, pattern);
2896 for (i=0; i<nfonts; i++) {
2899 if (*p != '-') continue;
2901 if (*p == NULLCHAR) break;
2902 if (*p++ == '-') j++;
2904 if (j < 7) continue;
2907 scalable = fonts[i];
2910 err = pxlSize - targetPxlSize;
2911 if (Abs(err) < Abs(minerr) ||
2912 (minerr > 0 && err < 0 && -err == minerr)) {
2918 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
2919 /* If the error is too big and there is a scalable font,
2920 use the scalable font. */
2921 int headlen = scalableTail - scalable;
2922 p = (char *) XtMalloc(strlen(scalable) + 10);
2923 while (isdigit(*scalableTail)) scalableTail++;
2924 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
2926 p = (char *) XtMalloc(strlen(best) + 1);
2929 if (appData.debugMode) {
2930 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
2931 pattern, targetPxlSize, p);
2934 if (missing_count > 0)
2935 XFreeStringList(missing_list);
2936 XFreeFontSet(xDisplay, fntSet);
2938 XFreeFontNames(fonts);
2945 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
2946 | GCBackground | GCFunction | GCPlaneMask;
2947 XGCValues gc_values;
2950 gc_values.plane_mask = AllPlanes;
2951 gc_values.line_width = lineGap;
2952 gc_values.line_style = LineSolid;
2953 gc_values.function = GXcopy;
2955 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2956 gc_values.background = XBlackPixel(xDisplay, xScreen);
2957 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2959 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2960 gc_values.background = XWhitePixel(xDisplay, xScreen);
2961 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
2962 XSetFont(xDisplay, coordGC, coordFontID);
2964 // [HGM] make font for holdings counts (white on black0
2965 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2966 gc_values.background = XBlackPixel(xDisplay, xScreen);
2967 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
2968 XSetFont(xDisplay, countGC, countFontID);
2970 if (appData.monoMode) {
2971 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2972 gc_values.background = XWhitePixel(xDisplay, xScreen);
2973 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2975 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2976 gc_values.background = XBlackPixel(xDisplay, xScreen);
2977 lightSquareGC = wbPieceGC
2978 = XtGetGC(shellWidget, value_mask, &gc_values);
2980 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2981 gc_values.background = XWhitePixel(xDisplay, xScreen);
2982 darkSquareGC = bwPieceGC
2983 = XtGetGC(shellWidget, value_mask, &gc_values);
2985 if (DefaultDepth(xDisplay, xScreen) == 1) {
2986 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
2987 gc_values.function = GXcopyInverted;
2988 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
2989 gc_values.function = GXcopy;
2990 if (XBlackPixel(xDisplay, xScreen) == 1) {
2991 bwPieceGC = darkSquareGC;
2992 wbPieceGC = copyInvertedGC;
2994 bwPieceGC = copyInvertedGC;
2995 wbPieceGC = lightSquareGC;
2999 gc_values.foreground = highlightSquareColor;
3000 gc_values.background = highlightSquareColor;
3001 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3003 gc_values.foreground = premoveHighlightColor;
3004 gc_values.background = premoveHighlightColor;
3005 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3007 gc_values.foreground = lightSquareColor;
3008 gc_values.background = darkSquareColor;
3009 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3011 gc_values.foreground = darkSquareColor;
3012 gc_values.background = lightSquareColor;
3013 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3015 gc_values.foreground = jailSquareColor;
3016 gc_values.background = jailSquareColor;
3017 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3019 gc_values.foreground = whitePieceColor;
3020 gc_values.background = darkSquareColor;
3021 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3023 gc_values.foreground = whitePieceColor;
3024 gc_values.background = lightSquareColor;
3025 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3027 gc_values.foreground = whitePieceColor;
3028 gc_values.background = jailSquareColor;
3029 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3031 gc_values.foreground = blackPieceColor;
3032 gc_values.background = darkSquareColor;
3033 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3035 gc_values.foreground = blackPieceColor;
3036 gc_values.background = lightSquareColor;
3037 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3039 gc_values.foreground = blackPieceColor;
3040 gc_values.background = jailSquareColor;
3041 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3045 void loadXIM(xim, xmask, filename, dest, mask)
3058 fp = fopen(filename, "rb");
3060 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3067 for (y=0; y<h; ++y) {
3068 for (x=0; x<h; ++x) {
3073 XPutPixel(xim, x, y, blackPieceColor);
3075 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3078 XPutPixel(xim, x, y, darkSquareColor);
3080 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3083 XPutPixel(xim, x, y, whitePieceColor);
3085 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3088 XPutPixel(xim, x, y, lightSquareColor);
3090 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3096 /* create Pixmap of piece */
3097 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3099 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3102 /* create Pixmap of clipmask
3103 Note: We assume the white/black pieces have the same
3104 outline, so we make only 6 masks. This is okay
3105 since the XPM clipmask routines do the same. */
3107 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3109 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3112 /* now create the 1-bit version */
3113 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3116 values.foreground = 1;
3117 values.background = 0;
3119 /* Don't use XtGetGC, not read only */
3120 maskGC = XCreateGC(xDisplay, *mask,
3121 GCForeground | GCBackground, &values);
3122 XCopyPlane(xDisplay, temp, *mask, maskGC,
3123 0, 0, squareSize, squareSize, 0, 0, 1);
3124 XFreePixmap(xDisplay, temp);
3129 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3131 void CreateXIMPieces()
3136 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3141 /* The XSynchronize calls were copied from CreatePieces.
3142 Not sure if needed, but can't hurt */
3143 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3146 /* temp needed by loadXIM() */
3147 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3148 0, 0, ss, ss, AllPlanes, XYPixmap);
3150 if (strlen(appData.pixmapDirectory) == 0) {
3154 if (appData.monoMode) {
3155 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3159 fprintf(stderr, _("\nLoading XIMs...\n"));
3161 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3162 fprintf(stderr, "%d", piece+1);
3163 for (kind=0; kind<4; kind++) {
3164 fprintf(stderr, ".");
3165 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3166 ExpandPathName(appData.pixmapDirectory),
3167 piece <= (int) WhiteKing ? "" : "w",
3168 pieceBitmapNames[piece],
3170 ximPieceBitmap[kind][piece] =
3171 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3172 0, 0, ss, ss, AllPlanes, XYPixmap);
3173 if (appData.debugMode)
3174 fprintf(stderr, _("(File:%s:) "), buf);
3175 loadXIM(ximPieceBitmap[kind][piece],
3177 &(xpmPieceBitmap2[kind][piece]),
3178 &(ximMaskPm2[piece]));
3179 if(piece <= (int)WhiteKing)
3180 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3182 fprintf(stderr," ");
3184 /* Load light and dark squares */
3185 /* If the LSQ and DSQ pieces don't exist, we will
3186 draw them with solid squares. */
3187 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3188 if (access(buf, 0) != 0) {
3192 fprintf(stderr, _("light square "));
3194 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3195 0, 0, ss, ss, AllPlanes, XYPixmap);
3196 if (appData.debugMode)
3197 fprintf(stderr, _("(File:%s:) "), buf);
3199 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3200 fprintf(stderr, _("dark square "));
3201 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3202 ExpandPathName(appData.pixmapDirectory), ss);
3203 if (appData.debugMode)
3204 fprintf(stderr, _("(File:%s:) "), buf);
3206 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3207 0, 0, ss, ss, AllPlanes, XYPixmap);
3208 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3209 xpmJailSquare = xpmLightSquare;
3211 fprintf(stderr, _("Done.\n"));
3213 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3217 void CreateXPMPieces()
3221 u_int ss = squareSize;
3223 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3224 XpmColorSymbol symbols[4];
3226 /* The XSynchronize calls were copied from CreatePieces.
3227 Not sure if needed, but can't hurt */
3228 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3230 /* Setup translations so piece colors match square colors */
3231 symbols[0].name = "light_piece";
3232 symbols[0].value = appData.whitePieceColor;
3233 symbols[1].name = "dark_piece";
3234 symbols[1].value = appData.blackPieceColor;
3235 symbols[2].name = "light_square";
3236 symbols[2].value = appData.lightSquareColor;
3237 symbols[3].name = "dark_square";
3238 symbols[3].value = appData.darkSquareColor;
3240 attr.valuemask = XpmColorSymbols;
3241 attr.colorsymbols = symbols;
3242 attr.numsymbols = 4;
3244 if (appData.monoMode) {
3245 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3249 if (strlen(appData.pixmapDirectory) == 0) {
3250 XpmPieces* pieces = builtInXpms;
3253 while (pieces->size != squareSize && pieces->size) pieces++;
3254 if (!pieces->size) {
3255 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3258 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3259 for (kind=0; kind<4; kind++) {
3261 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3262 pieces->xpm[piece][kind],
3263 &(xpmPieceBitmap2[kind][piece]),
3264 NULL, &attr)) != 0) {
3265 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3269 if(piece <= (int) WhiteKing)
3270 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3274 xpmJailSquare = xpmLightSquare;
3278 fprintf(stderr, _("\nLoading XPMs...\n"));
3281 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3282 fprintf(stderr, "%d ", piece+1);
3283 for (kind=0; kind<4; kind++) {
3284 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3285 ExpandPathName(appData.pixmapDirectory),
3286 piece > (int) WhiteKing ? "w" : "",
3287 pieceBitmapNames[piece],
3289 if (appData.debugMode) {
3290 fprintf(stderr, _("(File:%s:) "), buf);
3292 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3293 &(xpmPieceBitmap2[kind][piece]),
3294 NULL, &attr)) != 0) {
3295 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3296 // [HGM] missing: read of unorthodox piece failed; substitute King.
3297 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3298 ExpandPathName(appData.pixmapDirectory),
3300 if (appData.debugMode) {
3301 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3303 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3304 &(xpmPieceBitmap2[kind][piece]),
3308 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3313 if(piece <= (int) WhiteKing)
3314 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3317 /* Load light and dark squares */
3318 /* If the LSQ and DSQ pieces don't exist, we will
3319 draw them with solid squares. */
3320 fprintf(stderr, _("light square "));
3321 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3322 if (access(buf, 0) != 0) {
3326 if (appData.debugMode)
3327 fprintf(stderr, _("(File:%s:) "), buf);
3329 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3330 &xpmLightSquare, NULL, &attr)) != 0) {
3331 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3334 fprintf(stderr, _("dark square "));
3335 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3336 ExpandPathName(appData.pixmapDirectory), ss);
3337 if (appData.debugMode) {
3338 fprintf(stderr, _("(File:%s:) "), buf);
3340 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3341 &xpmDarkSquare, NULL, &attr)) != 0) {
3342 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3346 xpmJailSquare = xpmLightSquare;
3347 fprintf(stderr, _("Done.\n"));
3349 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3352 #endif /* HAVE_LIBXPM */
3355 /* No built-in bitmaps */
3360 u_int ss = squareSize;
3362 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3365 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3366 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3367 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3368 pieceBitmapNames[piece],
3369 ss, kind == SOLID ? 's' : 'o');
3370 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3371 if(piece <= (int)WhiteKing)
3372 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3376 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3380 /* With built-in bitmaps */
3383 BuiltInBits* bib = builtInBits;
3386 u_int ss = squareSize;
3388 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3391 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3393 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3394 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3395 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3396 pieceBitmapNames[piece],
3397 ss, kind == SOLID ? 's' : 'o');
3398 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3399 bib->bits[kind][piece], ss, ss);
3400 if(piece <= (int)WhiteKing)
3401 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3405 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3410 void ReadBitmap(pm, name, bits, wreq, hreq)
3413 unsigned char bits[];
3419 char msg[MSG_SIZ], fullname[MSG_SIZ];
3421 if (*appData.bitmapDirectory != NULLCHAR) {
3422 strcpy(fullname, appData.bitmapDirectory);
3423 strcat(fullname, "/");
3424 strcat(fullname, name);
3425 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3426 &w, &h, pm, &x_hot, &y_hot);
3427 fprintf(stderr, "load %s\n", name);
3428 if (errcode != BitmapSuccess) {
3430 case BitmapOpenFailed:
3431 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3433 case BitmapFileInvalid:
3434 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3436 case BitmapNoMemory:
3437 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3441 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3445 fprintf(stderr, _("%s: %s...using built-in\n"),
3447 } else if (w != wreq || h != hreq) {
3449 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3450 programName, fullname, w, h, wreq, hreq);
3456 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3465 if (lineGap == 0) return;
3467 /* [HR] Split this into 2 loops for non-square boards. */
3469 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3470 gridSegments[i].x1 = 0;
3471 gridSegments[i].x2 =
3472 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3473 gridSegments[i].y1 = gridSegments[i].y2
3474 = lineGap / 2 + (i * (squareSize + lineGap));
3477 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3478 gridSegments[j + i].y1 = 0;
3479 gridSegments[j + i].y2 =
3480 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3481 gridSegments[j + i].x1 = gridSegments[j + i].x2
3482 = lineGap / 2 + (j * (squareSize + lineGap));
3486 static void MenuBarSelect(w, addr, index)
3491 XtActionProc proc = (XtActionProc) addr;
3493 (proc)(NULL, NULL, NULL, NULL);
3496 void CreateMenuBarPopup(parent, name, mb)
3506 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3509 XtSetArg(args[j], XtNleftMargin, 20); j++;
3510 XtSetArg(args[j], XtNrightMargin, 20); j++;
3512 while (mi->string != NULL) {
3513 if (strcmp(mi->string, "----") == 0) {
3514 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3517 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3518 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3520 XtAddCallback(entry, XtNcallback,
3521 (XtCallbackProc) MenuBarSelect,
3522 (caddr_t) mi->proc);
3528 Widget CreateMenuBar(mb)
3532 Widget anchor, menuBar;
3534 char menuName[MSG_SIZ];
3537 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3538 XtSetArg(args[j], XtNvSpace, 0); j++;
3539 XtSetArg(args[j], XtNborderWidth, 0); j++;
3540 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3541 formWidget, args, j);
3543 while (mb->name != NULL) {
3544 strcpy(menuName, "menu");
3545 strcat(menuName, mb->name);
3547 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3550 shortName[0] = _(mb->name)[0];
3551 shortName[1] = NULLCHAR;
3552 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3555 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3558 XtSetArg(args[j], XtNborderWidth, 0); j++;
3559 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3561 CreateMenuBarPopup(menuBar, menuName, mb);
3567 Widget CreateButtonBar(mi)
3571 Widget button, buttonBar;
3575 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3577 XtSetArg(args[j], XtNhSpace, 0); j++;
3579 XtSetArg(args[j], XtNborderWidth, 0); j++;
3580 XtSetArg(args[j], XtNvSpace, 0); j++;
3581 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3582 formWidget, args, j);
3584 while (mi->string != NULL) {
3587 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3588 XtSetArg(args[j], XtNborderWidth, 0); j++;
3590 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3591 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3592 buttonBar, args, j);
3593 XtAddCallback(button, XtNcallback,
3594 (XtCallbackProc) MenuBarSelect,
3595 (caddr_t) mi->proc);
3602 CreatePieceMenu(name, color)
3609 ChessSquare selection;
3611 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3612 boardWidget, args, 0);
3614 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3615 String item = pieceMenuStrings[color][i];
3617 if (strcmp(item, "----") == 0) {
3618 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3621 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3622 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3624 selection = pieceMenuTranslation[color][i];
3625 XtAddCallback(entry, XtNcallback,
3626 (XtCallbackProc) PieceMenuSelect,
3627 (caddr_t) selection);
3628 if (selection == WhitePawn || selection == BlackPawn) {
3629 XtSetArg(args[0], XtNpopupOnEntry, entry);
3630 XtSetValues(menu, args, 1);
3643 ChessSquare selection;
3645 whitePieceMenu = CreatePieceMenu("menuW", 0);
3646 blackPieceMenu = CreatePieceMenu("menuB", 1);
3648 XtRegisterGrabAction(PieceMenuPopup, True,
3649 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3650 GrabModeAsync, GrabModeAsync);
3652 XtSetArg(args[0], XtNlabel, _("Drop"));
3653 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3654 boardWidget, args, 1);
3655 for (i = 0; i < DROP_MENU_SIZE; i++) {
3656 String item = dropMenuStrings[i];
3658 if (strcmp(item, "----") == 0) {
3659 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3662 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3663 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3665 selection = dropMenuTranslation[i];
3666 XtAddCallback(entry, XtNcallback,
3667 (XtCallbackProc) DropMenuSelect,
3668 (caddr_t) selection);
3673 void SetupDropMenu()
3681 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3682 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3683 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3684 dmEnables[i].piece);
3685 XtSetSensitive(entry, p != NULL || !appData.testLegality
3686 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3687 && !appData.icsActive));
3689 while (p && *p++ == dmEnables[i].piece) count++;
3690 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3692 XtSetArg(args[j], XtNlabel, label); j++;
3693 XtSetValues(entry, args, j);
3697 void PieceMenuPopup(w, event, params, num_params)
3701 Cardinal *num_params;
3704 if (event->type != ButtonPress) return;
3705 if (errorUp) ErrorPopDown();
3709 whichMenu = params[0];
3711 case IcsPlayingWhite:
3712 case IcsPlayingBlack:
3714 case MachinePlaysWhite:
3715 case MachinePlaysBlack:
3716 if (appData.testLegality &&
3717 gameInfo.variant != VariantBughouse &&
3718 gameInfo.variant != VariantCrazyhouse) return;
3720 whichMenu = "menuD";
3726 if (((pmFromX = EventToSquare(event->xbutton.x, BOARD_WIDTH)) < 0) ||
3727 ((pmFromY = EventToSquare(event->xbutton.y, BOARD_HEIGHT)) < 0)) {
3728 pmFromX = pmFromY = -1;
3732 pmFromX = BOARD_WIDTH - 1 - pmFromX;
3734 pmFromY = BOARD_HEIGHT - 1 - pmFromY;
3736 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3739 static void PieceMenuSelect(w, piece, junk)
3744 if (pmFromX < 0 || pmFromY < 0) return;
3745 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3748 static void DropMenuSelect(w, piece, junk)
3753 if (pmFromX < 0 || pmFromY < 0) return;
3754 DropMenuEvent(piece, pmFromX, pmFromY);
3757 void WhiteClock(w, event, prms, nprms)
3763 if (gameMode == EditPosition || gameMode == IcsExamining) {
3764 SetWhiteToPlayEvent();
3765 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3770 void BlackClock(w, event, prms, nprms)
3776 if (gameMode == EditPosition || gameMode == IcsExamining) {
3777 SetBlackToPlayEvent();
3778 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3785 * If the user selects on a border boundary, return -1; if off the board,
3786 * return -2. Otherwise map the event coordinate to the square.
3788 int EventToSquare(x, limit)
3796 if ((x % (squareSize + lineGap)) >= squareSize)
3798 x /= (squareSize + lineGap);
3804 static void do_flash_delay(msec)
3810 static void drawHighlight(file, rank, gc)
3816 if (lineGap == 0 || appData.blindfold) return;
3819 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3820 (squareSize + lineGap);
3821 y = lineGap/2 + rank * (squareSize + lineGap);
3823 x = lineGap/2 + file * (squareSize + lineGap);
3824 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3825 (squareSize + lineGap);
3828 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3829 squareSize+lineGap, squareSize+lineGap);
3832 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3833 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3836 SetHighlights(fromX, fromY, toX, toY)
3837 int fromX, fromY, toX, toY;
3839 if (hi1X != fromX || hi1Y != fromY) {
3840 if (hi1X >= 0 && hi1Y >= 0) {
3841 drawHighlight(hi1X, hi1Y, lineGC);
3843 if (fromX >= 0 && fromY >= 0) {
3844 drawHighlight(fromX, fromY, highlineGC);
3847 if (hi2X != toX || hi2Y != toY) {
3848 if (hi2X >= 0 && hi2Y >= 0) {
3849 drawHighlight(hi2X, hi2Y, lineGC);
3851 if (toX >= 0 && toY >= 0) {
3852 drawHighlight(toX, toY, highlineGC);
3864 SetHighlights(-1, -1, -1, -1);
3869 SetPremoveHighlights(fromX, fromY, toX, toY)
3870 int fromX, fromY, toX, toY;
3872 if (pm1X != fromX || pm1Y != fromY) {
3873 if (pm1X >= 0 && pm1Y >= 0) {
3874 drawHighlight(pm1X, pm1Y, lineGC);
3876 if (fromX >= 0 && fromY >= 0) {
3877 drawHighlight(fromX, fromY, prelineGC);
3880 if (pm2X != toX || pm2Y != toY) {
3881 if (pm2X >= 0 && pm2Y >= 0) {
3882 drawHighlight(pm2X, pm2Y, lineGC);
3884 if (toX >= 0 && toY >= 0) {
3885 drawHighlight(toX, toY, prelineGC);
3895 ClearPremoveHighlights()
3897 SetPremoveHighlights(-1, -1, -1, -1);
3900 static void BlankSquare(x, y, color, piece, dest)
3905 if (useImages && useImageSqs) {
3909 pm = xpmLightSquare;
3914 case 2: /* neutral */
3919 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
3920 squareSize, squareSize, x, y);
3930 case 2: /* neutral */
3935 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
3940 I split out the routines to draw a piece so that I could
3941 make a generic flash routine.
3943 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
3945 int square_color, x, y;
3948 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3949 switch (square_color) {
3951 case 2: /* neutral */
3953 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3954 ? *pieceToOutline(piece)
3955 : *pieceToSolid(piece),
3956 dest, bwPieceGC, 0, 0,
3957 squareSize, squareSize, x, y);
3960 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3961 ? *pieceToSolid(piece)
3962 : *pieceToOutline(piece),
3963 dest, wbPieceGC, 0, 0,
3964 squareSize, squareSize, x, y);
3969 static void monoDrawPiece(piece, square_color, x, y, dest)
3971 int square_color, x, y;
3974 switch (square_color) {
3976 case 2: /* neutral */
3978 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3979 ? *pieceToOutline(piece)
3980 : *pieceToSolid(piece),
3981 dest, bwPieceGC, 0, 0,
3982 squareSize, squareSize, x, y, 1);
3985 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3986 ? *pieceToSolid(piece)
3987 : *pieceToOutline(piece),
3988 dest, wbPieceGC, 0, 0,
3989 squareSize, squareSize, x, y, 1);
3994 static void colorDrawPiece(piece, square_color, x, y, dest)
3996 int square_color, x, y;
3999 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4000 switch (square_color) {
4002 XCopyPlane(xDisplay, *pieceToSolid(piece),
4003 dest, (int) piece < (int) BlackPawn
4004 ? wlPieceGC : blPieceGC, 0, 0,
4005 squareSize, squareSize, x, y, 1);
4008 XCopyPlane(xDisplay, *pieceToSolid(piece),
4009 dest, (int) piece < (int) BlackPawn
4010 ? wdPieceGC : bdPieceGC, 0, 0,
4011 squareSize, squareSize, x, y, 1);
4013 case 2: /* neutral */
4015 XCopyPlane(xDisplay, *pieceToSolid(piece),
4016 dest, (int) piece < (int) BlackPawn
4017 ? wjPieceGC : bjPieceGC, 0, 0,
4018 squareSize, squareSize, x, y, 1);
4023 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4025 int square_color, x, y;
4030 switch (square_color) {
4032 case 2: /* neutral */
4034 if ((int)piece < (int) BlackPawn) {
4042 if ((int)piece < (int) BlackPawn) {
4050 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4051 dest, wlPieceGC, 0, 0,
4052 squareSize, squareSize, x, y);
4055 typedef void (*DrawFunc)();
4057 DrawFunc ChooseDrawFunc()
4059 if (appData.monoMode) {
4060 if (DefaultDepth(xDisplay, xScreen) == 1) {
4061 return monoDrawPiece_1bit;
4063 return monoDrawPiece;
4067 return colorDrawPieceImage;
4069 return colorDrawPiece;
4073 /* [HR] determine square color depending on chess variant. */
4074 static int SquareColor(row, column)
4079 if (gameInfo.variant == VariantXiangqi) {
4080 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4082 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4084 } else if (row <= 4) {
4090 square_color = ((column + row) % 2) == 1;
4093 /* [hgm] holdings: next line makes all holdings squares light */
4094 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4096 return square_color;
4099 void DrawSquare(row, column, piece, do_flash)
4100 int row, column, do_flash;
4103 int square_color, x, y, direction, font_ascent, font_descent;
4106 XCharStruct overall;
4110 /* Calculate delay in milliseconds (2-delays per complete flash) */
4111 flash_delay = 500 / appData.flashRate;
4114 x = lineGap + ((BOARD_WIDTH-1)-column) *
4115 (squareSize + lineGap);
4116 y = lineGap + row * (squareSize + lineGap);
4118 x = lineGap + column * (squareSize + lineGap);
4119 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4120 (squareSize + lineGap);
4123 square_color = SquareColor(row, column);
4125 if ( // [HGM] holdings: blank out area between board and holdings
4126 column == BOARD_LEFT-1 || column == BOARD_RGHT
4127 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4128 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4129 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4131 // [HGM] print piece counts next to holdings
4132 string[1] = NULLCHAR;
4133 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && 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 + squareSize - overall.width - 2,
4140 y + font_ascent + 1, string, 1);
4142 XDrawString(xDisplay, xBoardWindow, countGC,
4143 x + squareSize - overall.width - 2,
4144 y + font_ascent + 1, string, 1);
4147 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4148 string[0] = '0' + piece;
4149 XTextExtents(countFontStruct, string, 1, &direction,
4150 &font_ascent, &font_descent, &overall);
4151 if (appData.monoMode) {
4152 XDrawImageString(xDisplay, xBoardWindow, countGC,
4153 x + 2, y + font_ascent + 1, string, 1);
4155 XDrawString(xDisplay, xBoardWindow, countGC,
4156 x + 2, y + font_ascent + 1, string, 1);
4160 if (piece == EmptySquare || appData.blindfold) {
4161 BlankSquare(x, y, square_color, piece, xBoardWindow);
4163 drawfunc = ChooseDrawFunc();
4164 if (do_flash && appData.flashCount > 0) {
4165 for (i=0; i<appData.flashCount; ++i) {
4167 drawfunc(piece, square_color, x, y, xBoardWindow);
4168 XSync(xDisplay, False);
4169 do_flash_delay(flash_delay);
4171 BlankSquare(x, y, square_color, piece, xBoardWindow);
4172 XSync(xDisplay, False);
4173 do_flash_delay(flash_delay);
4176 drawfunc(piece, square_color, x, y, xBoardWindow);
4180 string[1] = NULLCHAR;
4181 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4182 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4183 string[0] = 'a' + column - BOARD_LEFT;
4184 XTextExtents(coordFontStruct, string, 1, &direction,
4185 &font_ascent, &font_descent, &overall);
4186 if (appData.monoMode) {
4187 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4188 x + squareSize - overall.width - 2,
4189 y + squareSize - font_descent - 1, string, 1);
4191 XDrawString(xDisplay, xBoardWindow, coordGC,
4192 x + squareSize - overall.width - 2,
4193 y + squareSize - font_descent - 1, string, 1);
4196 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4197 string[0] = ONE + row;
4198 XTextExtents(coordFontStruct, string, 1, &direction,
4199 &font_ascent, &font_descent, &overall);
4200 if (appData.monoMode) {
4201 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4202 x + 2, y + font_ascent + 1, string, 1);
4204 XDrawString(xDisplay, xBoardWindow, coordGC,
4205 x + 2, y + font_ascent + 1, string, 1);
4211 /* Why is this needed on some versions of X? */
4212 void EventProc(widget, unused, event)
4217 if (!XtIsRealized(widget))
4220 switch (event->type) {
4222 if (event->xexpose.count > 0) return; /* no clipping is done */
4223 XDrawPosition(widget, True, NULL);
4231 void DrawPosition(fullRedraw, board)
4232 /*Boolean*/int fullRedraw;
4235 XDrawPosition(boardWidget, fullRedraw, board);
4238 /* Returns 1 if there are "too many" differences between b1 and b2
4239 (i.e. more than 1 move was made) */
4240 static int too_many_diffs(b1, b2)