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, 2010, 2011, 2012 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. */
60 #include <sys/types.h>
66 # if HAVE_SYS_SOCKET_H
67 # include <sys/socket.h>
68 # include <netinet/in.h>
70 # else /* not HAVE_SYS_SOCKET_H */
71 # if HAVE_LAN_SOCKET_H
72 # include <lan/socket.h>
74 # include <lan/netdb.h>
75 # else /* not HAVE_LAN_SOCKET_H */
76 # define OMIT_SOCKETS 1
77 # endif /* not HAVE_LAN_SOCKET_H */
78 # endif /* not HAVE_SYS_SOCKET_H */
79 #endif /* !OMIT_SOCKETS */
84 #else /* not STDC_HEADERS */
85 extern char *getenv();
88 # else /* not HAVE_STRING_H */
90 # endif /* not HAVE_STRING_H */
91 #endif /* not STDC_HEADERS */
94 # include <sys/fcntl.h>
95 #else /* not HAVE_SYS_FCNTL_H */
98 # endif /* HAVE_FCNTL_H */
99 #endif /* not HAVE_SYS_FCNTL_H */
101 #if HAVE_SYS_SYSTEMINFO_H
102 # include <sys/systeminfo.h>
103 #endif /* HAVE_SYS_SYSTEMINFO_H */
105 #if TIME_WITH_SYS_TIME
106 # include <sys/time.h>
110 # include <sys/time.h>
121 # include <sys/wait.h>
126 # define NAMLEN(dirent) strlen((dirent)->d_name)
127 # define HAVE_DIR_STRUCT
129 # define dirent direct
130 # define NAMLEN(dirent) (dirent)->d_namlen
132 # include <sys/ndir.h>
133 # define HAVE_DIR_STRUCT
136 # include <sys/dir.h>
137 # define HAVE_DIR_STRUCT
141 # define HAVE_DIR_STRUCT
149 #include <X11/Intrinsic.h>
150 #include <X11/StringDefs.h>
151 #include <X11/Shell.h>
152 #include <X11/cursorfont.h>
153 #include <X11/Xatom.h>
154 #include <X11/Xmu/Atoms.h>
156 #include <X11/Xaw3d/Dialog.h>
157 #include <X11/Xaw3d/Form.h>
158 #include <X11/Xaw3d/List.h>
159 #include <X11/Xaw3d/Label.h>
160 #include <X11/Xaw3d/SimpleMenu.h>
161 #include <X11/Xaw3d/SmeBSB.h>
162 #include <X11/Xaw3d/SmeLine.h>
163 #include <X11/Xaw3d/Box.h>
164 #include <X11/Xaw3d/MenuButton.h>
165 #include <X11/Xaw3d/Text.h>
166 #include <X11/Xaw3d/AsciiText.h>
168 #include <X11/Xaw/Dialog.h>
169 #include <X11/Xaw/Form.h>
170 #include <X11/Xaw/List.h>
171 #include <X11/Xaw/Label.h>
172 #include <X11/Xaw/SimpleMenu.h>
173 #include <X11/Xaw/SmeBSB.h>
174 #include <X11/Xaw/SmeLine.h>
175 #include <X11/Xaw/Box.h>
176 #include <X11/Xaw/MenuButton.h>
177 #include <X11/Xaw/Text.h>
178 #include <X11/Xaw/AsciiText.h>
181 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
186 #include "pixmaps/pixmaps.h"
187 #define IMAGE_EXT "xpm"
189 #define IMAGE_EXT "xim"
190 #include "bitmaps/bitmaps.h"
193 #include "bitmaps/icon_white.bm"
194 #include "bitmaps/icon_black.bm"
195 #include "bitmaps/checkmark.bm"
197 #include "frontend.h"
199 #include "backendz.h"
203 #include "xgamelist.h"
204 #include "xhistory.h"
205 #include "xedittags.h"
208 // must be moved to xengineoutput.h
210 void EngineOutputProc P((Widget w, XEvent *event,
211 String *prms, Cardinal *nprms));
212 void EvalGraphProc P((Widget w, XEvent *event,
213 String *prms, Cardinal *nprms));
220 #define usleep(t) _sleep2(((t)+500)/1000)
224 # define _(s) gettext (s)
225 # define N_(s) gettext_noop (s)
245 int main P((int argc, char **argv));
246 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
247 char *init_path, char *filter, char *mode, int (*show_entry)(), char **name_return));
248 RETSIGTYPE CmailSigHandler P((int sig));
249 RETSIGTYPE IntSigHandler P((int sig));
250 RETSIGTYPE TermSizeSigHandler P((int sig));
251 void CreateGCs P((int redo));
252 void CreateAnyPieces P((void));
253 void CreateXIMPieces P((void));
254 void CreateXPMPieces P((void));
255 void CreateXPMBoard P((char *s, int n));
256 void CreatePieces P((void));
257 void CreatePieceMenus P((void));
258 Widget CreateMenuBar P((Menu *mb, int boardWidth));
259 Widget CreateButtonBar P ((MenuItem *mi));
261 char *InsertPxlSize P((char *pattern, int targetPxlSize));
262 XFontSet CreateFontSet P((char *base_fnt_lst));
264 char *FindFont P((char *pattern, int targetPxlSize));
266 void PieceMenuPopup P((Widget w, XEvent *event,
267 String *params, Cardinal *num_params));
268 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
269 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
270 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
271 u_int wreq, u_int hreq));
272 void CreateGrid P((void));
273 int EventToSquare P((int x, int limit));
274 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
275 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
276 void DelayedDrag P((void));
277 void MoveTypeInProc P((Widget widget, caddr_t unused, XEvent *event));
278 void HandleUserMove P((Widget w, XEvent *event,
279 String *prms, Cardinal *nprms));
280 void AnimateUserMove P((Widget w, XEvent * event,
281 String * params, Cardinal * nParams));
282 void HandlePV P((Widget w, XEvent * event,
283 String * params, Cardinal * nParams));
284 void SelectPV P((Widget w, XEvent * event,
285 String * params, Cardinal * nParams));
286 void StopPV P((Widget w, XEvent * event,
287 String * params, Cardinal * nParams));
288 void WhiteClock P((Widget w, XEvent *event,
289 String *prms, Cardinal *nprms));
290 void BlackClock P((Widget w, XEvent *event,
291 String *prms, Cardinal *nprms));
292 void DrawPositionProc P((Widget w, XEvent *event,
293 String *prms, Cardinal *nprms));
294 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
296 void CommentClick P((Widget w, XEvent * event,
297 String * params, Cardinal * nParams));
298 void CommentPopUp P((char *title, char *label));
299 void CommentPopDown P((void));
300 void ICSInputBoxPopUp P((void));
301 void ICSInputBoxPopDown P((void));
302 void FileNamePopUp P((char *label, char *def, char *filter,
303 FileProc proc, char *openMode));
304 void FileNamePopDown P((void));
305 void FileNameCallback P((Widget w, XtPointer client_data,
306 XtPointer call_data));
307 void FileNameAction P((Widget w, XEvent *event,
308 String *prms, Cardinal *nprms));
309 void AskQuestionReplyAction P((Widget w, XEvent *event,
310 String *prms, Cardinal *nprms));
311 void AskQuestionProc P((Widget w, XEvent *event,
312 String *prms, Cardinal *nprms));
313 void AskQuestionPopDown P((void));
314 void PromotionPopDown P((void));
315 void PromotionCallback P((Widget w, XtPointer client_data,
316 XtPointer call_data));
317 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
318 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
319 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
320 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
322 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
324 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
326 void LoadPositionProc P((Widget w, XEvent *event,
327 String *prms, Cardinal *nprms));
328 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
330 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
332 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
334 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
336 void PastePositionProc P((Widget w, XEvent *event, String *prms,
338 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
339 void CopyGameListProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
340 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
341 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
342 void SavePositionProc P((Widget w, XEvent *event,
343 String *prms, Cardinal *nprms));
344 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
345 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
347 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
348 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
349 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
351 void MachineWhiteProc P((Widget w, XEvent *event,
352 String *prms, Cardinal *nprms));
353 void AnalyzeModeProc P((Widget w, XEvent *event,
354 String *prms, Cardinal *nprms));
355 void AnalyzeFileProc P((Widget w, XEvent *event,
356 String *prms, Cardinal *nprms));
357 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
359 void MatchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void MatchOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void IcsClientProc P((Widget w, XEvent *event, String *prms,
363 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void EditPositionProc P((Widget w, XEvent *event,
365 String *prms, Cardinal *nprms));
366 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void EditCommentProc P((Widget w, XEvent *event,
368 String *prms, Cardinal *nprms));
369 void IcsInputBoxProc P((Widget w, XEvent *event,
370 String *prms, Cardinal *nprms));
371 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
372 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
373 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
374 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
375 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
376 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
377 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
379 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
380 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void TypeInProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
384 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
385 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
386 void StopObservingProc P((Widget w, XEvent *event, String *prms,
388 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
390 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
391 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
392 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
393 void TempBackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
394 void TempForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
395 Boolean TempBackwardActive = False;
396 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
397 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
398 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
399 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
400 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
402 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
404 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
405 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
407 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
409 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
411 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
412 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
413 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
414 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
416 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
417 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
419 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
421 void HighlightArrowProc P((Widget w, XEvent *event, String *prms,
423 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
424 //void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
425 void OneClickProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
426 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
428 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
430 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
432 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
434 //void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
435 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
437 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
439 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
441 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
443 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
444 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
445 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
446 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
447 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
448 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
449 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
450 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
451 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
452 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
453 void DisplayMove P((int moveNumber));
454 void DisplayTitle P((char *title));
455 void ICSInitScript P((void));
456 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
457 void ErrorPopUp P((char *title, char *text, int modal));
458 void ErrorPopDown P((void));
459 static char *ExpandPathName P((char *path));
460 static void CreateAnimVars P((void));
461 static void DragPieceMove P((int x, int y));
462 static void DrawDragPiece P((void));
463 char *ModeToWidgetName P((GameMode mode));
464 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
465 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
466 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
467 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
468 void OptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
469 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
470 void IcsTextProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
471 void LoadEngineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
472 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
473 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
474 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
475 void IcsOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
476 void SoundOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
477 void BoardOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
478 void LoadOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
479 void SaveOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
480 void EditBookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
481 void SelectMove P((Widget w, XEvent * event, String * params, Cardinal * nParams));
482 void GameListOptionsPopDown P(());
483 void GenericPopDown P(());
484 void update_ics_width P(());
485 int get_term_width P(());
486 int CopyMemoProc P(());
487 void DrawArrowHighlight P((int fromX, int fromY, int toX,int toY));
488 Boolean IsDrawArrowEnabled P(());
491 * XBoard depends on Xt R4 or higher
493 int xtVersion = XtSpecificationRelease;
498 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
499 jailSquareColor, highlightSquareColor, premoveHighlightColor;
500 Pixel lowTimeWarningColor;
501 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
502 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
503 wjPieceGC, bjPieceGC, prelineGC, countGC;
504 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
505 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
506 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
507 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
508 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
509 ICSInputShell, fileNameShell, askQuestionShell;
510 Widget historyShell, evalGraphShell, gameListShell;
511 int hOffset; // [HGM] dual
512 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
513 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
514 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
516 XFontSet fontSet, clockFontSet;
519 XFontStruct *clockFontStruct;
521 Font coordFontID, countFontID;
522 XFontStruct *coordFontStruct, *countFontStruct;
523 XtAppContext appContext;
525 char *oldICSInteractionTitle;
529 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
531 Position commentX = -1, commentY = -1;
532 Dimension commentW, commentH;
533 typedef unsigned int BoardSize;
535 Boolean chessProgram;
537 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
538 int squareSize, smallLayout = 0, tinyLayout = 0,
539 marginW, marginH, // [HGM] for run-time resizing
540 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
541 ICSInputBoxUp = False, askQuestionUp = False,
542 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
543 errorUp = False, errorExitStatus = -1, lineGap, defaultLineGap;
544 Dimension textHeight;
545 Pixel timerForegroundPixel, timerBackgroundPixel;
546 Pixel buttonForegroundPixel, buttonBackgroundPixel;
547 char *chessDir, *programName, *programVersion,
548 *gameCopyFilename, *gamePasteFilename;
549 Boolean alwaysOnTop = False;
550 Boolean saveSettingsOnExit;
551 char *settingsFileName;
552 char *icsTextMenuString;
554 char *firstChessProgramNames;
555 char *secondChessProgramNames;
557 WindowPlacement wpMain;
558 WindowPlacement wpConsole;
559 WindowPlacement wpComment;
560 WindowPlacement wpMoveHistory;
561 WindowPlacement wpEvalGraph;
562 WindowPlacement wpEngineOutput;
563 WindowPlacement wpGameList;
564 WindowPlacement wpTags;
566 extern Widget shells[];
567 extern Boolean shellUp[];
571 Pixmap pieceBitmap[2][(int)BlackPawn];
572 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
573 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
574 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
575 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
576 Pixmap xpmBoardBitmap[2];
577 int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
578 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
579 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
580 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
581 XImage *ximLightSquare, *ximDarkSquare;
584 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
585 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
587 #define White(piece) ((int)(piece) < (int)BlackPawn)
589 /* Variables for doing smooth animation. This whole thing
590 would be much easier if the board was double-buffered,
591 but that would require a fairly major rewrite. */
596 GC blitGC, pieceGC, outlineGC;
597 XPoint startSquare, prevFrame, mouseDelta;
601 int startBoardX, startBoardY;
604 /* There can be two pieces being animated at once: a player
605 can begin dragging a piece before the remote opponent has moved. */
607 static AnimState game, player;
609 /* Bitmaps for use as masks when drawing XPM pieces.
610 Need one for each black and white piece. */
611 static Pixmap xpmMask[BlackKing + 1];
613 /* This magic number is the number of intermediate frames used
614 in each half of the animation. For short moves it's reduced
615 by 1. The total number of frames will be factor * 2 + 1. */
618 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
620 MenuItem fileMenu[] = {
621 {N_("New Game Ctrl+N"), "New Game", ResetProc},
622 {N_("New Shuffle Game ..."), "New Shuffle Game", ShuffleMenuProc},
623 {N_("New Variant ... Alt+Shift+V"), "New Variant", NewVariantProc}, // [HGM] variant: not functional yet
624 {"----", NULL, NothingProc},
625 {N_("Load Game Ctrl+O"), "Load Game", LoadGameProc},
626 {N_("Load Position Ctrl+Shift+O"), "Load Position", LoadPositionProc},
627 // {N_("Load Next Game"), "Load Next Game", LoadNextGameProc},
628 // {N_("Load Previous Game"), "Load Previous Game", LoadPrevGameProc},
629 // {N_("Reload Same Game"), "Reload Same Game", ReloadGameProc},
630 {N_("Next Position Shift+PgDn"), "Load Next Position", LoadNextPositionProc},
631 {N_("Prev Position Shift+PgUp"), "Load Previous Position", LoadPrevPositionProc},
632 {"----", NULL, NothingProc},
633 // {N_("Reload Same Position"), "Reload Same Position", ReloadPositionProc},
634 {N_("Save Game Ctrl+S"), "Save Game", SaveGameProc},
635 {N_("Save Position Ctrl+Shift+S"), "Save Position", SavePositionProc},
636 {"----", NULL, NothingProc},
637 {N_("Mail Move"), "Mail Move", MailMoveProc},
638 {N_("Reload CMail Message"), "Reload CMail Message", ReloadCmailMsgProc},
639 {"----", NULL, NothingProc},
640 {N_("Quit Ctr+Q"), "Exit", QuitProc},
644 MenuItem editMenu[] = {
645 {N_("Copy Game Ctrl+C"), "Copy Game", CopyGameProc},
646 {N_("Copy Position Ctrl+Shift+C"), "Copy Position", CopyPositionProc},
647 {N_("Copy Game List"), "Copy Game List", CopyGameListProc},
648 {"----", NULL, NothingProc},
649 {N_("Paste Game Ctrl+V"), "Paste Game", PasteGameProc},
650 {N_("Paste Position Ctrl+Shift+V"), "Paste Position", PastePositionProc},
651 {"----", NULL, NothingProc},
652 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
653 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
654 {N_("Edit Tags"), "Edit Tags", EditTagsProc},
655 {N_("Edit Comment"), "Edit Comment", EditCommentProc},
656 {N_("Edit Book"), "Edit Book", EditBookProc},
657 {"----", NULL, NothingProc},
658 {N_("Revert Home"), "Revert", RevertProc},
659 {N_("Annotate"), "Annotate", AnnotateProc},
660 {N_("Truncate Game End"), "Truncate Game", TruncateGameProc},
661 {"----", NULL, NothingProc},
662 {N_("Backward Alt+Left"), "Backward", BackwardProc},
663 {N_("Forward Alt+Right"), "Forward", ForwardProc},
664 {N_("Back to Start Alt+Home"), "Back to Start", ToStartProc},
665 {N_("Forward to End Alt+End"), "Forward to End", ToEndProc},
669 MenuItem viewMenu[] = {
670 {N_("Flip View F2"), "Flip View", FlipViewProc},
671 {"----", NULL, NothingProc},
672 {N_("Engine Output Alt+Shift+O"), "Show Engine Output", EngineOutputProc},
673 {N_("Move History Alt+Shift+H"), "Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
674 {N_("Evaluation Graph Alt+Shift+E"), "Show Evaluation Graph", EvalGraphProc},
675 {N_("Game List Alt+Shift+G"), "Show Game List", ShowGameListProc},
676 {N_("ICS text menu"), "ICStex", IcsTextProc},
677 {"----", NULL, NothingProc},
678 {N_("Tags"), "Show Tags", EditTagsProc},
679 {N_("Comments"), "Show Comments", EditCommentProc},
680 {N_("ICS Input Box"), "ICS Input Box", IcsInputBoxProc},
681 {"----", NULL, NothingProc},
682 {N_("Board..."), "Board Options", BoardOptionsProc},
683 {N_("Game List Tags..."), "Game List", GameListOptionsPopUp},
687 MenuItem modeMenu[] = {
688 {N_("Machine White Ctrl+W"), "Machine White", MachineWhiteProc},
689 {N_("Machine Black Ctrl+B"), "Machine Black", MachineBlackProc},
690 {N_("Two Machines Ctrl+T"), "Two Machines", TwoMachinesProc},
691 {N_("Analysis Mode Ctrl+A"), "Analysis Mode", AnalyzeModeProc},
692 {N_("Analyze Game Ctrl+G"), "Analyze File", AnalyzeFileProc },
693 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
694 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
695 {N_("Training"), "Training", TrainingProc},
696 {N_("ICS Client"), "ICS Client", IcsClientProc},
697 {"----", NULL, NothingProc},
698 {N_("Machine Match"), "Machine Match", MatchProc},
699 {N_("Pause Pause"), "Pause", PauseProc},
703 MenuItem actionMenu[] = {
704 {N_("Accept F3"), "Accept", AcceptProc},
705 {N_("Decline F4"), "Decline", DeclineProc},
706 {N_("Rematch F12"), "Rematch", RematchProc},
707 {"----", NULL, NothingProc},
708 {N_("Call Flag F5"), "Call Flag", CallFlagProc},
709 {N_("Draw F6"), "Draw", DrawProc},
710 {N_("Adjourn F7"), "Adjourn", AdjournProc},
711 {N_("Abort F8"),"Abort", AbortProc},
712 {N_("Resign F9"), "Resign", ResignProc},
713 {"----", NULL, NothingProc},
714 {N_("Stop Observing F10"), "Stop Observing", StopObservingProc},
715 {N_("Stop Examining F11"), "Stop Examining", StopExaminingProc},
716 {N_("Upload to Examine"), "Upload to Examine", UploadProc},
717 {"----", NULL, NothingProc},
718 {N_("Adjudicate to White"), "Adjudicate to White", AdjuWhiteProc},
719 {N_("Adjudicate to Black"), "Adjudicate to Black", AdjuBlackProc},
720 {N_("Adjudicate Draw"), "Adjudicate Draw", AdjuDrawProc},
724 MenuItem engineMenu[] = {
725 {N_("Load New Engine ..."), "Load Engine", LoadEngineProc},
726 {"----", NULL, NothingProc},
727 {N_("Engine #1 Settings ..."), "Engine #1 Settings", FirstSettingsProc},
728 {N_("Engine #2 Settings ..."), "Engine #2 Settings", SecondSettingsProc},
729 {"----", NULL, NothingProc},
730 {N_("Hint"), "Hint", HintProc},
731 {N_("Book"), "Book", BookProc},
732 {"----", NULL, NothingProc},
733 {N_("Move Now Ctrl+M"), "Move Now", MoveNowProc},
734 {N_("Retract Move Ctrl+X"), "Retract Move", RetractMoveProc},
738 MenuItem optionsMenu[] = {
739 #define OPTIONSDIALOG
741 {N_("General ..."), "General", OptionsProc},
743 {N_("Time Control ... Alt+Shift+T"), "Time Control", TimeControlProc},
744 {N_("Common Engine ... Alt+Shift+U"), "Common Engine", UciMenuProc},
745 {N_("Adjudications ... Alt+Shift+J"), "Adjudications", EngineMenuProc},
746 {N_("ICS ..."), "ICS", IcsOptionsProc},
747 {N_("Match ..."), "Match", MatchOptionsProc},
748 {N_("Load Game ..."), "Load Game", LoadOptionsProc},
749 {N_("Save Game ..."), "Save Game", SaveOptionsProc},
750 // {N_(" ..."), "", OptionsProc},
751 {N_("Game List ..."), "Game List", GameListOptionsPopUp},
752 {N_("Sounds ..."), "Sounds", SoundOptionsProc},
753 {"----", NULL, NothingProc},
754 #ifndef OPTIONSDIALOG
755 {N_("Always Queen Ctrl+Shift+Q"), "Always Queen", AlwaysQueenProc},
756 {N_("Animate Dragging"), "Animate Dragging", AnimateDraggingProc},
757 {N_("Animate Moving Ctrl+Shift+A"), "Animate Moving", AnimateMovingProc},
758 {N_("Auto Flag Ctrl+Shift+F"), "Auto Flag", AutoflagProc},
759 {N_("Auto Flip View"), "Auto Flip View", AutoflipProc},
760 {N_("Blindfold"), "Blindfold", BlindfoldProc},
761 {N_("Flash Moves"), "Flash Moves", FlashMovesProc},
763 {N_("Highlight Dragging"), "Highlight Dragging", HighlightDraggingProc},
765 {N_("Highlight Last Move"), "Highlight Last Move", HighlightLastMoveProc},
766 {N_("Highlight With Arrow"), "Arrow", HighlightArrowProc},
767 {N_("Move Sound"), "Move Sound", MoveSoundProc},
768 // {N_("ICS Alarm"), "ICS Alarm", IcsAlarmProc},
769 {N_("One-Click Moving"), "OneClick", OneClickProc},
770 {N_("Periodic Updates"), "Periodic Updates", PeriodicUpdatesProc},
771 {N_("Ponder Next Move Ctrl+Shift+P"), "Ponder Next Move", PonderNextMoveProc},
772 {N_("Popup Exit Message"), "Popup Exit Message", PopupExitMessageProc},
773 {N_("Popup Move Errors"), "Popup Move Errors", PopupMoveErrorsProc},
774 // {N_("Premove"), "Premove", PremoveProc},
775 {N_("Show Coords"), "Show Coords", ShowCoordsProc},
776 {N_("Hide Thinking Ctrl+Shift+H"), "Hide Thinking", HideThinkingProc},
777 {N_("Test Legality Ctrl+Shift+L"), "Test Legality", TestLegalityProc},
778 {"----", NULL, NothingProc},
780 {N_("Save Settings Now"), "Save Settings Now", SaveSettingsProc},
781 {N_("Save Settings on Exit"), "Save Settings on Exit", SaveOnExitProc},
785 MenuItem helpMenu[] = {
786 {N_("Info XBoard"), "Info XBoard", InfoProc},
787 {N_("Man XBoard F1"), "Man XBoard", ManProc},
788 {"----", NULL, NothingProc},
789 {N_("About XBoard"), "About XBoard", AboutProc},
794 {N_("File"), "File", fileMenu},
795 {N_("Edit"), "Edit", editMenu},
796 {N_("View"), "View", viewMenu},
797 {N_("Mode"), "Mode", modeMenu},
798 {N_("Action"), "Action", actionMenu},
799 {N_("Engine"), "Engine", engineMenu},
800 {N_("Options"), "Options", optionsMenu},
801 {N_("Help"), "Help", helpMenu},
805 #define PAUSE_BUTTON "P"
806 MenuItem buttonBar[] = {
807 {"<<", "<<", ToStartProc},
808 {"<", "<", BackwardProc},
809 {N_(PAUSE_BUTTON), PAUSE_BUTTON, PauseProc},
810 {">", ">", ForwardProc},
811 {">>", ">>", ToEndProc},
815 #define PIECE_MENU_SIZE 18
816 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
817 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
818 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
819 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
820 N_("Empty square"), N_("Clear board") },
821 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
822 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
823 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
824 N_("Empty square"), N_("Clear board") }
826 /* must be in same order as pieceMenuStrings! */
827 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
828 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
829 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
830 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
831 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
832 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
833 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
834 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
835 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
838 #define DROP_MENU_SIZE 6
839 String dropMenuStrings[DROP_MENU_SIZE] = {
840 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
842 /* must be in same order as dropMenuStrings! */
843 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
844 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
845 WhiteRook, WhiteQueen
853 DropMenuEnables dmEnables[] = {
871 { XtNborderWidth, 0 },
872 { XtNdefaultDistance, 0 },
876 { XtNborderWidth, 0 },
877 { XtNresizable, (XtArgVal) True },
881 { XtNborderWidth, 0 },
887 { XtNjustify, (XtArgVal) XtJustifyRight },
888 { XtNlabel, (XtArgVal) "..." },
889 { XtNresizable, (XtArgVal) True },
890 { XtNresize, (XtArgVal) False }
893 Arg messageArgs[] = {
894 { XtNjustify, (XtArgVal) XtJustifyLeft },
895 { XtNlabel, (XtArgVal) "..." },
896 { XtNresizable, (XtArgVal) True },
897 { XtNresize, (XtArgVal) False }
901 { XtNborderWidth, 0 },
902 { XtNjustify, (XtArgVal) XtJustifyLeft }
905 XtResource clientResources[] = {
906 { "flashCount", "flashCount", XtRInt, sizeof(int),
907 XtOffset(AppDataPtr, flashCount), XtRImmediate,
908 (XtPointer) FLASH_COUNT },
911 XrmOptionDescRec shellOptions[] = {
912 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
913 { "-flash", "flashCount", XrmoptionNoArg, "3" },
914 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
917 XtActionsRec boardActions[] = {
918 { "DrawPosition", DrawPositionProc },
919 { "HandleUserMove", HandleUserMove },
920 { "AnimateUserMove", AnimateUserMove },
921 { "HandlePV", HandlePV },
922 { "SelectPV", SelectPV },
923 { "StopPV", StopPV },
924 { "FileNameAction", FileNameAction },
925 { "AskQuestionProc", AskQuestionProc },
926 { "AskQuestionReplyAction", AskQuestionReplyAction },
927 { "PieceMenuPopup", PieceMenuPopup },
928 { "WhiteClock", WhiteClock },
929 { "BlackClock", BlackClock },
930 { "ResetProc", ResetProc },
931 { "NewVariantProc", NewVariantProc },
932 { "LoadGameProc", LoadGameProc },
933 { "LoadNextGameProc", LoadNextGameProc },
934 { "LoadPrevGameProc", LoadPrevGameProc },
935 { "LoadSelectedProc", LoadSelectedProc },
936 { "SetFilterProc", SetFilterProc },
937 { "ReloadGameProc", ReloadGameProc },
938 { "LoadPositionProc", LoadPositionProc },
939 { "LoadNextPositionProc", LoadNextPositionProc },
940 { "LoadPrevPositionProc", LoadPrevPositionProc },
941 { "ReloadPositionProc", ReloadPositionProc },
942 { "CopyPositionProc", CopyPositionProc },
943 { "PastePositionProc", PastePositionProc },
944 { "CopyGameProc", CopyGameProc },
945 { "CopyGameListProc", CopyGameListProc },
946 { "PasteGameProc", PasteGameProc },
947 { "SaveGameProc", SaveGameProc },
948 { "SavePositionProc", SavePositionProc },
949 { "MailMoveProc", MailMoveProc },
950 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
951 { "QuitProc", QuitProc },
952 { "MachineWhiteProc", MachineWhiteProc },
953 { "MachineBlackProc", MachineBlackProc },
954 { "AnalysisModeProc", AnalyzeModeProc },
955 { "AnalyzeFileProc", AnalyzeFileProc },
956 { "TwoMachinesProc", TwoMachinesProc },
957 { "IcsClientProc", IcsClientProc },
958 { "EditGameProc", EditGameProc },
959 { "EditPositionProc", EditPositionProc },
960 { "TrainingProc", EditPositionProc },
961 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
962 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
963 { "ShowGameListProc", ShowGameListProc },
964 { "ShowMoveListProc", HistoryShowProc},
965 { "EditTagsProc", EditTagsProc },
966 { "EditBookProc", EditBookProc },
967 { "EditCommentProc", EditCommentProc },
968 { "IcsInputBoxProc", IcsInputBoxProc },
969 { "PauseProc", PauseProc },
970 { "AcceptProc", AcceptProc },
971 { "DeclineProc", DeclineProc },
972 { "RematchProc", RematchProc },
973 { "CallFlagProc", CallFlagProc },
974 { "DrawProc", DrawProc },
975 { "AdjournProc", AdjournProc },
976 { "AbortProc", AbortProc },
977 { "ResignProc", ResignProc },
978 { "AdjuWhiteProc", AdjuWhiteProc },
979 { "AdjuBlackProc", AdjuBlackProc },
980 { "AdjuDrawProc", AdjuDrawProc },
981 { "TypeInProc", TypeInProc },
982 { "EnterKeyProc", EnterKeyProc },
983 { "UpKeyProc", UpKeyProc },
984 { "DownKeyProc", DownKeyProc },
985 { "StopObservingProc", StopObservingProc },
986 { "StopExaminingProc", StopExaminingProc },
987 { "UploadProc", UploadProc },
988 { "BackwardProc", BackwardProc },
989 { "ForwardProc", ForwardProc },
990 { "TempBackwardProc", TempBackwardProc },
991 { "TempForwardProc", TempForwardProc },
992 { "ToStartProc", ToStartProc },
993 { "ToEndProc", ToEndProc },
994 { "RevertProc", RevertProc },
995 { "AnnotateProc", AnnotateProc },
996 { "TruncateGameProc", TruncateGameProc },
997 { "MoveNowProc", MoveNowProc },
998 { "RetractMoveProc", RetractMoveProc },
999 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
1000 { "UciMenuProc", (XtActionProc) UciMenuProc },
1001 { "TimeControlProc", (XtActionProc) TimeControlProc },
1002 { "FlipViewProc", FlipViewProc },
1003 { "PonderNextMoveProc", PonderNextMoveProc },
1004 #ifndef OPTIONSDIALOG
1005 { "AlwaysQueenProc", AlwaysQueenProc },
1006 { "AnimateDraggingProc", AnimateDraggingProc },
1007 { "AnimateMovingProc", AnimateMovingProc },
1008 { "AutoflagProc", AutoflagProc },
1009 { "AutoflipProc", AutoflipProc },
1010 { "BlindfoldProc", BlindfoldProc },
1011 { "FlashMovesProc", FlashMovesProc },
1013 { "HighlightDraggingProc", HighlightDraggingProc },
1015 { "HighlightLastMoveProc", HighlightLastMoveProc },
1016 // { "IcsAlarmProc", IcsAlarmProc },
1017 { "MoveSoundProc", MoveSoundProc },
1018 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
1019 { "PopupExitMessageProc", PopupExitMessageProc },
1020 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
1021 // { "PremoveProc", PremoveProc },
1022 { "ShowCoordsProc", ShowCoordsProc },
1023 { "ShowThinkingProc", ShowThinkingProc },
1024 { "HideThinkingProc", HideThinkingProc },
1025 { "TestLegalityProc", TestLegalityProc },
1027 { "SaveSettingsProc", SaveSettingsProc },
1028 { "SaveOnExitProc", SaveOnExitProc },
1029 { "InfoProc", InfoProc },
1030 { "ManProc", ManProc },
1031 { "HintProc", HintProc },
1032 { "BookProc", BookProc },
1033 { "AboutGameProc", AboutGameProc },
1034 { "AboutProc", AboutProc },
1035 { "DebugProc", DebugProc },
1036 { "NothingProc", NothingProc },
1037 { "CommentClick", (XtActionProc) CommentClick },
1038 { "CommentPopDown", (XtActionProc) CommentPopDown },
1039 { "TagsPopDown", (XtActionProc) TagsPopDown },
1040 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
1041 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
1042 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
1043 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
1044 { "GameListPopDown", (XtActionProc) GameListPopDown },
1045 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
1046 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1047 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1048 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1049 { "GenericPopDown", (XtActionProc) GenericPopDown },
1050 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1051 { "SelectMove", (XtActionProc) SelectMove },
1054 char globalTranslations[] =
1055 ":<Key>F9: ResignProc() \n \
1056 :Ctrl<Key>n: ResetProc() \n \
1057 :Meta<Key>V: NewVariantProc() \n \
1058 :Ctrl<Key>o: LoadGameProc() \n \
1059 :Meta<Key>Next: LoadNextGameProc() \n \
1060 :Meta<Key>Prior: LoadPrevGameProc() \n \
1061 :Ctrl<Key>Down: LoadSelectedProc(3) \n \
1062 :Ctrl<Key>Up: LoadSelectedProc(-3) \n \
1063 :Ctrl<Key>s: SaveGameProc() \n \
1064 :Ctrl<Key>c: CopyGameProc() \n \
1065 :Ctrl<Key>v: PasteGameProc() \n \
1066 :Ctrl<Key>O: LoadPositionProc() \n \
1067 :Shift<Key>Next: LoadNextPositionProc() \n \
1068 :Shift<Key>Prior: LoadPrevPositionProc() \n \
1069 :Ctrl<Key>S: SavePositionProc() \n \
1070 :Ctrl<Key>C: CopyPositionProc() \n \
1071 :Ctrl<Key>V: PastePositionProc() \n \
1072 :Ctrl<Key>q: QuitProc() \n \
1073 :Ctrl<Key>w: MachineWhiteProc() \n \
1074 :Ctrl<Key>b: MachineBlackProc() \n \
1075 :Ctrl<Key>t: TwoMachinesProc() \n \
1076 :Ctrl<Key>a: AnalysisModeProc() \n \
1077 :Ctrl<Key>g: AnalyzeFileProc() \n \
1078 :Ctrl<Key>e: EditGameProc() \n \
1079 :Ctrl<Key>E: EditPositionProc() \n \
1080 :Meta<Key>O: EngineOutputProc() \n \
1081 :Meta<Key>E: EvalGraphProc() \n \
1082 :Meta<Key>G: ShowGameListProc() \n \
1083 :Meta<Key>H: ShowMoveListProc() \n \
1084 :<Key>Pause: PauseProc() \n \
1085 :<Key>F3: AcceptProc() \n \
1086 :<Key>F4: DeclineProc() \n \
1087 :<Key>F12: RematchProc() \n \
1088 :<Key>F5: CallFlagProc() \n \
1089 :<Key>F6: DrawProc() \n \
1090 :<Key>F7: AdjournProc() \n \
1091 :<Key>F8: AbortProc() \n \
1092 :<Key>F10: StopObservingProc() \n \
1093 :<Key>F11: StopExaminingProc() \n \
1094 :Meta Ctrl<Key>F12: DebugProc() \n \
1095 :Meta<Key>End: ToEndProc() \n \
1096 :Meta<Key>Right: ForwardProc() \n \
1097 :Meta<Key>Home: ToStartProc() \n \
1098 :Meta<Key>Left: BackwardProc() \n \
1099 :<Key>Left: BackwardProc() \n \
1100 :<Key>Right: ForwardProc() \n \
1101 :<Key>Home: RevertProc() \n \
1102 :<Key>End: TruncateGameProc() \n \
1103 :Ctrl<Key>m: MoveNowProc() \n \
1104 :Ctrl<Key>x: RetractMoveProc() \n \
1105 :Meta<Key>J: EngineMenuProc() \n \
1106 :Meta<Key>U: UciMenuProc() \n \
1107 :Meta<Key>T: TimeControlProc() \n \
1108 :Ctrl<Key>P: PonderNextMoveProc() \n "
1109 #ifndef OPTIONSDIALOG
1111 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1112 :Ctrl<Key>F: AutoflagProc() \n \
1113 :Ctrl<Key>A: AnimateMovingProc() \n \
1114 :Ctrl<Key>L: TestLegalityProc() \n \
1115 :Ctrl<Key>H: HideThinkingProc() \n "
1118 :<Key>F1: ManProc() \n \
1119 :<Key>F2: FlipViewProc() \n \
1120 :<KeyDown>Return: TempBackwardProc() \n \
1121 :<KeyUp>Return: TempForwardProc() \n";
1123 char boardTranslations[] =
1124 "<Btn1Down>: HandleUserMove(0) \n \
1125 Shift<Btn1Up>: HandleUserMove(1) \n \
1126 <Btn1Up>: HandleUserMove(0) \n \
1127 <Btn1Motion>: AnimateUserMove() \n \
1128 <Btn3Motion>: HandlePV() \n \
1129 <Btn2Motion>: HandlePV() \n \
1130 <Btn3Up>: PieceMenuPopup(menuB) \n \
1131 <Btn2Up>: PieceMenuPopup(menuB) \n \
1132 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1133 PieceMenuPopup(menuB) \n \
1134 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1135 PieceMenuPopup(menuW) \n \
1136 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1137 PieceMenuPopup(menuW) \n \
1138 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1139 PieceMenuPopup(menuB) \n";
1141 char whiteTranslations[] =
1142 "Shift<BtnDown>: WhiteClock(1)\n \
1143 <BtnDown>: WhiteClock(0)\n";
1144 char blackTranslations[] =
1145 "Shift<BtnDown>: BlackClock(1)\n \
1146 <BtnDown>: BlackClock(0)\n";
1148 char ICSInputTranslations[] =
1149 "<Key>Up: UpKeyProc() \n "
1150 "<Key>Down: DownKeyProc() \n "
1151 "<Key>Return: EnterKeyProc() \n";
1153 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1154 // as the widget is destroyed before the up-click can call extend-end
1155 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1157 String xboardResources[] = {
1158 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1159 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1160 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1165 /* Max possible square size */
1166 #define MAXSQSIZE 256
1168 static int xpm_avail[MAXSQSIZE];
1170 #ifdef HAVE_DIR_STRUCT
1172 /* Extract piece size from filename */
1174 xpm_getsize (char *name, int len, char *ext)
1182 if ((p=strchr(name, '.')) == NULL ||
1183 StrCaseCmp(p+1, ext) != 0)
1189 while (*p && isdigit(*p))
1196 /* Setup xpm_avail */
1198 xpm_getavail (char *dirname, char *ext)
1204 for (i=0; i<MAXSQSIZE; ++i)
1207 if (appData.debugMode)
1208 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1210 dir = opendir(dirname);
1213 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1214 programName, dirname);
1218 while ((ent=readdir(dir)) != NULL) {
1219 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1220 if (i > 0 && i < MAXSQSIZE)
1230 xpm_print_avail (FILE *fp, char *ext)
1234 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1235 for (i=1; i<MAXSQSIZE; ++i) {
1241 /* Return XPM piecesize closest to size */
1243 xpm_closest_to (char *dirname, int size, char *ext)
1246 int sm_diff = MAXSQSIZE;
1250 xpm_getavail(dirname, ext);
1252 if (appData.debugMode)
1253 xpm_print_avail(stderr, ext);
1255 for (i=1; i<MAXSQSIZE; ++i) {
1258 diff = (diff<0) ? -diff : diff;
1259 if (diff < sm_diff) {
1267 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1273 #else /* !HAVE_DIR_STRUCT */
1274 /* If we are on a system without a DIR struct, we can't
1275 read the directory, so we can't collect a list of
1276 filenames, etc., so we can't do any size-fitting. */
1278 xpm_closest_to (char *dirname, int size, char *ext)
1280 fprintf(stderr, _("\
1281 Warning: No DIR structure found on this system --\n\
1282 Unable to autosize for XPM/XIM pieces.\n\
1283 Please report this error to %s.\n\
1284 Include system type & operating system in message.\n"), PACKAGE_BUGREPORT););
1287 #endif /* HAVE_DIR_STRUCT */
1289 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1290 "magenta", "cyan", "white" };
1294 TextColors textColors[(int)NColorClasses];
1296 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1298 parse_color (char *str, int which)
1300 char *p, buf[100], *d;
1303 if (strlen(str) > 99) /* watch bounds on buf */
1308 for (i=0; i<which; ++i) {
1315 /* Could be looking at something like:
1317 .. in which case we want to stop on a comma also */
1318 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1322 return -1; /* Use default for empty field */
1325 if (which == 2 || isdigit(*p))
1328 while (*p && isalpha(*p))
1333 for (i=0; i<8; ++i) {
1334 if (!StrCaseCmp(buf, cnames[i]))
1335 return which? (i+40) : (i+30);
1337 if (!StrCaseCmp(buf, "default")) return -1;
1339 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1344 parse_cpair (ColorClass cc, char *str)
1346 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1347 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1352 /* bg and attr are optional */
1353 textColors[(int)cc].bg = parse_color(str, 1);
1354 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1355 textColors[(int)cc].attr = 0;
1361 /* Arrange to catch delete-window events */
1362 Atom wm_delete_window;
1364 CatchDeleteWindow (Widget w, String procname)
1367 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1368 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1369 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1376 XtSetArg(args[0], XtNiconic, False);
1377 XtSetValues(shellWidget, args, 1);
1379 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1382 //---------------------------------------------------------------------------------------------------------
1383 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1386 #define CW_USEDEFAULT (1<<31)
1387 #define ICS_TEXT_MENU_SIZE 90
1388 #define DEBUG_FILE "xboard.debug"
1389 #define SetCurrentDirectory chdir
1390 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1394 // these two must some day move to frontend.h, when they are implemented
1395 Boolean GameListIsUp();
1397 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1400 // front-end part of option handling
1402 // [HGM] This platform-dependent table provides the location for storing the color info
1403 extern char *crWhite, * crBlack;
1407 &appData.whitePieceColor,
1408 &appData.blackPieceColor,
1409 &appData.lightSquareColor,
1410 &appData.darkSquareColor,
1411 &appData.highlightSquareColor,
1412 &appData.premoveHighlightColor,
1413 &appData.lowTimeWarningColor,
1424 // [HGM] font: keep a font for each square size, even non-stndard ones
1425 #define NUM_SIZES 18
1426 #define MAX_SIZE 130
1427 Boolean fontIsSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1428 char *fontTable[NUM_FONTS][MAX_SIZE];
1431 ParseFont (char *name, int number)
1432 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1434 if(sscanf(name, "size%d:", &size)) {
1435 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1436 // defer processing it until we know if it matches our board size
1437 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1438 fontTable[number][size] = strdup(strchr(name, ':')+1);
1439 fontValid[number][size] = True;
1444 case 0: // CLOCK_FONT
1445 appData.clockFont = strdup(name);
1447 case 1: // MESSAGE_FONT
1448 appData.font = strdup(name);
1450 case 2: // COORD_FONT
1451 appData.coordFont = strdup(name);
1456 fontIsSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1461 { // only 2 fonts currently
1462 appData.clockFont = CLOCK_FONT_NAME;
1463 appData.coordFont = COORD_FONT_NAME;
1464 appData.font = DEFAULT_FONT_NAME;
1469 { // no-op, until we identify the code for this already in XBoard and move it here
1473 ParseColor (int n, char *name)
1474 { // in XBoard, just copy the color-name string
1475 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1479 ParseTextAttribs (ColorClass cc, char *s)
1481 (&appData.colorShout)[cc] = strdup(s);
1485 ParseBoardSize (void *addr, char *name)
1487 appData.boardSize = strdup(name);
1492 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1496 SetCommPortDefaults ()
1497 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1500 // [HGM] args: these three cases taken out to stay in front-end
1502 SaveFontArg (FILE *f, ArgDescriptor *ad)
1505 int i, n = (int)(intptr_t)ad->argLoc;
1507 case 0: // CLOCK_FONT
1508 name = appData.clockFont;
1510 case 1: // MESSAGE_FONT
1511 name = appData.font;
1513 case 2: // COORD_FONT
1514 name = appData.coordFont;
1519 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1520 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1521 fontTable[n][squareSize] = strdup(name);
1522 fontValid[n][squareSize] = True;
1525 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1526 fprintf(f, OPTCHAR "%s" SEPCHAR "\"size%d:%s\"\n", ad->argName, i, fontTable[n][i]);
1531 { // nothing to do, as the sounds are at all times represented by their text-string names already
1535 SaveAttribsArg (FILE *f, ArgDescriptor *ad)
1536 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1537 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
1541 SaveColor (FILE *f, ArgDescriptor *ad)
1542 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1543 if(colorVariable[(int)(intptr_t)ad->argLoc])
1544 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
1548 SaveBoardSize (FILE *f, char *name, void *addr)
1549 { // wrapper to shield back-end from BoardSize & sizeInfo
1550 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1554 ParseCommPortSettings (char *s)
1555 { // no such option in XBoard (yet)
1558 extern Widget engineOutputShell;
1562 GetActualPlacement (Widget wg, WindowPlacement *wp)
1567 XWindowAttributes winAt;
1574 XGetWindowAttributes(xDisplay, win, &winAt); // this works, where XtGetValues on XtNx, XtNy does not!
1575 XTranslateCoordinates (xDisplay, win, winAt.root, -winAt.border_width, -winAt.border_width, &rx, &ry, &dummy);
1576 wp->x = rx - winAt.x;
1577 wp->y = ry - winAt.y;
1578 wp->height = winAt.height;
1579 wp->width = winAt.width;
1580 frameX = winAt.x; frameY = winAt.y; // remember to decide if windows touch
1585 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1586 // In XBoard this will have to wait until awareness of window parameters is implemented
1587 GetActualPlacement(shellWidget, &wpMain);
1588 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput);
1589 if(MoveHistoryIsUp()) GetActualPlacement(shells[7], &wpMoveHistory);
1590 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1591 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1592 if(shellUp[1]) GetActualPlacement(shells[1], &wpComment);
1593 if(shellUp[2]) GetActualPlacement(shells[2], &wpTags);
1597 PrintCommPortSettings (FILE *f, char *name)
1598 { // This option does not exist in XBoard
1602 MySearchPath (char *installDir, char *name, char *fullname)
1603 { // just append installDir and name. Perhaps ExpandPath should be used here?
1604 name = ExpandPathName(name);
1605 if(name && name[0] == '/')
1606 safeStrCpy(fullname, name, MSG_SIZ );
1608 sprintf(fullname, "%s%c%s", installDir, '/', name);
1614 MyGetFullPathName (char *name, char *fullname)
1615 { // should use ExpandPath?
1616 name = ExpandPathName(name);
1617 safeStrCpy(fullname, name, MSG_SIZ );
1622 EnsureOnScreen (int *x, int *y, int minX, int minY)
1629 { // [HGM] args: allows testing if main window is realized from back-end
1630 return xBoardWindow != 0;
1634 PopUpStartupDialog ()
1635 { // start menu not implemented in XBoard
1639 ConvertToLine (int argc, char **argv)
1641 static char line[128*1024], buf[1024];
1645 for(i=1; i<argc; i++)
1647 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') || argv[i][0] == NULLCHAR)
1648 && argv[i][0] != '{' )
1649 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1651 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1652 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1655 line[strlen(line)-1] = NULLCHAR;
1659 //--------------------------------------------------------------------------------------------
1661 extern Boolean twoBoards, partnerUp;
1664 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1666 #define BoardSize int
1668 InitDrawingSizes (BoardSize boardSize, int flags)
1669 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1670 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1672 XtGeometryResult gres;
1674 static Dimension oldWidth, oldHeight;
1675 static VariantClass oldVariant;
1676 static int oldDual = -1, oldMono = -1;
1678 if(!formWidget) return;
1680 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1681 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1682 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1684 if(boardWidth != oldWidth || boardHeight != oldHeight || oldDual != twoBoards) { // do resizing stuff only if size actually changed
1686 * Enable shell resizing.
1688 shellArgs[0].value = (XtArgVal) &w;
1689 shellArgs[1].value = (XtArgVal) &h;
1690 XtGetValues(shellWidget, shellArgs, 2);
1692 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1693 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1694 XtSetValues(shellWidget, &shellArgs[2], 4);
1696 XtSetArg(args[0], XtNdefaultDistance, &sep);
1697 XtGetValues(formWidget, args, 1);
1699 oldWidth = boardWidth; oldHeight = boardHeight; oldDual = twoBoards;
1701 hOffset = boardWidth + 10;
1702 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1703 secondSegments[i] = gridSegments[i];
1704 secondSegments[i].x1 += hOffset;
1705 secondSegments[i].x2 += hOffset;
1708 XtSetArg(args[0], XtNwidth, boardWidth);
1709 XtSetArg(args[1], XtNheight, boardHeight);
1710 XtSetValues(boardWidget, args, 2);
1712 timerWidth = (boardWidth - sep) / 2;
1713 XtSetArg(args[0], XtNwidth, timerWidth);
1714 XtSetValues(whiteTimerWidget, args, 1);
1715 XtSetValues(blackTimerWidget, args, 1);
1717 XawFormDoLayout(formWidget, False);
1719 if (appData.titleInWindow) {
1721 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1722 XtSetArg(args[i], XtNheight, &h); i++;
1723 XtGetValues(titleWidget, args, i);
1725 w = boardWidth - 2*bor;
1727 XtSetArg(args[0], XtNwidth, &w);
1728 XtGetValues(menuBarWidget, args, 1);
1729 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1732 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1733 if (gres != XtGeometryYes && appData.debugMode) {
1735 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1736 programName, gres, w, h, wr, hr);
1740 XawFormDoLayout(formWidget, True);
1743 * Inhibit shell resizing.
1745 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1746 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1747 shellArgs[4].value = shellArgs[2].value = w;
1748 shellArgs[5].value = shellArgs[3].value = h;
1749 XtSetValues(shellWidget, &shellArgs[0], 6);
1751 XSync(xDisplay, False);
1755 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1758 if(gameInfo.variant != oldVariant) { // and only if variant changed
1761 for(i=0; i<4; i++) {
1763 for(p=0; p<=(int)WhiteKing; p++)
1764 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1765 if(gameInfo.variant == VariantShogi) {
1766 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1767 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1768 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1769 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1770 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1773 if(gameInfo.variant == VariantGothic) {
1774 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1777 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1778 xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
1779 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1782 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1783 for(p=0; p<=(int)WhiteKing; p++)
1784 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1785 if(gameInfo.variant == VariantShogi) {
1786 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1787 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1788 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1789 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1790 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1793 if(gameInfo.variant == VariantGothic) {
1794 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1797 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1798 ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
1799 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1804 for(i=0; i<2; i++) {
1806 for(p=0; p<=(int)WhiteKing; p++)
1807 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1808 if(gameInfo.variant == VariantShogi) {
1809 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1810 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1811 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1812 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1813 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1816 if(gameInfo.variant == VariantGothic) {
1817 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1820 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1821 pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
1822 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1826 oldMono = -10; // kludge to force recreation of animation masks
1827 oldVariant = gameInfo.variant;
1830 if(appData.monoMode != oldMono)
1833 oldMono = appData.monoMode;
1838 ParseIcsTextColors ()
1839 { // [HGM] tken out of main(), so it can be called from ICS-Options dialog
1840 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1841 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1842 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1843 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1844 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1845 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1846 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1847 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1848 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1849 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1851 if (appData.colorize) {
1853 _("%s: can't parse color names; disabling colorization\n"),
1856 appData.colorize = FALSE;
1862 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
1863 XrmValue vFrom, vTo;
1864 int forceMono = False;
1866 if (!appData.monoMode) {
1867 vFrom.addr = (caddr_t) appData.lightSquareColor;
1868 vFrom.size = strlen(appData.lightSquareColor);
1869 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1870 if (vTo.addr == NULL) {
1871 appData.monoMode = True;
1874 lightSquareColor = *(Pixel *) vTo.addr;
1877 if (!appData.monoMode) {
1878 vFrom.addr = (caddr_t) appData.darkSquareColor;
1879 vFrom.size = strlen(appData.darkSquareColor);
1880 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1881 if (vTo.addr == NULL) {
1882 appData.monoMode = True;
1885 darkSquareColor = *(Pixel *) vTo.addr;
1888 if (!appData.monoMode) {
1889 vFrom.addr = (caddr_t) appData.whitePieceColor;
1890 vFrom.size = strlen(appData.whitePieceColor);
1891 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1892 if (vTo.addr == NULL) {
1893 appData.monoMode = True;
1896 whitePieceColor = *(Pixel *) vTo.addr;
1899 if (!appData.monoMode) {
1900 vFrom.addr = (caddr_t) appData.blackPieceColor;
1901 vFrom.size = strlen(appData.blackPieceColor);
1902 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1903 if (vTo.addr == NULL) {
1904 appData.monoMode = True;
1907 blackPieceColor = *(Pixel *) vTo.addr;
1911 if (!appData.monoMode) {
1912 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1913 vFrom.size = strlen(appData.highlightSquareColor);
1914 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1915 if (vTo.addr == NULL) {
1916 appData.monoMode = True;
1919 highlightSquareColor = *(Pixel *) vTo.addr;
1923 if (!appData.monoMode) {
1924 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1925 vFrom.size = strlen(appData.premoveHighlightColor);
1926 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1927 if (vTo.addr == NULL) {
1928 appData.monoMode = True;
1931 premoveHighlightColor = *(Pixel *) vTo.addr;
1939 { // [HGM] taken out of main
1941 if (appData.monoMode && // [HGM] no sense to go on to certain doom
1942 (appData.bitmapDirectory == NULL || appData.bitmapDirectory[0] == NULLCHAR))
1943 appData.bitmapDirectory = strdup(DEF_BITMAP_DIR);
1945 if (appData.bitmapDirectory[0] != NULLCHAR) {
1949 CreateXPMBoard(appData.liteBackTextureFile, 1);
1950 CreateXPMBoard(appData.darkBackTextureFile, 0);
1954 /* Create regular pieces */
1955 if (!useImages) CreatePieces();
1960 main (int argc, char **argv)
1962 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1963 XSetWindowAttributes window_attributes;
1965 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1966 XrmValue vFrom, vTo;
1967 XtGeometryResult gres;
1970 int forceMono = False;
1972 srandom(time(0)); // [HGM] book: make random truly random
1974 setbuf(stdout, NULL);
1975 setbuf(stderr, NULL);
1978 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1979 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1983 programName = strrchr(argv[0], '/');
1984 if (programName == NULL)
1985 programName = argv[0];
1990 XtSetLanguageProc(NULL, NULL, NULL);
1991 bindtextdomain(PACKAGE, LOCALEDIR);
1992 textdomain(PACKAGE);
1996 XtAppInitialize(&appContext, "XBoard", shellOptions,
1997 XtNumber(shellOptions),
1998 &argc, argv, xboardResources, NULL, 0);
1999 appData.boardSize = "";
2000 InitAppData(ConvertToLine(argc, argv));
2002 if (p == NULL) p = "/tmp";
2003 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
2004 gameCopyFilename = (char*) malloc(i);
2005 gamePasteFilename = (char*) malloc(i);
2006 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
2007 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
2009 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
2010 clientResources, XtNumber(clientResources),
2013 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
2014 static char buf[MSG_SIZ];
2015 EscapeExpand(buf, appData.firstInitString);
2016 appData.firstInitString = strdup(buf);
2017 EscapeExpand(buf, appData.secondInitString);
2018 appData.secondInitString = strdup(buf);
2019 EscapeExpand(buf, appData.firstComputerString);
2020 appData.firstComputerString = strdup(buf);
2021 EscapeExpand(buf, appData.secondComputerString);
2022 appData.secondComputerString = strdup(buf);
2025 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
2028 if (chdir(chessDir) != 0) {
2029 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
2035 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
2036 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
2037 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
2038 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
2041 setbuf(debugFP, NULL);
2045 if (appData.debugMode) {
2046 fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
2050 /* [HGM,HR] make sure board size is acceptable */
2051 if(appData.NrFiles > BOARD_FILES ||
2052 appData.NrRanks > BOARD_RANKS )
2053 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
2056 /* This feature does not work; animation needs a rewrite */
2057 appData.highlightDragging = FALSE;
2061 xDisplay = XtDisplay(shellWidget);
2062 xScreen = DefaultScreen(xDisplay);
2063 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
2065 gameInfo.variant = StringToVariant(appData.variant);
2066 InitPosition(FALSE);
2069 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
2071 if (isdigit(appData.boardSize[0])) {
2072 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
2073 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
2074 &fontPxlSize, &smallLayout, &tinyLayout);
2076 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
2077 programName, appData.boardSize);
2081 /* Find some defaults; use the nearest known size */
2082 SizeDefaults *szd, *nearest;
2083 int distance = 99999;
2084 nearest = szd = sizeDefaults;
2085 while (szd->name != NULL) {
2086 if (abs(szd->squareSize - squareSize) < distance) {
2088 distance = abs(szd->squareSize - squareSize);
2089 if (distance == 0) break;
2093 if (i < 2) lineGap = nearest->lineGap;
2094 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
2095 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
2096 if (i < 5) fontPxlSize = nearest->fontPxlSize;
2097 if (i < 6) smallLayout = nearest->smallLayout;
2098 if (i < 7) tinyLayout = nearest->tinyLayout;
2101 SizeDefaults *szd = sizeDefaults;
2102 if (*appData.boardSize == NULLCHAR) {
2103 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
2104 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
2107 if (szd->name == NULL) szd--;
2108 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
2110 while (szd->name != NULL &&
2111 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
2112 if (szd->name == NULL) {
2113 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
2114 programName, appData.boardSize);
2118 squareSize = szd->squareSize;
2119 lineGap = szd->lineGap;
2120 clockFontPxlSize = szd->clockFontPxlSize;
2121 coordFontPxlSize = szd->coordFontPxlSize;
2122 fontPxlSize = szd->fontPxlSize;
2123 smallLayout = szd->smallLayout;
2124 tinyLayout = szd->tinyLayout;
2125 // [HGM] font: use defaults from settings file if available and not overruled
2127 if(!fontIsSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
2128 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
2129 if(!fontIsSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
2130 appData.font = fontTable[MESSAGE_FONT][squareSize];
2131 if(!fontIsSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
2132 appData.coordFont = fontTable[COORD_FONT][squareSize];
2134 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
2135 if (strlen(appData.pixmapDirectory) > 0) {
2136 p = ExpandPathName(appData.pixmapDirectory);
2138 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
2139 appData.pixmapDirectory);
2142 if (appData.debugMode) {
2143 fprintf(stderr, _("\
2144 XBoard square size (hint): %d\n\
2145 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
2147 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
2148 if (appData.debugMode) {
2149 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
2152 defaultLineGap = lineGap;
2153 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
2155 /* [HR] height treated separately (hacked) */
2156 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
2157 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
2158 if (appData.showJail == 1) {
2159 /* Jail on top and bottom */
2160 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2161 XtSetArg(boardArgs[2], XtNheight,
2162 boardHeight + 2*(lineGap + squareSize));
2163 } else if (appData.showJail == 2) {
2165 XtSetArg(boardArgs[1], XtNwidth,
2166 boardWidth + 2*(lineGap + squareSize));
2167 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2170 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2171 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2175 * Determine what fonts to use.
2178 appData.font = InsertPxlSize(appData.font, fontPxlSize);
2179 appData.clockFont = InsertPxlSize(appData.clockFont, clockFontPxlSize);
2180 appData.coordFont = InsertPxlSize(appData.coordFont, coordFontPxlSize);
2181 fontSet = CreateFontSet(appData.font);
2182 clockFontSet = CreateFontSet(appData.clockFont);
2184 /* For the coordFont, use the 0th font of the fontset. */
2185 XFontSet coordFontSet = CreateFontSet(appData.coordFont);
2186 XFontStruct **font_struct_list;
2187 XFontSetExtents *fontSize;
2188 char **font_name_list;
2189 XFontsOfFontSet(coordFontSet, &font_struct_list, &font_name_list);
2190 coordFontID = XLoadFont(xDisplay, font_name_list[0]);
2191 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2192 fontSize = XExtentsOfFontSet(fontSet); // [HGM] figure out how much vertical space font takes
2193 textHeight = fontSize->max_logical_extent.height + 5; // add borderWidth
2196 appData.font = FindFont(appData.font, fontPxlSize);
2197 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2198 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2199 clockFontID = XLoadFont(xDisplay, appData.clockFont);
2200 clockFontStruct = XQueryFont(xDisplay, clockFontID);
2201 coordFontID = XLoadFont(xDisplay, appData.coordFont);
2202 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2204 countFontID = coordFontID; // [HGM] holdings
2205 countFontStruct = coordFontStruct;
2207 xdb = XtDatabase(xDisplay);
2209 XrmPutLineResource(&xdb, "*international: True");
2210 vTo.size = sizeof(XFontSet);
2211 vTo.addr = (XtPointer) &fontSet;
2212 XrmPutResource(&xdb, "*fontSet", XtRFontSet, &vTo);
2214 XrmPutStringResource(&xdb, "*font", appData.font);
2218 * Detect if there are not enough colors available and adapt.
2220 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2221 appData.monoMode = True;
2224 forceMono = MakeColors();
2227 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2229 appData.monoMode = True;
2232 if (appData.lowTimeWarning && !appData.monoMode) {
2233 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2234 vFrom.size = strlen(appData.lowTimeWarningColor);
2235 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2236 if (vTo.addr == NULL)
2237 appData.monoMode = True;
2239 lowTimeWarningColor = *(Pixel *) vTo.addr;
2242 if (appData.monoMode && appData.debugMode) {
2243 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2244 (unsigned long) XWhitePixel(xDisplay, xScreen),
2245 (unsigned long) XBlackPixel(xDisplay, xScreen));
2248 ParseIcsTextColors();
2249 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2250 textColors[ColorNone].attr = 0;
2252 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2258 layoutName = "tinyLayout";
2259 } else if (smallLayout) {
2260 layoutName = "smallLayout";
2262 layoutName = "normalLayout";
2264 /* Outer layoutWidget is there only to provide a name for use in
2265 resources that depend on the layout style */
2267 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2268 layoutArgs, XtNumber(layoutArgs));
2270 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2271 formArgs, XtNumber(formArgs));
2272 XtSetArg(args[0], XtNdefaultDistance, &sep);
2273 XtGetValues(formWidget, args, 1);
2276 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar, boardWidth);
2277 XtSetArg(args[0], XtNtop, XtChainTop);
2278 XtSetArg(args[1], XtNbottom, XtChainTop);
2279 XtSetArg(args[2], XtNright, XtChainLeft);
2280 XtSetValues(menuBarWidget, args, 3);
2282 widgetList[j++] = whiteTimerWidget =
2283 XtCreateWidget("whiteTime", labelWidgetClass,
2284 formWidget, timerArgs, XtNumber(timerArgs));
2286 XtSetArg(args[0], XtNfontSet, clockFontSet);
2288 XtSetArg(args[0], XtNfont, clockFontStruct);
2290 XtSetArg(args[1], XtNtop, XtChainTop);
2291 XtSetArg(args[2], XtNbottom, XtChainTop);
2292 XtSetValues(whiteTimerWidget, args, 3);
2294 widgetList[j++] = blackTimerWidget =
2295 XtCreateWidget("blackTime", labelWidgetClass,
2296 formWidget, timerArgs, XtNumber(timerArgs));
2298 XtSetArg(args[0], XtNfontSet, clockFontSet);
2300 XtSetArg(args[0], XtNfont, clockFontStruct);
2302 XtSetArg(args[1], XtNtop, XtChainTop);
2303 XtSetArg(args[2], XtNbottom, XtChainTop);
2304 XtSetValues(blackTimerWidget, args, 3);
2306 if (appData.titleInWindow) {
2307 widgetList[j++] = titleWidget =
2308 XtCreateWidget("title", labelWidgetClass, formWidget,
2309 titleArgs, XtNumber(titleArgs));
2310 XtSetArg(args[0], XtNtop, XtChainTop);
2311 XtSetArg(args[1], XtNbottom, XtChainTop);
2312 XtSetValues(titleWidget, args, 2);
2315 if (appData.showButtonBar) {
2316 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2317 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2318 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2319 XtSetArg(args[2], XtNtop, XtChainTop);
2320 XtSetArg(args[3], XtNbottom, XtChainTop);
2321 XtSetValues(buttonBarWidget, args, 4);
2324 widgetList[j++] = messageWidget =
2325 XtCreateWidget("message", labelWidgetClass, formWidget,
2326 messageArgs, XtNumber(messageArgs));
2327 XtSetArg(args[0], XtNtop, XtChainTop);
2328 XtSetArg(args[1], XtNbottom, XtChainTop);
2329 XtSetValues(messageWidget, args, 2);
2331 widgetList[j++] = boardWidget =
2332 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2333 XtNumber(boardArgs));
2335 XtManageChildren(widgetList, j);
2337 timerWidth = (boardWidth - sep) / 2;
2338 XtSetArg(args[0], XtNwidth, timerWidth);
2339 XtSetValues(whiteTimerWidget, args, 1);
2340 XtSetValues(blackTimerWidget, args, 1);
2342 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2343 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2344 XtGetValues(whiteTimerWidget, args, 2);
2346 if (appData.showButtonBar) {
2347 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2348 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2349 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2353 * formWidget uses these constraints but they are stored
2357 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2358 XtSetValues(menuBarWidget, args, i);
2359 if (appData.titleInWindow) {
2362 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2363 XtSetValues(whiteTimerWidget, args, i);
2365 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2366 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2367 XtSetValues(blackTimerWidget, args, i);
2369 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2370 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2371 XtSetValues(titleWidget, args, i);
2373 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2374 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2375 XtSetValues(messageWidget, args, i);
2376 if (appData.showButtonBar) {
2378 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2379 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2380 XtSetValues(buttonBarWidget, args, i);
2384 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2385 XtSetValues(whiteTimerWidget, args, i);
2387 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2388 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2389 XtSetValues(blackTimerWidget, args, i);
2391 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2392 XtSetValues(titleWidget, args, i);
2394 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2395 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2396 XtSetValues(messageWidget, args, i);
2397 if (appData.showButtonBar) {
2399 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2400 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2401 XtSetValues(buttonBarWidget, args, i);
2406 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2407 XtSetValues(whiteTimerWidget, args, i);
2409 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2410 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2411 XtSetValues(blackTimerWidget, args, i);
2413 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2414 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2415 XtSetValues(messageWidget, args, i);
2416 if (appData.showButtonBar) {
2418 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2419 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2420 XtSetValues(buttonBarWidget, args, i);
2424 XtSetArg(args[0], XtNfromVert, messageWidget);
2425 XtSetArg(args[1], XtNtop, XtChainTop);
2426 XtSetArg(args[2], XtNbottom, XtChainBottom);
2427 XtSetArg(args[3], XtNleft, XtChainLeft);
2428 XtSetArg(args[4], XtNright, XtChainRight);
2429 XtSetValues(boardWidget, args, 5);
2431 XtRealizeWidget(shellWidget);
2434 XtSetArg(args[0], XtNx, wpMain.x);
2435 XtSetArg(args[1], XtNy, wpMain.y);
2436 XtSetValues(shellWidget, args, 2);
2440 * Correct the width of the message and title widgets.
2441 * It is not known why some systems need the extra fudge term.
2442 * The value "2" is probably larger than needed.
2444 XawFormDoLayout(formWidget, False);
2446 #define WIDTH_FUDGE 2
2448 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2449 XtSetArg(args[i], XtNheight, &h); i++;
2450 XtGetValues(messageWidget, args, i);
2451 if (appData.showButtonBar) {
2453 XtSetArg(args[i], XtNwidth, &w); i++;
2454 XtGetValues(buttonBarWidget, args, i);
2455 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2457 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2460 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2461 if (gres != XtGeometryYes && appData.debugMode) {
2462 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2463 programName, gres, w, h, wr, hr);
2466 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2467 /* The size used for the child widget in layout lags one resize behind
2468 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2470 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2471 if (gres != XtGeometryYes && appData.debugMode) {
2472 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2473 programName, gres, w, h, wr, hr);
2476 if(!textHeight) textHeight = hr; // [HGM] if !NLS textHeight is still undefined, and we grab it from here
2477 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2478 XtSetArg(args[1], XtNright, XtChainRight);
2479 XtSetValues(messageWidget, args, 2);
2481 if (appData.titleInWindow) {
2483 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2484 XtSetArg(args[i], XtNheight, &h); i++;
2485 XtGetValues(titleWidget, args, i);
2487 w = boardWidth - 2*bor;
2489 XtSetArg(args[0], XtNwidth, &w);
2490 XtGetValues(menuBarWidget, args, 1);
2491 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2494 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2495 if (gres != XtGeometryYes && appData.debugMode) {
2497 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2498 programName, gres, w, h, wr, hr);
2501 XawFormDoLayout(formWidget, True);
2503 xBoardWindow = XtWindow(boardWidget);
2505 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2506 // not need to go into InitDrawingSizes().
2510 * Create X checkmark bitmap and initialize option menu checks.
2512 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2513 checkmark_bits, checkmark_width, checkmark_height);
2514 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2515 #ifndef OPTIONSDIALOG
2516 if (appData.alwaysPromoteToQueen) {
2517 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2520 if (appData.animateDragging) {
2521 XtSetValues(XtNameToWidget(menuBarWidget,
2522 "menuOptions.Animate Dragging"),
2525 if (appData.animate) {
2526 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2529 if (appData.autoCallFlag) {
2530 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2533 if (appData.autoFlipView) {
2534 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2537 if (appData.blindfold) {
2538 XtSetValues(XtNameToWidget(menuBarWidget,
2539 "menuOptions.Blindfold"), args, 1);
2541 if (appData.flashCount > 0) {
2542 XtSetValues(XtNameToWidget(menuBarWidget,
2543 "menuOptions.Flash Moves"),
2547 if (appData.highlightDragging) {
2548 XtSetValues(XtNameToWidget(menuBarWidget,
2549 "menuOptions.Highlight Dragging"),
2553 if (appData.highlightLastMove) {
2554 XtSetValues(XtNameToWidget(menuBarWidget,
2555 "menuOptions.Highlight Last Move"),
2558 if (appData.highlightMoveWithArrow) {
2559 XtSetValues(XtNameToWidget(menuBarWidget,
2560 "menuOptions.Arrow"),
2563 // if (appData.icsAlarm) {
2564 // XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2567 if (appData.ringBellAfterMoves) {
2568 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2571 if (appData.oneClick) {
2572 XtSetValues(XtNameToWidget(menuBarWidget,
2573 "menuOptions.OneClick"), args, 1);
2575 if (appData.periodicUpdates) {
2576 XtSetValues(XtNameToWidget(menuBarWidget,
2577 "menuOptions.Periodic Updates"), args, 1);
2579 if (appData.ponderNextMove) {
2580 XtSetValues(XtNameToWidget(menuBarWidget,
2581 "menuOptions.Ponder Next Move"), args, 1);
2583 if (appData.popupExitMessage) {
2584 XtSetValues(XtNameToWidget(menuBarWidget,
2585 "menuOptions.Popup Exit Message"), args, 1);
2587 if (appData.popupMoveErrors) {
2588 XtSetValues(XtNameToWidget(menuBarWidget,
2589 "menuOptions.Popup Move Errors"), args, 1);
2591 // if (appData.premove) {
2592 // XtSetValues(XtNameToWidget(menuBarWidget,
2593 // "menuOptions.Premove"), args, 1);
2595 if (appData.showCoords) {
2596 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2599 if (appData.hideThinkingFromHuman) {
2600 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2603 if (appData.testLegality) {
2604 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2608 if (saveSettingsOnExit) {
2609 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2616 ReadBitmap(&wIconPixmap, "icon_white.bm",
2617 icon_white_bits, icon_white_width, icon_white_height);
2618 ReadBitmap(&bIconPixmap, "icon_black.bm",
2619 icon_black_bits, icon_black_width, icon_black_height);
2620 iconPixmap = wIconPixmap;
2622 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2623 XtSetValues(shellWidget, args, i);
2626 * Create a cursor for the board widget.
2628 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2629 XChangeWindowAttributes(xDisplay, xBoardWindow,
2630 CWCursor, &window_attributes);
2633 * Inhibit shell resizing.
2635 shellArgs[0].value = (XtArgVal) &w;
2636 shellArgs[1].value = (XtArgVal) &h;
2637 XtGetValues(shellWidget, shellArgs, 2);
2638 shellArgs[4].value = shellArgs[2].value = w;
2639 shellArgs[5].value = shellArgs[3].value = h;
2640 XtSetValues(shellWidget, &shellArgs[2], 4);
2641 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2642 marginH = h - boardHeight;
2644 CatchDeleteWindow(shellWidget, "QuitProc");
2652 if (appData.animate || appData.animateDragging)
2655 XtAugmentTranslations(formWidget,
2656 XtParseTranslationTable(globalTranslations));
2657 XtAugmentTranslations(boardWidget,
2658 XtParseTranslationTable(boardTranslations));
2659 XtAugmentTranslations(whiteTimerWidget,
2660 XtParseTranslationTable(whiteTranslations));
2661 XtAugmentTranslations(blackTimerWidget,
2662 XtParseTranslationTable(blackTranslations));
2664 /* Why is the following needed on some versions of X instead
2665 * of a translation? */
2666 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2667 (XtEventHandler) EventProc, NULL);
2669 XtAddEventHandler(formWidget, KeyPressMask, False,
2670 (XtEventHandler) MoveTypeInProc, NULL);
2671 XtAddEventHandler(shellWidget, StructureNotifyMask, False,
2672 (XtEventHandler) EventProc, NULL);
2674 /* [AS] Restore layout */
2675 if( wpMoveHistory.visible ) {
2679 if( wpEvalGraph.visible )
2684 if( wpEngineOutput.visible ) {
2685 EngineOutputPopUp();
2690 if (errorExitStatus == -1) {
2691 if (appData.icsActive) {
2692 /* We now wait until we see "login:" from the ICS before
2693 sending the logon script (problems with timestamp otherwise) */
2694 /*ICSInitScript();*/
2695 if (appData.icsInputBox) ICSInputBoxPopUp();
2699 signal(SIGWINCH, TermSizeSigHandler);
2701 signal(SIGINT, IntSigHandler);
2702 signal(SIGTERM, IntSigHandler);
2703 if (*appData.cmailGameName != NULLCHAR) {
2704 signal(SIGUSR1, CmailSigHandler);
2707 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2709 // XtSetKeyboardFocus(shellWidget, formWidget);
2710 XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
2712 XtAppMainLoop(appContext);
2713 if (appData.debugMode) fclose(debugFP); // [DM] debug
2717 static Boolean noEcho;
2722 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2723 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2725 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2726 unlink(gameCopyFilename);
2727 unlink(gamePasteFilename);
2728 if(noEcho) EchoOn();
2732 TermSizeSigHandler (int sig)
2738 IntSigHandler (int sig)
2744 CmailSigHandler (int sig)
2749 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2751 /* Activate call-back function CmailSigHandlerCallBack() */
2752 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2754 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2758 CmailSigHandlerCallBack (InputSourceRef isr, VOIDSTAR closure, char *message, int count, int error)
2761 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2763 /**** end signal code ****/
2769 /* try to open the icsLogon script, either in the location given
2770 * or in the users HOME directory
2777 f = fopen(appData.icsLogon, "r");
2780 homedir = getenv("HOME");
2781 if (homedir != NULL)
2783 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2784 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2785 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2786 f = fopen(buf, "r");
2791 ProcessICSInitScript(f);
2793 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2812 GreyRevert (Boolean grey)
2815 if (!menuBarWidget) return;
2816 w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2818 DisplayError("menuEdit.Revert", 0);
2820 XtSetSensitive(w, !grey);
2822 w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2824 DisplayError("menuEdit.Annotate", 0);
2826 XtSetSensitive(w, !grey);
2831 SetMenuEnables (Enables *enab)
2834 if (!menuBarWidget) return;
2835 while (enab->name != NULL) {
2836 w = XtNameToWidget(menuBarWidget, enab->name);
2838 DisplayError(enab->name, 0);
2840 XtSetSensitive(w, enab->value);
2846 Enables icsEnables[] = {
2847 { "menuFile.Mail Move", False },
2848 { "menuFile.Reload CMail Message", False },
2849 { "menuMode.Machine Black", False },
2850 { "menuMode.Machine White", False },
2851 { "menuMode.Analysis Mode", False },
2852 { "menuMode.Analyze File", False },
2853 { "menuMode.Two Machines", False },
2854 { "menuMode.Machine Match", False },
2856 { "menuEngine.Hint", False },
2857 { "menuEngine.Book", False },
2858 { "menuEngine.Move Now", False },
2859 #ifndef OPTIONSDIALOG
2860 { "menuOptions.Periodic Updates", False },
2861 { "menuOptions.Hide Thinking", False },
2862 { "menuOptions.Ponder Next Move", False },
2865 { "menuEngine.Engine #1 Settings", False },
2866 { "menuEngine.Engine #2 Settings", False },
2867 { "menuEngine.Load Engine", False },
2868 { "menuEdit.Annotate", False },
2869 { "menuOptions.Match", False },
2873 Enables ncpEnables[] = {
2874 { "menuFile.Mail Move", False },
2875 { "menuFile.Reload CMail Message", False },
2876 { "menuMode.Machine White", False },
2877 { "menuMode.Machine Black", False },
2878 { "menuMode.Analysis Mode", False },
2879 { "menuMode.Analyze File", False },
2880 { "menuMode.Two Machines", False },
2881 { "menuMode.Machine Match", False },
2882 { "menuMode.ICS Client", False },
2883 { "menuView.ICStex", False },
2884 { "menuView.ICS Input Box", False },
2885 { "Action", False },
2886 { "menuEdit.Revert", False },
2887 { "menuEdit.Annotate", False },
2888 { "menuEngine.Engine #1 Settings", False },
2889 { "menuEngine.Engine #2 Settings", False },
2890 { "menuEngine.Move Now", False },
2891 { "menuEngine.Retract Move", False },
2892 { "menuOptions.ICS", False },
2893 #ifndef OPTIONSDIALOG
2894 { "menuOptions.Auto Flag", False },
2895 { "menuOptions.Auto Flip View", False },
2896 // { "menuOptions.ICS Alarm", False },
2897 { "menuOptions.Move Sound", False },
2898 { "menuOptions.Hide Thinking", False },
2899 { "menuOptions.Periodic Updates", False },
2900 { "menuOptions.Ponder Next Move", False },
2902 { "menuEngine.Hint", False },
2903 { "menuEngine.Book", False },
2907 Enables gnuEnables[] = {
2908 { "menuMode.ICS Client", False },
2909 { "menuView.ICStex", False },
2910 { "menuView.ICS Input Box", False },
2911 { "menuAction.Accept", False },
2912 { "menuAction.Decline", False },
2913 { "menuAction.Rematch", False },
2914 { "menuAction.Adjourn", False },
2915 { "menuAction.Stop Examining", False },
2916 { "menuAction.Stop Observing", False },
2917 { "menuAction.Upload to Examine", False },
2918 { "menuEdit.Revert", False },
2919 { "menuEdit.Annotate", False },
2920 { "menuOptions.ICS", False },
2922 /* The next two options rely on SetCmailMode being called *after* */
2923 /* SetGNUMode so that when GNU is being used to give hints these */
2924 /* menu options are still available */
2926 { "menuFile.Mail Move", False },
2927 { "menuFile.Reload CMail Message", False },
2928 // [HGM] The following have been added to make a switch from ncp to GNU mode possible
2929 { "menuMode.Machine White", True },
2930 { "menuMode.Machine Black", True },
2931 { "menuMode.Analysis Mode", True },
2932 { "menuMode.Analyze File", True },
2933 { "menuMode.Two Machines", True },
2934 { "menuMode.Machine Match", True },
2935 { "menuEngine.Engine #1 Settings", True },
2936 { "menuEngine.Engine #2 Settings", True },
2937 { "menuEngine.Hint", True },
2938 { "menuEngine.Book", True },
2939 { "menuEngine.Move Now", True },
2940 { "menuEngine.Retract Move", True },
2945 Enables cmailEnables[] = {
2947 { "menuAction.Call Flag", False },
2948 { "menuAction.Draw", True },
2949 { "menuAction.Adjourn", False },
2950 { "menuAction.Abort", False },
2951 { "menuAction.Stop Observing", False },
2952 { "menuAction.Stop Examining", False },
2953 { "menuFile.Mail Move", True },
2954 { "menuFile.Reload CMail Message", True },
2958 Enables trainingOnEnables[] = {
2959 { "menuMode.Edit Comment", False },
2960 { "menuMode.Pause", False },
2961 { "menuEdit.Forward", False },
2962 { "menuEdit.Backward", False },
2963 { "menuEdit.Forward to End", False },
2964 { "menuEdit.Back to Start", False },
2965 { "menuEngine.Move Now", False },
2966 { "menuEdit.Truncate Game", False },
2970 Enables trainingOffEnables[] = {
2971 { "menuMode.Edit Comment", True },
2972 { "menuMode.Pause", True },
2973 { "menuEdit.Forward", True },
2974 { "menuEdit.Backward", True },
2975 { "menuEdit.Forward to End", True },
2976 { "menuEdit.Back to Start", True },
2977 { "menuEngine.Move Now", True },
2978 { "menuEdit.Truncate Game", True },
2982 Enables machineThinkingEnables[] = {
2983 { "menuFile.Load Game", False },
2984 // { "menuFile.Load Next Game", False },
2985 // { "menuFile.Load Previous Game", False },
2986 // { "menuFile.Reload Same Game", False },
2987 { "menuEdit.Paste Game", False },
2988 { "menuFile.Load Position", False },
2989 // { "menuFile.Load Next Position", False },
2990 // { "menuFile.Load Previous Position", False },
2991 // { "menuFile.Reload Same Position", False },
2992 { "menuEdit.Paste Position", False },
2993 { "menuMode.Machine White", False },
2994 { "menuMode.Machine Black", False },
2995 { "menuMode.Two Machines", False },
2996 // { "menuMode.Machine Match", False },
2997 { "menuEngine.Retract Move", False },
3001 Enables userThinkingEnables[] = {
3002 { "menuFile.Load Game", True },
3003 // { "menuFile.Load Next Game", True },
3004 // { "menuFile.Load Previous Game", True },
3005 // { "menuFile.Reload Same Game", True },
3006 { "menuEdit.Paste Game", True },
3007 { "menuFile.Load Position", True },
3008 // { "menuFile.Load Next Position", True },
3009 // { "menuFile.Load Previous Position", True },
3010 // { "menuFile.Reload Same Position", True },
3011 { "menuEdit.Paste Position", True },
3012 { "menuMode.Machine White", True },
3013 { "menuMode.Machine Black", True },
3014 { "menuMode.Two Machines", True },
3015 // { "menuMode.Machine Match", True },
3016 { "menuEngine.Retract Move", True },
3023 SetMenuEnables(icsEnables);
3026 if (appData.zippyPlay && !appData.noChessProgram) { /* [DM] icsEngineAnalyze */
3027 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
3028 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuEngine.Engine #1 Settings"), True);
3036 SetMenuEnables(ncpEnables);
3042 SetMenuEnables(gnuEnables);
3048 SetMenuEnables(cmailEnables);
3052 SetTrainingModeOn ()
3054 SetMenuEnables(trainingOnEnables);
3055 if (appData.showButtonBar) {
3056 XtSetSensitive(buttonBarWidget, False);
3062 SetTrainingModeOff ()
3064 SetMenuEnables(trainingOffEnables);
3065 if (appData.showButtonBar) {
3066 XtSetSensitive(buttonBarWidget, True);
3071 SetUserThinkingEnables ()
3073 if (appData.noChessProgram) return;
3074 SetMenuEnables(userThinkingEnables);
3078 SetMachineThinkingEnables ()
3080 if (appData.noChessProgram) return;
3081 SetMenuEnables(machineThinkingEnables);
3083 case MachinePlaysBlack:
3084 case MachinePlaysWhite:
3085 case TwoMachinesPlay:
3086 XtSetSensitive(XtNameToWidget(menuBarWidget,
3087 ModeToWidgetName(gameMode)), True);
3094 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
3095 #define HISTORY_SIZE 64
3096 static char *history[HISTORY_SIZE];
3097 int histIn = 0, histP = 0;
3100 SaveInHistory (char *cmd)
3102 if (history[histIn] != NULL) {
3103 free(history[histIn]);
3104 history[histIn] = NULL;
3106 if (*cmd == NULLCHAR) return;
3107 history[histIn] = StrSave(cmd);
3108 histIn = (histIn + 1) % HISTORY_SIZE;
3109 if (history[histIn] != NULL) {
3110 free(history[histIn]);
3111 history[histIn] = NULL;
3117 PrevInHistory (char *cmd)
3120 if (histP == histIn) {
3121 if (history[histIn] != NULL) free(history[histIn]);
3122 history[histIn] = StrSave(cmd);
3124 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
3125 if (newhp == histIn || history[newhp] == NULL) return NULL;
3127 return history[histP];
3133 if (histP == histIn) return NULL;
3134 histP = (histP + 1) % HISTORY_SIZE;
3135 return history[histP];
3137 // end of borrowed code
3139 #define Abs(n) ((n)<0 ? -(n) : (n))
3143 InsertPxlSize (char *pattern, int targetPxlSize)
3145 char *base_fnt_lst, strInt[12], *p, *q;
3146 int alternatives, i, len, strIntLen;
3149 * Replace the "*" (if present) in the pixel-size slot of each
3150 * alternative with the targetPxlSize.
3154 while ((p = strchr(p, ',')) != NULL) {
3158 snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
3159 strIntLen = strlen(strInt);
3160 base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
3164 while (alternatives--) {
3165 char *comma = strchr(p, ',');
3166 for (i=0; i<14; i++) {
3167 char *hyphen = strchr(p, '-');
3169 if (comma && hyphen > comma) break;
3170 len = hyphen + 1 - p;
3171 if (i == 7 && *p == '*' && len == 2) {
3173 memcpy(q, strInt, strIntLen);
3183 len = comma + 1 - p;
3190 return base_fnt_lst;
3194 CreateFontSet (char *base_fnt_lst)
3197 char **missing_list;
3201 fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
3202 &missing_list, &missing_count, &def_string);
3203 if (appData.debugMode) {
3205 XFontStruct **font_struct_list;
3206 char **font_name_list;
3207 fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
3209 fprintf(debugFP, " got list %s, locale %s\n",
3210 XBaseFontNameListOfFontSet(fntSet),
3211 XLocaleOfFontSet(fntSet));
3212 count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
3213 for (i = 0; i < count; i++) {
3214 fprintf(debugFP, " got charset %s\n", font_name_list[i]);
3217 for (i = 0; i < missing_count; i++) {
3218 fprintf(debugFP, " missing charset %s\n", missing_list[i]);
3221 if (fntSet == NULL) {
3222 fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
3227 #else // not ENABLE_NLS
3229 * Find a font that matches "pattern" that is as close as
3230 * possible to the targetPxlSize. Prefer fonts that are k
3231 * pixels smaller to fonts that are k pixels larger. The
3232 * pattern must be in the X Consortium standard format,
3233 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3234 * The return value should be freed with XtFree when no
3238 FindFont (char *pattern, int targetPxlSize)
3240 char **fonts, *p, *best, *scalable, *scalableTail;
3241 int i, j, nfonts, minerr, err, pxlSize;
3243 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3245 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3246 programName, pattern);
3253 for (i=0; i<nfonts; i++) {
3256 if (*p != '-') continue;
3258 if (*p == NULLCHAR) break;
3259 if (*p++ == '-') j++;
3261 if (j < 7) continue;
3264 scalable = fonts[i];
3267 err = pxlSize - targetPxlSize;
3268 if (Abs(err) < Abs(minerr) ||
3269 (minerr > 0 && err < 0 && -err == minerr)) {
3275 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3276 /* If the error is too big and there is a scalable font,
3277 use the scalable font. */
3278 int headlen = scalableTail - scalable;
3279 p = (char *) XtMalloc(strlen(scalable) + 10);
3280 while (isdigit(*scalableTail)) scalableTail++;
3281 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3283 p = (char *) XtMalloc(strlen(best) + 2);
3284 safeStrCpy(p, best, strlen(best)+1 );
3286 if (appData.debugMode) {
3287 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3288 pattern, targetPxlSize, p);
3290 XFreeFontNames(fonts);
3297 { // [HGM] deletes GCs that are to be remade, to prevent resource leak;
3298 // must be called before all non-first callse to CreateGCs()
3299 XtReleaseGC(shellWidget, highlineGC);
3300 XtReleaseGC(shellWidget, lightSquareGC);
3301 XtReleaseGC(shellWidget, darkSquareGC);
3302 XtReleaseGC(shellWidget, lineGC);
3303 if (appData.monoMode) {
3304 if (DefaultDepth(xDisplay, xScreen) == 1) {
3305 XtReleaseGC(shellWidget, wbPieceGC);
3307 XtReleaseGC(shellWidget, bwPieceGC);
3310 XtReleaseGC(shellWidget, prelineGC);
3311 XtReleaseGC(shellWidget, jailSquareGC);
3312 XtReleaseGC(shellWidget, wdPieceGC);
3313 XtReleaseGC(shellWidget, wlPieceGC);
3314 XtReleaseGC(shellWidget, wjPieceGC);
3315 XtReleaseGC(shellWidget, bdPieceGC);
3316 XtReleaseGC(shellWidget, blPieceGC);
3317 XtReleaseGC(shellWidget, bjPieceGC);
3322 CreateGCs (int redo)
3324 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3325 | GCBackground | GCFunction | GCPlaneMask;
3326 XGCValues gc_values;
3329 gc_values.plane_mask = AllPlanes;
3330 gc_values.line_width = lineGap;
3331 gc_values.line_style = LineSolid;
3332 gc_values.function = GXcopy;
3335 DeleteGCs(); // called a second time; clean up old GCs first
3336 } else { // [HGM] grid and font GCs created on first call only
3337 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3338 gc_values.background = XWhitePixel(xDisplay, xScreen);
3339 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3340 XSetFont(xDisplay, coordGC, coordFontID);
3342 // [HGM] make font for holdings counts (white on black)
3343 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3344 gc_values.background = XBlackPixel(xDisplay, xScreen);
3345 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3346 XSetFont(xDisplay, countGC, countFontID);
3348 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3349 gc_values.background = XBlackPixel(xDisplay, xScreen);
3350 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3352 if (appData.monoMode) {
3353 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3354 gc_values.background = XWhitePixel(xDisplay, xScreen);
3355 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3357 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3358 gc_values.background = XBlackPixel(xDisplay, xScreen);
3359 lightSquareGC = wbPieceGC
3360 = XtGetGC(shellWidget, value_mask, &gc_values);
3362 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3363 gc_values.background = XWhitePixel(xDisplay, xScreen);
3364 darkSquareGC = bwPieceGC
3365 = XtGetGC(shellWidget, value_mask, &gc_values);
3367 if (DefaultDepth(xDisplay, xScreen) == 1) {
3368 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3369 gc_values.function = GXcopyInverted;
3370 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3371 gc_values.function = GXcopy;
3372 if (XBlackPixel(xDisplay, xScreen) == 1) {
3373 bwPieceGC = darkSquareGC;
3374 wbPieceGC = copyInvertedGC;
3376 bwPieceGC = copyInvertedGC;
3377 wbPieceGC = lightSquareGC;
3381 gc_values.foreground = highlightSquareColor;
3382 gc_values.background = highlightSquareColor;
3383 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3385 gc_values.foreground = premoveHighlightColor;
3386 gc_values.background = premoveHighlightColor;
3387 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3389 gc_values.foreground = lightSquareColor;
3390 gc_values.background = darkSquareColor;
3391 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3393 gc_values.foreground = darkSquareColor;
3394 gc_values.background = lightSquareColor;
3395 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3397 gc_values.foreground = jailSquareColor;
3398 gc_values.background = jailSquareColor;
3399 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3401 gc_values.foreground = whitePieceColor;
3402 gc_values.background = darkSquareColor;
3403 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3405 gc_values.foreground = whitePieceColor;
3406 gc_values.background = lightSquareColor;
3407 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3409 gc_values.foreground = whitePieceColor;
3410 gc_values.background = jailSquareColor;
3411 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3413 gc_values.foreground = blackPieceColor;
3414 gc_values.background = darkSquareColor;
3415 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3417 gc_values.foreground = blackPieceColor;
3418 gc_values.background = lightSquareColor;
3419 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3421 gc_values.foreground = blackPieceColor;
3422 gc_values.background = jailSquareColor;
3423 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3428 loadXIM (XImage *xim, XImage *xmask, char *filename, Pixmap *dest, Pixmap *mask)
3436 fp = fopen(filename, "rb");
3438 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3445 for (y=0; y<h; ++y) {
3446 for (x=0; x<h; ++x) {
3451 XPutPixel(xim, x, y, blackPieceColor);
3453 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3456 XPutPixel(xim, x, y, darkSquareColor);
3458 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3461 XPutPixel(xim, x, y, whitePieceColor);
3463 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3466 XPutPixel(xim, x, y, lightSquareColor);
3468 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3476 /* create Pixmap of piece */
3477 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3479 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3482 /* create Pixmap of clipmask
3483 Note: We assume the white/black pieces have the same
3484 outline, so we make only 6 masks. This is okay
3485 since the XPM clipmask routines do the same. */
3487 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3489 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3492 /* now create the 1-bit version */
3493 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3496 values.foreground = 1;
3497 values.background = 0;
3499 /* Don't use XtGetGC, not read only */
3500 maskGC = XCreateGC(xDisplay, *mask,
3501 GCForeground | GCBackground, &values);
3502 XCopyPlane(xDisplay, temp, *mask, maskGC,
3503 0, 0, squareSize, squareSize, 0, 0, 1);
3504 XFreePixmap(xDisplay, temp);
3509 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3517 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3522 /* The XSynchronize calls were copied from CreatePieces.
3523 Not sure if needed, but can't hurt */
3524 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3527 /* temp needed by loadXIM() */
3528 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3529 0, 0, ss, ss, AllPlanes, XYPixmap);
3531 if (strlen(appData.pixmapDirectory) == 0) {
3535 if (appData.monoMode) {
3536 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3540 fprintf(stderr, _("\nLoading XIMs...\n"));
3542 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3543 fprintf(stderr, "%d", piece+1);
3544 for (kind=0; kind<4; kind++) {
3545 fprintf(stderr, ".");
3546 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3547 ExpandPathName(appData.pixmapDirectory),
3548 piece <= (int) WhiteKing ? "" : "w",
3549 pieceBitmapNames[piece],
3551 ximPieceBitmap[kind][piece] =
3552 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3553 0, 0, ss, ss, AllPlanes, XYPixmap);
3554 if (appData.debugMode)
3555 fprintf(stderr, _("(File:%s:) "), buf);
3556 loadXIM(ximPieceBitmap[kind][piece],
3558 &(xpmPieceBitmap2[kind][piece]),
3559 &(ximMaskPm2[piece]));
3560 if(piece <= (int)WhiteKing)
3561 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3563 fprintf(stderr," ");
3565 /* Load light and dark squares */
3566 /* If the LSQ and DSQ pieces don't exist, we will
3567 draw them with solid squares. */
3568 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3569 if (access(buf, 0) != 0) {
3573 fprintf(stderr, _("light square "));
3575 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3576 0, 0, ss, ss, AllPlanes, XYPixmap);
3577 if (appData.debugMode)
3578 fprintf(stderr, _("(File:%s:) "), buf);
3580 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3581 fprintf(stderr, _("dark square "));
3582 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3583 ExpandPathName(appData.pixmapDirectory), ss);
3584 if (appData.debugMode)
3585 fprintf(stderr, _("(File:%s:) "), buf);
3587 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3588 0, 0, ss, ss, AllPlanes, XYPixmap);
3589 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3590 xpmJailSquare = xpmLightSquare;
3592 fprintf(stderr, _("Done.\n"));
3594 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3597 static VariantClass oldVariant = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
3601 CreateXPMBoard (char *s, int kind)
3605 if(!appData.useBitmaps || s == NULL || *s == 0 || *s == '*') { useTexture &= ~(kind+1); return; }
3606 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3607 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3613 { // [HGM] to prevent resoucre leak on calling CreaeXPMPieces() a second time,
3614 // thisroutine has to be called t free the old piece pixmaps
3616 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++)
3617 for (kind=0; kind<4; kind++) XFreePixmap(xDisplay, xpmPieceBitmap2[kind][piece]);
3619 XFreePixmap(xDisplay, xpmLightSquare);
3620 XFreePixmap(xDisplay, xpmDarkSquare);
3629 u_int ss = squareSize;
3631 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3632 XpmColorSymbol symbols[4];
3633 static int redo = False;
3635 if(redo) FreeXPMPieces(); else redo = 1;
3637 /* The XSynchronize calls were copied from CreatePieces.
3638 Not sure if needed, but can't hurt */
3639 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3641 /* Setup translations so piece colors match square colors */
3642 symbols[0].name = "light_piece";
3643 symbols[0].value = appData.whitePieceColor;
3644 symbols[1].name = "dark_piece";
3645 symbols[1].value = appData.blackPieceColor;
3646 symbols[2].name = "light_square";
3647 symbols[2].value = appData.lightSquareColor;