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 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
145 #include <X11/Intrinsic.h>
146 #include <X11/StringDefs.h>
147 #include <X11/Shell.h>
148 #include <X11/cursorfont.h>
149 #include <X11/Xatom.h>
150 #include <X11/Xmu/Atoms.h>
152 #include <X11/Xaw3d/Dialog.h>
153 #include <X11/Xaw3d/Form.h>
154 #include <X11/Xaw3d/List.h>
155 #include <X11/Xaw3d/Label.h>
156 #include <X11/Xaw3d/SimpleMenu.h>
157 #include <X11/Xaw3d/SmeBSB.h>
158 #include <X11/Xaw3d/SmeLine.h>
159 #include <X11/Xaw3d/Box.h>
160 #include <X11/Xaw3d/MenuButton.h>
161 #include <X11/Xaw3d/Text.h>
162 #include <X11/Xaw3d/AsciiText.h>
164 #include <X11/Xaw/Dialog.h>
165 #include <X11/Xaw/Form.h>
166 #include <X11/Xaw/List.h>
167 #include <X11/Xaw/Label.h>
168 #include <X11/Xaw/SimpleMenu.h>
169 #include <X11/Xaw/SmeBSB.h>
170 #include <X11/Xaw/SmeLine.h>
171 #include <X11/Xaw/Box.h>
172 #include <X11/Xaw/MenuButton.h>
173 #include <X11/Xaw/Text.h>
174 #include <X11/Xaw/AsciiText.h>
177 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
182 #include "pixmaps/pixmaps.h"
183 #define IMAGE_EXT "xpm"
185 #define IMAGE_EXT "xim"
186 #include "bitmaps/bitmaps.h"
189 #include "bitmaps/icon_white.bm"
190 #include "bitmaps/icon_black.bm"
191 #include "bitmaps/checkmark.bm"
193 #include "frontend.h"
195 #include "backendz.h"
199 #include "xgamelist.h"
200 #include "xhistory.h"
201 #include "xedittags.h"
204 // must be moved to xengineoutput.h
206 void EngineOutputProc P((Widget w, XEvent *event,
207 String *prms, Cardinal *nprms));
208 void EvalGraphProc P((Widget w, XEvent *event,
209 String *prms, Cardinal *nprms));
216 #define usleep(t) _sleep2(((t)+500)/1000)
220 # define _(s) gettext (s)
221 # define N_(s) gettext_noop (s)
239 int main P((int argc, char **argv));
240 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
241 char *init_path, char *filter, char *mode, int (*show_entry)(), char **name_return));
242 RETSIGTYPE CmailSigHandler P((int sig));
243 RETSIGTYPE IntSigHandler P((int sig));
244 RETSIGTYPE TermSizeSigHandler P((int sig));
245 void CreateGCs P((int redo));
246 void CreateAnyPieces P((void));
247 void CreateXIMPieces P((void));
248 void CreateXPMPieces P((void));
249 void CreateXPMBoard P((char *s, int n));
250 void CreatePieces P((void));
251 void CreatePieceMenus P((void));
252 Widget CreateMenuBar P((Menu *mb));
253 Widget CreateButtonBar P ((MenuItem *mi));
255 char *InsertPxlSize P((char *pattern, int targetPxlSize));
256 XFontSet CreateFontSet P((char *base_fnt_lst));
258 char *FindFont P((char *pattern, int targetPxlSize));
260 void PieceMenuPopup P((Widget w, XEvent *event,
261 String *params, Cardinal *num_params));
262 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
263 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
264 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
265 u_int wreq, u_int hreq));
266 void CreateGrid P((void));
267 int EventToSquare P((int x, int limit));
268 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
269 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
270 void MoveTypeInProc P((Widget widget, caddr_t unused, XEvent *event));
271 void HandleUserMove P((Widget w, XEvent *event,
272 String *prms, Cardinal *nprms));
273 void AnimateUserMove P((Widget w, XEvent * event,
274 String * params, Cardinal * nParams));
275 void HandlePV P((Widget w, XEvent * event,
276 String * params, Cardinal * nParams));
277 void SelectPV P((Widget w, XEvent * event,
278 String * params, Cardinal * nParams));
279 void StopPV P((Widget w, XEvent * event,
280 String * params, Cardinal * nParams));
281 void WhiteClock P((Widget w, XEvent *event,
282 String *prms, Cardinal *nprms));
283 void BlackClock P((Widget w, XEvent *event,
284 String *prms, Cardinal *nprms));
285 void DrawPositionProc P((Widget w, XEvent *event,
286 String *prms, Cardinal *nprms));
287 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
289 void CommentClick P((Widget w, XEvent * event,
290 String * params, Cardinal * nParams));
291 void CommentPopUp P((char *title, char *label));
292 void CommentPopDown P((void));
293 void ICSInputBoxPopUp P((void));
294 void ICSInputBoxPopDown P((void));
295 void FileNamePopUp P((char *label, char *def, char *filter,
296 FileProc proc, char *openMode));
297 void FileNamePopDown P((void));
298 void FileNameCallback P((Widget w, XtPointer client_data,
299 XtPointer call_data));
300 void FileNameAction P((Widget w, XEvent *event,
301 String *prms, Cardinal *nprms));
302 void AskQuestionReplyAction P((Widget w, XEvent *event,
303 String *prms, Cardinal *nprms));
304 void AskQuestionProc P((Widget w, XEvent *event,
305 String *prms, Cardinal *nprms));
306 void AskQuestionPopDown P((void));
307 void PromotionPopDown P((void));
308 void PromotionCallback P((Widget w, XtPointer client_data,
309 XtPointer call_data));
310 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
311 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
312 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
313 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
315 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
317 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
319 void LoadPositionProc P((Widget w, XEvent *event,
320 String *prms, Cardinal *nprms));
321 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
323 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
325 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
327 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
329 void PastePositionProc P((Widget w, XEvent *event, String *prms,
331 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
332 void CopyGameListProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
333 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
334 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
335 void SavePositionProc P((Widget w, XEvent *event,
336 String *prms, Cardinal *nprms));
337 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
338 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
340 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
341 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
342 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
344 void MachineWhiteProc P((Widget w, XEvent *event,
345 String *prms, Cardinal *nprms));
346 void AnalyzeModeProc P((Widget w, XEvent *event,
347 String *prms, Cardinal *nprms));
348 void AnalyzeFileProc P((Widget w, XEvent *event,
349 String *prms, Cardinal *nprms));
350 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
352 void MatchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
353 void MatchOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
354 void IcsClientProc P((Widget w, XEvent *event, String *prms,
356 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
357 void EditPositionProc P((Widget w, XEvent *event,
358 String *prms, Cardinal *nprms));
359 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void EditCommentProc P((Widget w, XEvent *event,
361 String *prms, Cardinal *nprms));
362 void IcsInputBoxProc P((Widget w, XEvent *event,
363 String *prms, Cardinal *nprms));
364 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
365 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
370 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
371 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
372 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
373 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
374 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
375 void TypeInProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
376 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
377 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
379 void StopObservingProc P((Widget w, XEvent *event, String *prms,
381 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
383 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
384 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
385 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
386 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
387 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
388 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
389 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
390 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
392 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
394 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
395 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
397 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
399 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
401 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
402 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
403 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
404 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
406 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
407 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
409 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
411 void HighlightArrowProc P((Widget w, XEvent *event, String *prms,
413 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
414 //void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
415 void OneClickProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
416 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
418 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
420 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
422 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
424 //void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
425 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
427 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
429 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
431 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
433 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
434 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
435 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
436 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
442 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
443 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
444 void DisplayMove P((int moveNumber));
445 void DisplayTitle P((char *title));
446 void ICSInitScript P((void));
447 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
448 void ErrorPopUp P((char *title, char *text, int modal));
449 void ErrorPopDown P((void));
450 static char *ExpandPathName P((char *path));
451 static void CreateAnimVars P((void));
452 static void DragPieceMove P((int x, int y));
453 static void DrawDragPiece P((void));
454 char *ModeToWidgetName P((GameMode mode));
455 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
456 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
457 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
458 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
459 void OptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
460 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
461 void IcsTextProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
462 void LoadEngineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
463 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
464 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
465 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
466 void IcsOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
467 void SoundOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
468 void BoardOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
469 void LoadOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
470 void SaveOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
471 void EditBookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
472 void GameListOptionsPopDown P(());
473 void ShufflePopDown P(());
474 void TimeControlPopDown P(());
475 void GenericPopDown P(());
476 void update_ics_width P(());
477 int get_term_width P(());
478 int CopyMemoProc P(());
479 void DrawArrowHighlight P((int fromX, int fromY, int toX,int toY));
480 Boolean IsDrawArrowEnabled P(());
483 * XBoard depends on Xt R4 or higher
485 int xtVersion = XtSpecificationRelease;
490 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
491 jailSquareColor, highlightSquareColor, premoveHighlightColor;
492 Pixel lowTimeWarningColor;
493 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
494 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
495 wjPieceGC, bjPieceGC, prelineGC, countGC;
496 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
497 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
498 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
499 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
500 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
501 ICSInputShell, fileNameShell, askQuestionShell;
502 Widget historyShell, evalGraphShell, gameListShell;
503 int hOffset; // [HGM] dual
504 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
505 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
506 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
508 XFontSet fontSet, clockFontSet;
511 XFontStruct *clockFontStruct;
513 Font coordFontID, countFontID;
514 XFontStruct *coordFontStruct, *countFontStruct;
515 XtAppContext appContext;
517 char *oldICSInteractionTitle;
521 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
523 Position commentX = -1, commentY = -1;
524 Dimension commentW, commentH;
525 typedef unsigned int BoardSize;
527 Boolean chessProgram;
529 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
530 int squareSize, smallLayout = 0, tinyLayout = 0,
531 marginW, marginH, // [HGM] for run-time resizing
532 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
533 ICSInputBoxUp = False, askQuestionUp = False,
534 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
535 errorUp = False, errorExitStatus = -1, lineGap, defaultLineGap;
536 Pixel timerForegroundPixel, timerBackgroundPixel;
537 Pixel buttonForegroundPixel, buttonBackgroundPixel;
538 char *chessDir, *programName, *programVersion,
539 *gameCopyFilename, *gamePasteFilename;
540 Boolean alwaysOnTop = False;
541 Boolean saveSettingsOnExit;
542 char *settingsFileName;
543 char *icsTextMenuString;
545 char *firstChessProgramNames;
546 char *secondChessProgramNames;
548 WindowPlacement wpMain;
549 WindowPlacement wpConsole;
550 WindowPlacement wpComment;
551 WindowPlacement wpMoveHistory;
552 WindowPlacement wpEvalGraph;
553 WindowPlacement wpEngineOutput;
554 WindowPlacement wpGameList;
555 WindowPlacement wpTags;
557 extern Widget shells[];
558 extern Boolean shellUp[];
562 Pixmap pieceBitmap[2][(int)BlackPawn];
563 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
564 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
565 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
566 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
567 Pixmap xpmBoardBitmap[2];
568 int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
569 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
570 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
571 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
572 XImage *ximLightSquare, *ximDarkSquare;
575 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
576 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
578 #define White(piece) ((int)(piece) < (int)BlackPawn)
580 /* Variables for doing smooth animation. This whole thing
581 would be much easier if the board was double-buffered,
582 but that would require a fairly major rewrite. */
587 GC blitGC, pieceGC, outlineGC;
588 XPoint startSquare, prevFrame, mouseDelta;
592 int startBoardX, startBoardY;
595 /* There can be two pieces being animated at once: a player
596 can begin dragging a piece before the remote opponent has moved. */
598 static AnimState game, player;
600 /* Bitmaps for use as masks when drawing XPM pieces.
601 Need one for each black and white piece. */
602 static Pixmap xpmMask[BlackKing + 1];
604 /* This magic number is the number of intermediate frames used
605 in each half of the animation. For short moves it's reduced
606 by 1. The total number of frames will be factor * 2 + 1. */
609 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
611 MenuItem fileMenu[] = {
612 {N_("New Game Ctrl+N"), "New Game", ResetProc},
613 {N_("New Shuffle Game ..."), "New Shuffle Game", ShuffleMenuProc},
614 {N_("New Variant ... Alt+Shift+V"), "New Variant", NewVariantProc}, // [HGM] variant: not functional yet
615 {"----", NULL, NothingProc},
616 {N_("Load Game Ctrl+O"), "Load Game", LoadGameProc},
617 {N_("Load Position Ctrl+Shift+O"), "Load Position", LoadPositionProc},
618 // {N_("Load Next Game"), "Load Next Game", LoadNextGameProc},
619 // {N_("Load Previous Game"), "Load Previous Game", LoadPrevGameProc},
620 // {N_("Reload Same Game"), "Reload Same Game", ReloadGameProc},
621 {N_("Next Position Shift+PgDn"), "Load Next Position", LoadNextPositionProc},
622 {N_("Prev Position Shift+PgUp"), "Load Previous Position", LoadPrevPositionProc},
623 {"----", NULL, NothingProc},
624 // {N_("Reload Same Position"), "Reload Same Position", ReloadPositionProc},
625 {N_("Save Game Ctrl+S"), "Save Game", SaveGameProc},
626 {N_("Save Position Ctrl+Shift+S"), "Save Position", SavePositionProc},
627 {"----", NULL, NothingProc},
628 {N_("Mail Move"), "Mail Move", MailMoveProc},
629 {N_("Reload CMail Message"), "Reload CMail Message", ReloadCmailMsgProc},
630 {"----", NULL, NothingProc},
631 {N_("Quit Ctr+Q"), "Exit", QuitProc},
635 MenuItem editMenu[] = {
636 {N_("Copy Game Ctrl+C"), "Copy Game", CopyGameProc},
637 {N_("Copy Position Ctrl+Shift+C"), "Copy Position", CopyPositionProc},
638 {N_("Copy Game List"), "Copy Game List", CopyGameListProc},
639 {"----", NULL, NothingProc},
640 {N_("Paste Game Ctrl+V"), "Paste Game", PasteGameProc},
641 {N_("Paste Position Ctrl+Shift+V"), "Paste Position", PastePositionProc},
642 {"----", NULL, NothingProc},
643 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
644 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
645 {N_("Edit Tags"), "Edit Tags", EditTagsProc},
646 {N_("Edit Comment"), "Edit Comment", EditCommentProc},
647 {N_("Edit Book"), "Edit Book", EditBookProc},
648 {"----", NULL, NothingProc},
649 {N_("Revert Home"), "Revert", RevertProc},
650 {N_("Annotate"), "Annotate", AnnotateProc},
651 {N_("Truncate Game End"), "Truncate Game", TruncateGameProc},
652 {"----", NULL, NothingProc},
653 {N_("Backward Alt+Left"), "Backward", BackwardProc},
654 {N_("Forward Alt+Right"), "Forward", ForwardProc},
655 {N_("Back to Start Alt+Home"), "Back to Start", ToStartProc},
656 {N_("Forward to End Alt+End"), "Forward to End", ToEndProc},
660 MenuItem viewMenu[] = {
661 {N_("Flip View F2"), "Flip View", FlipViewProc},
662 {"----", NULL, NothingProc},
663 {N_("Engine Output Alt+Shift+O"), "Show Engine Output", EngineOutputProc},
664 {N_("Move History Alt+Shift+H"), "Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
665 {N_("Evaluation Graph Alt+Shift+E"), "Show Evaluation Graph", EvalGraphProc},
666 {N_("Game List Alt+Shift+G"), "Show Game List", ShowGameListProc},
667 {N_("ICS text menu"), "ICStex", IcsTextProc},
668 {"----", NULL, NothingProc},
669 {N_("Tags"), "Show Tags", EditTagsProc},
670 {N_("Comments"), "Show Comments", EditCommentProc},
671 {N_("ICS Input Box"), "ICS Input Box", IcsInputBoxProc},
672 {"----", NULL, NothingProc},
673 {N_("Board..."), "Board Options", BoardOptionsProc},
674 {N_("Game List Tags..."), "Game List", GameListOptionsPopUp},
678 MenuItem modeMenu[] = {
679 {N_("Machine White Ctrl+W"), "Machine White", MachineWhiteProc},
680 {N_("Machine Black Ctrl+B"), "Machine Black", MachineBlackProc},
681 {N_("Two Machines Ctrl+T"), "Two Machines", TwoMachinesProc},
682 {N_("Analysis Mode Ctrl+A"), "Analysis Mode", AnalyzeModeProc},
683 {N_("Analyze File Ctrl+F"), "Analyze File", AnalyzeFileProc },
684 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
685 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
686 {N_("Training"), "Training", TrainingProc},
687 {N_("ICS Client"), "ICS Client", IcsClientProc},
688 {"----", NULL, NothingProc},
689 {N_("Machine Match"), "Machine Match", MatchProc},
690 {N_("Pause Pause"), "Pause", PauseProc},
694 MenuItem actionMenu[] = {
695 {N_("Accept F3"), "Accept", AcceptProc},
696 {N_("Decline F4"), "Decline", DeclineProc},
697 {N_("Rematch F12"), "Rematch", RematchProc},
698 {"----", NULL, NothingProc},
699 {N_("Call Flag F5"), "Call Flag", CallFlagProc},
700 {N_("Draw F6"), "Draw", DrawProc},
701 {N_("Adjourn F7"), "Adjourn", AdjournProc},
702 {N_("Abort F8"),"Abort", AbortProc},
703 {N_("Resign F9"), "Resign", ResignProc},
704 {"----", NULL, NothingProc},
705 {N_("Stop Observing F10"), "Stop Observing", StopObservingProc},
706 {N_("Stop Examining F11"), "Stop Examining", StopExaminingProc},
707 {N_("Upload to Examine"), "Upload to Examine", UploadProc},
708 {"----", NULL, NothingProc},
709 {N_("Adjudicate to White"), "Adjudicate to White", AdjuWhiteProc},
710 {N_("Adjudicate to Black"), "Adjudicate to Black", AdjuBlackProc},
711 {N_("Adjudicate Draw"), "Adjudicate Draw", AdjuDrawProc},
715 MenuItem engineMenu[] = {
716 {N_("Load New Engine ..."), "Load Engine", LoadEngineProc},
717 {"----", NULL, NothingProc},
718 {N_("Engine #1 Settings ..."), "Engine #1 Settings", FirstSettingsProc},
719 {N_("Engine #2 Settings ..."), "Engine #2 Settings", SecondSettingsProc},
720 {"----", NULL, NothingProc},
721 {N_("Hint"), "Hint", HintProc},
722 {N_("Book"), "Book", BookProc},
723 {"----", NULL, NothingProc},
724 {N_("Move Now Ctrl+M"), "Move Now", MoveNowProc},
725 {N_("Retract Move Ctrl+X"), "Retract Move", RetractMoveProc},
729 MenuItem optionsMenu[] = {
730 #define OPTIONSDIALOG
732 {N_("General ..."), "General", OptionsProc},
734 {N_("Time Control ... Alt+Shift+T"), "Time Control", TimeControlProc},
735 {N_("Common Engine ... Alt+Shift+U"), "Common Engine", UciMenuProc},
736 {N_("Adjudications ... Alt+Shift+J"), "Adjudications", EngineMenuProc},
737 {N_("ICS ..."), "ICS", IcsOptionsProc},
738 {N_("Match ..."), "Match", MatchOptionsProc},
739 {N_("Load Game ..."), "Load Game", LoadOptionsProc},
740 {N_("Save Game ..."), "Save Game", SaveOptionsProc},
741 // {N_(" ..."), "", OptionsProc},
742 {N_("Game List ..."), "Game List", GameListOptionsPopUp},
743 {N_("Sounds ..."), "Sounds", SoundOptionsProc},
744 {"----", NULL, NothingProc},
745 #ifndef OPTIONSDIALOG
746 {N_("Always Queen Ctrl+Shift+Q"), "Always Queen", AlwaysQueenProc},
747 {N_("Animate Dragging"), "Animate Dragging", AnimateDraggingProc},
748 {N_("Animate Moving Ctrl+Shift+A"), "Animate Moving", AnimateMovingProc},
749 {N_("Auto Flag Ctrl+Shift+F"), "Auto Flag", AutoflagProc},
750 {N_("Auto Flip View"), "Auto Flip View", AutoflipProc},
751 {N_("Blindfold"), "Blindfold", BlindfoldProc},
752 {N_("Flash Moves"), "Flash Moves", FlashMovesProc},
754 {N_("Highlight Dragging"), "Highlight Dragging", HighlightDraggingProc},
756 {N_("Highlight Last Move"), "Highlight Last Move", HighlightLastMoveProc},
757 {N_("Highlight With Arrow"), "Arrow", HighlightArrowProc},
758 {N_("Move Sound"), "Move Sound", MoveSoundProc},
759 // {N_("ICS Alarm"), "ICS Alarm", IcsAlarmProc},
760 {N_("One-Click Moving"), "OneClick", OneClickProc},
761 {N_("Periodic Updates"), "Periodic Updates", PeriodicUpdatesProc},
762 {N_("Ponder Next Move Ctrl+Shift+P"), "Ponder Next Move", PonderNextMoveProc},
763 {N_("Popup Exit Message"), "Popup Exit Message", PopupExitMessageProc},
764 {N_("Popup Move Errors"), "Popup Move Errors", PopupMoveErrorsProc},
765 // {N_("Premove"), "Premove", PremoveProc},
766 {N_("Show Coords"), "Show Coords", ShowCoordsProc},
767 {N_("Hide Thinking Ctrl+Shift+H"), "Hide Thinking", HideThinkingProc},
768 {N_("Test Legality Ctrl+Shift+L"), "Test Legality", TestLegalityProc},
769 {"----", NULL, NothingProc},
771 {N_("Save Settings Now"), "Save Settings Now", SaveSettingsProc},
772 {N_("Save Settings on Exit"), "Save Settings on Exit", SaveOnExitProc},
776 MenuItem helpMenu[] = {
777 {N_("Info XBoard"), "Info XBoard", InfoProc},
778 {N_("Man XBoard F1"), "Man XBoard", ManProc},
779 {"----", NULL, NothingProc},
780 {N_("About XBoard"), "About XBoard", AboutProc},
785 {N_("File"), "File", fileMenu},
786 {N_("Edit"), "Edit", editMenu},
787 {N_("View"), "View", viewMenu},
788 {N_("Mode"), "Mode", modeMenu},
789 {N_("Action"), "Action", actionMenu},
790 {N_("Engine"), "Engine", engineMenu},
791 {N_("Options"), "Options", optionsMenu},
792 {N_("Help"), "Help", helpMenu},
796 #define PAUSE_BUTTON "P"
797 MenuItem buttonBar[] = {
798 {"<<", "<<", ToStartProc},
799 {"<", "<", BackwardProc},
800 {PAUSE_BUTTON, PAUSE_BUTTON, PauseProc},
801 {">", ">", ForwardProc},
802 {">>", ">>", ToEndProc},
806 #define PIECE_MENU_SIZE 18
807 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
808 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
809 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
810 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
811 N_("Empty square"), N_("Clear board") },
812 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
813 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
814 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
815 N_("Empty square"), N_("Clear board") }
817 /* must be in same order as PieceMenuStrings! */
818 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
819 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
820 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
821 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
822 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
823 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
824 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
825 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
826 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
829 #define DROP_MENU_SIZE 6
830 String dropMenuStrings[DROP_MENU_SIZE] = {
831 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
833 /* must be in same order as PieceMenuStrings! */
834 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
835 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
836 WhiteRook, WhiteQueen
844 DropMenuEnables dmEnables[] = {
862 { XtNborderWidth, 0 },
863 { XtNdefaultDistance, 0 },
867 { XtNborderWidth, 0 },
868 { XtNresizable, (XtArgVal) True },
872 { XtNborderWidth, 0 },
878 { XtNjustify, (XtArgVal) XtJustifyRight },
879 { XtNlabel, (XtArgVal) "..." },
880 { XtNresizable, (XtArgVal) True },
881 { XtNresize, (XtArgVal) False }
884 Arg messageArgs[] = {
885 { XtNjustify, (XtArgVal) XtJustifyLeft },
886 { XtNlabel, (XtArgVal) "..." },
887 { XtNresizable, (XtArgVal) True },
888 { XtNresize, (XtArgVal) False }
892 { XtNborderWidth, 0 },
893 { XtNjustify, (XtArgVal) XtJustifyLeft }
896 XtResource clientResources[] = {
897 { "flashCount", "flashCount", XtRInt, sizeof(int),
898 XtOffset(AppDataPtr, flashCount), XtRImmediate,
899 (XtPointer) FLASH_COUNT },
902 XrmOptionDescRec shellOptions[] = {
903 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
904 { "-flash", "flashCount", XrmoptionNoArg, "3" },
905 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
908 XtActionsRec boardActions[] = {
909 { "DrawPosition", DrawPositionProc },
910 { "HandleUserMove", HandleUserMove },
911 { "AnimateUserMove", AnimateUserMove },
912 { "HandlePV", HandlePV },
913 { "SelectPV", SelectPV },
914 { "StopPV", StopPV },
915 { "FileNameAction", FileNameAction },
916 { "AskQuestionProc", AskQuestionProc },
917 { "AskQuestionReplyAction", AskQuestionReplyAction },
918 { "PieceMenuPopup", PieceMenuPopup },
919 { "WhiteClock", WhiteClock },
920 { "BlackClock", BlackClock },
921 { "Iconify", Iconify },
922 { "ResetProc", ResetProc },
923 { "NewVariantProc", NewVariantProc },
924 { "LoadGameProc", LoadGameProc },
925 { "LoadNextGameProc", LoadNextGameProc },
926 { "LoadPrevGameProc", LoadPrevGameProc },
927 { "LoadSelectedProc", LoadSelectedProc },
928 { "SetFilterProc", SetFilterProc },
929 { "ReloadGameProc", ReloadGameProc },
930 { "LoadPositionProc", LoadPositionProc },
931 { "LoadNextPositionProc", LoadNextPositionProc },
932 { "LoadPrevPositionProc", LoadPrevPositionProc },
933 { "ReloadPositionProc", ReloadPositionProc },
934 { "CopyPositionProc", CopyPositionProc },
935 { "PastePositionProc", PastePositionProc },
936 { "CopyGameProc", CopyGameProc },
937 { "CopyGameListProc", CopyGameListProc },
938 { "PasteGameProc", PasteGameProc },
939 { "SaveGameProc", SaveGameProc },
940 { "SavePositionProc", SavePositionProc },
941 { "MailMoveProc", MailMoveProc },
942 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
943 { "QuitProc", QuitProc },
944 { "MachineWhiteProc", MachineWhiteProc },
945 { "MachineBlackProc", MachineBlackProc },
946 { "AnalysisModeProc", AnalyzeModeProc },
947 { "AnalyzeFileProc", AnalyzeFileProc },
948 { "TwoMachinesProc", TwoMachinesProc },
949 { "IcsClientProc", IcsClientProc },
950 { "EditGameProc", EditGameProc },
951 { "EditPositionProc", EditPositionProc },
952 { "TrainingProc", EditPositionProc },
953 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
954 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
955 { "ShowGameListProc", ShowGameListProc },
956 { "ShowMoveListProc", HistoryShowProc},
957 { "EditTagsProc", EditCommentProc },
958 { "EditBookProc", EditBookProc },
959 { "EditCommentProc", EditCommentProc },
960 { "IcsInputBoxProc", IcsInputBoxProc },
961 { "PauseProc", PauseProc },
962 { "AcceptProc", AcceptProc },
963 { "DeclineProc", DeclineProc },
964 { "RematchProc", RematchProc },
965 { "CallFlagProc", CallFlagProc },
966 { "DrawProc", DrawProc },
967 { "AdjournProc", AdjournProc },
968 { "AbortProc", AbortProc },
969 { "ResignProc", ResignProc },
970 { "AdjuWhiteProc", AdjuWhiteProc },
971 { "AdjuBlackProc", AdjuBlackProc },
972 { "AdjuDrawProc", AdjuDrawProc },
973 { "TypeInProc", TypeInProc },
974 { "EnterKeyProc", EnterKeyProc },
975 { "UpKeyProc", UpKeyProc },
976 { "DownKeyProc", DownKeyProc },
977 { "StopObservingProc", StopObservingProc },
978 { "StopExaminingProc", StopExaminingProc },
979 { "UploadProc", UploadProc },
980 { "BackwardProc", BackwardProc },
981 { "ForwardProc", ForwardProc },
982 { "ToStartProc", ToStartProc },
983 { "ToEndProc", ToEndProc },
984 { "RevertProc", RevertProc },
985 { "AnnotateProc", AnnotateProc },
986 { "TruncateGameProc", TruncateGameProc },
987 { "MoveNowProc", MoveNowProc },
988 { "RetractMoveProc", RetractMoveProc },
989 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
990 { "UciMenuProc", (XtActionProc) UciMenuProc },
991 { "TimeControlProc", (XtActionProc) TimeControlProc },
992 { "FlipViewProc", FlipViewProc },
993 { "PonderNextMoveProc", PonderNextMoveProc },
994 #ifndef OPTIONSDIALOG
995 { "AlwaysQueenProc", AlwaysQueenProc },
996 { "AnimateDraggingProc", AnimateDraggingProc },
997 { "AnimateMovingProc", AnimateMovingProc },
998 { "AutoflagProc", AutoflagProc },
999 { "AutoflipProc", AutoflipProc },
1000 { "BlindfoldProc", BlindfoldProc },
1001 { "FlashMovesProc", FlashMovesProc },
1003 { "HighlightDraggingProc", HighlightDraggingProc },
1005 { "HighlightLastMoveProc", HighlightLastMoveProc },
1006 // { "IcsAlarmProc", IcsAlarmProc },
1007 { "MoveSoundProc", MoveSoundProc },
1008 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
1009 { "PopupExitMessageProc", PopupExitMessageProc },
1010 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
1011 // { "PremoveProc", PremoveProc },
1012 { "ShowCoordsProc", ShowCoordsProc },
1013 { "ShowThinkingProc", ShowThinkingProc },
1014 { "HideThinkingProc", HideThinkingProc },
1015 { "TestLegalityProc", TestLegalityProc },
1017 { "SaveSettingsProc", SaveSettingsProc },
1018 { "SaveOnExitProc", SaveOnExitProc },
1019 { "InfoProc", InfoProc },
1020 { "ManProc", ManProc },
1021 { "HintProc", HintProc },
1022 { "BookProc", BookProc },
1023 { "AboutGameProc", AboutGameProc },
1024 { "AboutProc", AboutProc },
1025 { "DebugProc", DebugProc },
1026 { "NothingProc", NothingProc },
1027 { "CommentClick", (XtActionProc) CommentClick },
1028 { "CommentPopDown", (XtActionProc) CommentPopDown },
1029 { "TagsPopDown", (XtActionProc) TagsPopDown },
1030 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
1031 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
1032 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
1033 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
1034 { "GameListPopDown", (XtActionProc) GameListPopDown },
1035 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
1036 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1037 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
1038 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1039 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1040 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
1041 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
1042 { "GenericPopDown", (XtActionProc) GenericPopDown },
1043 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1046 char globalTranslations[] =
1047 ":<Key>F9: ResignProc() \n \
1048 :Ctrl<Key>n: ResetProc() \n \
1049 :Meta<Key>V: NewVariantProc() \n \
1050 :Ctrl<Key>o: LoadGameProc() \n \
1051 :Meta<Key>Next: LoadNextGameProc() \n \
1052 :Meta<Key>Prior: LoadPrevGameProc() \n \
1053 :Ctrl<Key>s: SaveGameProc() \n \
1054 :Ctrl<Key>c: CopyGameProc() \n \
1055 :Ctrl<Key>v: PasteGameProc() \n \
1056 :Ctrl<Key>O: LoadPositionProc() \n \
1057 :Shift<Key>Next: LoadNextPositionProc() \n \
1058 :Shift<Key>Prior: LoadPrevPositionProc() \n \
1059 :Ctrl<Key>S: SavePositionProc() \n \
1060 :Ctrl<Key>C: CopyPositionProc() \n \
1061 :Ctrl<Key>V: PastePositionProc() \n \
1062 :Ctrl<Key>q: QuitProc() \n \
1063 :Ctrl<Key>w: MachineWhiteProc() \n \
1064 :Ctrl<Key>b: MachineBlackProc() \n \
1065 :Ctrl<Key>t: TwoMachinesProc() \n \
1066 :Ctrl<Key>a: AnalysisModeProc() \n \
1067 :Ctrl<Key>f: AnalyzeFileProc() \n \
1068 :Ctrl<Key>e: EditGameProc() \n \
1069 :Ctrl<Key>E: EditPositionProc() \n \
1070 :Meta<Key>O: EngineOutputProc() \n \
1071 :Meta<Key>E: EvalGraphProc() \n \
1072 :Meta<Key>G: ShowGameListProc() \n \
1073 :Meta<Key>H: ShowMoveListProc() \n \
1074 :<Key>Pause: PauseProc() \n \
1075 :<Key>F3: AcceptProc() \n \
1076 :<Key>F4: DeclineProc() \n \
1077 :<Key>F12: RematchProc() \n \
1078 :<Key>F5: CallFlagProc() \n \
1079 :<Key>F6: DrawProc() \n \
1080 :<Key>F7: AdjournProc() \n \
1081 :<Key>F8: AbortProc() \n \
1082 :<Key>F10: StopObservingProc() \n \
1083 :<Key>F11: StopExaminingProc() \n \
1084 :Meta Ctrl<Key>F12: DebugProc() \n \
1085 :Meta<Key>End: ToEndProc() \n \
1086 :Meta<Key>Right: ForwardProc() \n \
1087 :Meta<Key>Home: ToStartProc() \n \
1088 :Meta<Key>Left: BackwardProc() \n \
1089 :<Key>Home: RevertProc() \n \
1090 :<Key>End: TruncateGameProc() \n \
1091 :Ctrl<Key>m: MoveNowProc() \n \
1092 :Ctrl<Key>x: RetractMoveProc() \n \
1093 :Meta<Key>J: EngineMenuProc() \n \
1094 :Meta<Key>U: UciMenuProc() \n \
1095 :Meta<Key>T: TimeControlProc() \n \
1096 :Ctrl<Key>P: PonderNextMoveProc() \n "
1097 #ifndef OPTIONSDIALOG
1099 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1100 :Ctrl<Key>F: AutoflagProc() \n \
1101 :Ctrl<Key>A: AnimateMovingProc() \n \
1102 :Ctrl<Key>L: TestLegalityProc() \n \
1103 :Ctrl<Key>H: HideThinkingProc() \n "
1106 :<Key>-: Iconify() \n \
1107 :<Key>F1: ManProc() \n \
1108 :<Key>F2: FlipViewProc() \n \
1109 <KeyDown>.: BackwardProc() \n \
1110 <KeyUp>.: ForwardProc() \n \
1111 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1112 \"Send to chess program:\",,1) \n \
1113 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1114 \"Send to second chess program:\",,2) \n";
1116 char boardTranslations[] =
1117 "<Btn1Down>: HandleUserMove(0) \n \
1118 Shift<Btn1Up>: HandleUserMove(1) \n \
1119 <Btn1Up>: HandleUserMove(0) \n \
1120 <Btn1Motion>: AnimateUserMove() \n \
1121 <Btn3Motion>: HandlePV() \n \
1122 <Btn3Up>: PieceMenuPopup(menuB) \n \
1123 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1124 PieceMenuPopup(menuB) \n \
1125 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1126 PieceMenuPopup(menuW) \n \
1127 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1128 PieceMenuPopup(menuW) \n \
1129 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1130 PieceMenuPopup(menuB) \n";
1132 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1133 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1135 char ICSInputTranslations[] =
1136 "<Key>Up: UpKeyProc() \n "
1137 "<Key>Down: DownKeyProc() \n "
1138 "<Key>Return: EnterKeyProc() \n";
1140 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1141 // as the widget is destroyed before the up-click can call extend-end
1142 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1144 String xboardResources[] = {
1145 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1146 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1147 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1152 /* Max possible square size */
1153 #define MAXSQSIZE 256
1155 static int xpm_avail[MAXSQSIZE];
1157 #ifdef HAVE_DIR_STRUCT
1159 /* Extract piece size from filename */
1161 xpm_getsize(name, len, ext)
1172 if ((p=strchr(name, '.')) == NULL ||
1173 StrCaseCmp(p+1, ext) != 0)
1179 while (*p && isdigit(*p))
1186 /* Setup xpm_avail */
1188 xpm_getavail(dirname, ext)
1196 for (i=0; i<MAXSQSIZE; ++i)
1199 if (appData.debugMode)
1200 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1202 dir = opendir(dirname);
1205 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1206 programName, dirname);
1210 while ((ent=readdir(dir)) != NULL) {
1211 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1212 if (i > 0 && i < MAXSQSIZE)
1222 xpm_print_avail(fp, ext)
1228 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1229 for (i=1; i<MAXSQSIZE; ++i) {
1235 /* Return XPM piecesize closest to size */
1237 xpm_closest_to(dirname, size, ext)
1243 int sm_diff = MAXSQSIZE;
1247 xpm_getavail(dirname, ext);
1249 if (appData.debugMode)
1250 xpm_print_avail(stderr, ext);
1252 for (i=1; i<MAXSQSIZE; ++i) {
1255 diff = (diff<0) ? -diff : diff;
1256 if (diff < sm_diff) {
1264 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1270 #else /* !HAVE_DIR_STRUCT */
1271 /* If we are on a system without a DIR struct, we can't
1272 read the directory, so we can't collect a list of
1273 filenames, etc., so we can't do any size-fitting. */
1275 xpm_closest_to(dirname, size, 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(str, which)
1302 char *p, buf[100], *d;
1305 if (strlen(str) > 99) /* watch bounds on buf */
1310 for (i=0; i<which; ++i) {
1317 /* Could be looking at something like:
1319 .. in which case we want to stop on a comma also */
1320 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1324 return -1; /* Use default for empty field */
1327 if (which == 2 || isdigit(*p))
1330 while (*p && isalpha(*p))
1335 for (i=0; i<8; ++i) {
1336 if (!StrCaseCmp(buf, cnames[i]))
1337 return which? (i+40) : (i+30);
1339 if (!StrCaseCmp(buf, "default")) return -1;
1341 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1346 parse_cpair(cc, str)
1350 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1351 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1356 /* bg and attr are optional */
1357 textColors[(int)cc].bg = parse_color(str, 1);
1358 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1359 textColors[(int)cc].attr = 0;
1365 /* Arrange to catch delete-window events */
1366 Atom wm_delete_window;
1368 CatchDeleteWindow(Widget w, String procname)
1371 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1372 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1373 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1380 XtSetArg(args[0], XtNiconic, False);
1381 XtSetValues(shellWidget, args, 1);
1383 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1386 //---------------------------------------------------------------------------------------------------------
1387 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1390 #define CW_USEDEFAULT (1<<31)
1391 #define ICS_TEXT_MENU_SIZE 90
1392 #define DEBUG_FILE "xboard.debug"
1393 #define SetCurrentDirectory chdir
1394 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1398 // these two must some day move to frontend.h, when they are implemented
1399 Boolean GameListIsUp();
1401 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1404 // front-end part of option handling
1406 // [HGM] This platform-dependent table provides the location for storing the color info
1407 extern char *crWhite, * crBlack;
1411 &appData.whitePieceColor,
1412 &appData.blackPieceColor,
1413 &appData.lightSquareColor,
1414 &appData.darkSquareColor,
1415 &appData.highlightSquareColor,
1416 &appData.premoveHighlightColor,
1417 &appData.lowTimeWarningColor,
1428 // [HGM] font: keep a font for each square size, even non-stndard ones
1429 #define NUM_SIZES 18
1430 #define MAX_SIZE 130
1431 Boolean fontIsSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1432 char *fontTable[NUM_FONTS][MAX_SIZE];
1435 ParseFont(char *name, int number)
1436 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1438 if(sscanf(name, "size%d:", &size)) {
1439 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1440 // defer processing it until we know if it matches our board size
1441 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1442 fontTable[number][size] = strdup(strchr(name, ':')+1);
1443 fontValid[number][size] = True;
1448 case 0: // CLOCK_FONT
1449 appData.clockFont = strdup(name);
1451 case 1: // MESSAGE_FONT
1452 appData.font = strdup(name);
1454 case 2: // COORD_FONT
1455 appData.coordFont = strdup(name);
1460 fontIsSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1465 { // only 2 fonts currently
1466 appData.clockFont = CLOCK_FONT_NAME;
1467 appData.coordFont = COORD_FONT_NAME;
1468 appData.font = DEFAULT_FONT_NAME;
1473 { // no-op, until we identify the code for this already in XBoard and move it here
1477 ParseColor(int n, char *name)
1478 { // in XBoard, just copy the color-name string
1479 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1483 ParseTextAttribs(ColorClass cc, char *s)
1485 (&appData.colorShout)[cc] = strdup(s);
1489 ParseBoardSize(void *addr, char *name)
1491 appData.boardSize = strdup(name);
1496 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1500 SetCommPortDefaults()
1501 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1504 // [HGM] args: these three cases taken out to stay in front-end
1506 SaveFontArg(FILE *f, ArgDescriptor *ad)
1509 int i, n = (int)(intptr_t)ad->argLoc;
1511 case 0: // CLOCK_FONT
1512 name = appData.clockFont;
1514 case 1: // MESSAGE_FONT
1515 name = appData.font;
1517 case 2: // COORD_FONT
1518 name = appData.coordFont;
1523 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1524 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1525 fontTable[n][squareSize] = strdup(name);
1526 fontValid[n][squareSize] = True;
1529 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1530 fprintf(f, OPTCHAR "%s" SEPCHAR "\"size%d:%s\"\n", ad->argName, i, fontTable[n][i]);
1535 { // nothing to do, as the sounds are at all times represented by their text-string names already
1539 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1540 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1541 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
1545 SaveColor(FILE *f, ArgDescriptor *ad)
1546 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1547 if(colorVariable[(int)(intptr_t)ad->argLoc])
1548 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
1552 SaveBoardSize(FILE *f, char *name, void *addr)
1553 { // wrapper to shield back-end from BoardSize & sizeInfo
1554 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1558 ParseCommPortSettings(char *s)
1559 { // no such option in XBoard (yet)
1562 extern Widget engineOutputShell;
1565 GetActualPlacement(Widget wg, WindowPlacement *wp)
1575 XtSetArg(args[i], XtNx, &x); i++;
1576 XtSetArg(args[i], XtNy, &y); i++;
1577 XtSetArg(args[i], XtNwidth, &w); i++;
1578 XtSetArg(args[i], XtNheight, &h); i++;
1579 XtGetValues(wg, args, i);
1588 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1589 // In XBoard this will have to wait until awareness of window parameters is implemented
1590 GetActualPlacement(shellWidget, &wpMain);
1591 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1592 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1593 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1594 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1595 if(shellUp[1]) GetActualPlacement(shells[1], &wpComment);
1596 if(shellUp[2]) GetActualPlacement(shells[2], &wpTags);
1600 PrintCommPortSettings(FILE *f, char *name)
1601 { // This option does not exist in XBoard
1605 MySearchPath(char *installDir, char *name, char *fullname)
1606 { // just append installDir and name. Perhaps ExpandPath should be used here?
1607 name = ExpandPathName(name);
1608 if(name && name[0] == '/')
1609 safeStrCpy(fullname, name, MSG_SIZ );
1611 sprintf(fullname, "%s%c%s", installDir, '/', name);
1617 MyGetFullPathName(char *name, char *fullname)
1618 { // should use ExpandPath?
1619 name = ExpandPathName(name);
1620 safeStrCpy(fullname, name, MSG_SIZ );
1625 EnsureOnScreen(int *x, int *y, int minX, int minY)
1632 { // [HGM] args: allows testing if main window is realized from back-end
1633 return xBoardWindow != 0;
1637 PopUpStartupDialog()
1638 { // start menu not implemented in XBoard
1642 ConvertToLine(int argc, char **argv)
1644 static char line[128*1024], buf[1024];
1648 for(i=1; i<argc; i++)
1650 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1651 && argv[i][0] != '{' )
1652 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1654 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1655 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1658 line[strlen(line)-1] = NULLCHAR;
1662 //--------------------------------------------------------------------------------------------
1664 extern Boolean twoBoards, partnerUp;
1667 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1669 #define BoardSize int
1670 void InitDrawingSizes(BoardSize boardSize, int flags)
1671 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1672 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1674 XtGeometryResult gres;
1677 if(!formWidget) return;
1680 * Enable shell resizing.
1682 shellArgs[0].value = (XtArgVal) &w;
1683 shellArgs[1].value = (XtArgVal) &h;
1684 XtGetValues(shellWidget, shellArgs, 2);
1686 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1687 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1688 XtSetValues(shellWidget, &shellArgs[2], 4);
1690 XtSetArg(args[0], XtNdefaultDistance, &sep);
1691 XtGetValues(formWidget, args, 1);
1693 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1694 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1695 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1697 hOffset = boardWidth + 10;
1698 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1699 secondSegments[i] = gridSegments[i];
1700 secondSegments[i].x1 += hOffset;
1701 secondSegments[i].x2 += hOffset;
1704 XtSetArg(args[0], XtNwidth, boardWidth);
1705 XtSetArg(args[1], XtNheight, boardHeight);
1706 XtSetValues(boardWidget, args, 2);
1708 timerWidth = (boardWidth - sep) / 2;
1709 XtSetArg(args[0], XtNwidth, timerWidth);
1710 XtSetValues(whiteTimerWidget, args, 1);
1711 XtSetValues(blackTimerWidget, args, 1);
1713 XawFormDoLayout(formWidget, False);
1715 if (appData.titleInWindow) {
1717 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1718 XtSetArg(args[i], XtNheight, &h); i++;
1719 XtGetValues(titleWidget, args, i);
1721 w = boardWidth - 2*bor;
1723 XtSetArg(args[0], XtNwidth, &w);
1724 XtGetValues(menuBarWidget, args, 1);
1725 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1728 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1729 if (gres != XtGeometryYes && appData.debugMode) {
1731 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1732 programName, gres, w, h, wr, hr);
1736 XawFormDoLayout(formWidget, True);
1739 * Inhibit shell resizing.
1741 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1742 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1743 shellArgs[4].value = shellArgs[2].value = w;
1744 shellArgs[5].value = shellArgs[3].value = h;
1745 XtSetValues(shellWidget, &shellArgs[0], 6);
1747 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1750 for(i=0; i<4; i++) {
1752 for(p=0; p<=(int)WhiteKing; p++)
1753 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1754 if(gameInfo.variant == VariantShogi) {
1755 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1756 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1757 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1758 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1759 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1762 if(gameInfo.variant == VariantGothic) {
1763 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1766 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1767 xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
1768 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1771 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1772 for(p=0; p<=(int)WhiteKing; p++)
1773 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1774 if(gameInfo.variant == VariantShogi) {
1775 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1776 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1777 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1778 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1779 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1782 if(gameInfo.variant == VariantGothic) {
1783 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1786 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1787 ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
1788 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1793 for(i=0; i<2; i++) {
1795 for(p=0; p<=(int)WhiteKing; p++)
1796 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1797 if(gameInfo.variant == VariantShogi) {
1798 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1799 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1800 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1801 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1802 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1805 if(gameInfo.variant == VariantGothic) {
1806 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1809 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1810 pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
1811 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1821 void ParseIcsTextColors()
1822 { // [HGM] tken out of main(), so it can be called from ICS-Options dialog
1823 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1824 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1825 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1826 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1827 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1828 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1829 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1830 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1831 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1832 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1834 if (appData.colorize) {
1836 _("%s: can't parse color names; disabling colorization\n"),
1839 appData.colorize = FALSE;
1844 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
1845 XrmValue vFrom, vTo;
1846 int forceMono = False;
1848 if (!appData.monoMode) {
1849 vFrom.addr = (caddr_t) appData.lightSquareColor;
1850 vFrom.size = strlen(appData.lightSquareColor);
1851 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1852 if (vTo.addr == NULL) {
1853 appData.monoMode = True;
1856 lightSquareColor = *(Pixel *) vTo.addr;
1859 if (!appData.monoMode) {
1860 vFrom.addr = (caddr_t) appData.darkSquareColor;
1861 vFrom.size = strlen(appData.darkSquareColor);
1862 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1863 if (vTo.addr == NULL) {
1864 appData.monoMode = True;
1867 darkSquareColor = *(Pixel *) vTo.addr;
1870 if (!appData.monoMode) {
1871 vFrom.addr = (caddr_t) appData.whitePieceColor;
1872 vFrom.size = strlen(appData.whitePieceColor);
1873 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1874 if (vTo.addr == NULL) {
1875 appData.monoMode = True;
1878 whitePieceColor = *(Pixel *) vTo.addr;
1881 if (!appData.monoMode) {
1882 vFrom.addr = (caddr_t) appData.blackPieceColor;
1883 vFrom.size = strlen(appData.blackPieceColor);
1884 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1885 if (vTo.addr == NULL) {
1886 appData.monoMode = True;
1889 blackPieceColor = *(Pixel *) vTo.addr;
1893 if (!appData.monoMode) {
1894 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1895 vFrom.size = strlen(appData.highlightSquareColor);
1896 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1897 if (vTo.addr == NULL) {
1898 appData.monoMode = True;
1901 highlightSquareColor = *(Pixel *) vTo.addr;
1905 if (!appData.monoMode) {
1906 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1907 vFrom.size = strlen(appData.premoveHighlightColor);
1908 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1909 if (vTo.addr == NULL) {
1910 appData.monoMode = True;
1913 premoveHighlightColor = *(Pixel *) vTo.addr;
1921 { // [HGM] taken out of main
1923 if (appData.monoMode && // [HGM] no sense to go on to certain doom
1924 (appData.bitmapDirectory == NULL || appData.bitmapDirectory[0] == NULLCHAR))
1925 appData.bitmapDirectory = DEF_BITMAP_DIR;
1927 if (appData.bitmapDirectory[0] != NULLCHAR) {
1931 CreateXPMBoard(appData.liteBackTextureFile, 1);
1932 CreateXPMBoard(appData.darkBackTextureFile, 0);
1936 /* Create regular pieces */
1937 if (!useImages) CreatePieces();
1946 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1947 XSetWindowAttributes window_attributes;
1949 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1950 XrmValue vFrom, vTo;
1951 XtGeometryResult gres;
1954 int forceMono = False;
1956 srandom(time(0)); // [HGM] book: make random truly random
1958 setbuf(stdout, NULL);
1959 setbuf(stderr, NULL);
1962 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1963 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1967 programName = strrchr(argv[0], '/');
1968 if (programName == NULL)
1969 programName = argv[0];
1974 XtSetLanguageProc(NULL, NULL, NULL);
1975 bindtextdomain(PACKAGE, LOCALEDIR);
1976 textdomain(PACKAGE);
1980 XtAppInitialize(&appContext, "XBoard", shellOptions,
1981 XtNumber(shellOptions),
1982 &argc, argv, xboardResources, NULL, 0);
1983 appData.boardSize = "";
1984 InitAppData(ConvertToLine(argc, argv));
1986 if (p == NULL) p = "/tmp";
1987 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1988 gameCopyFilename = (char*) malloc(i);
1989 gamePasteFilename = (char*) malloc(i);
1990 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1991 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1993 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1994 clientResources, XtNumber(clientResources),
1997 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1998 static char buf[MSG_SIZ];
1999 EscapeExpand(buf, appData.firstInitString);
2000 appData.firstInitString = strdup(buf);
2001 EscapeExpand(buf, appData.secondInitString);
2002 appData.secondInitString = strdup(buf);
2003 EscapeExpand(buf, appData.firstComputerString);
2004 appData.firstComputerString = strdup(buf);
2005 EscapeExpand(buf, appData.secondComputerString);
2006 appData.secondComputerString = strdup(buf);
2009 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
2012 if (chdir(chessDir) != 0) {
2013 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
2019 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
2020 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
2021 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
2022 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
2025 setbuf(debugFP, NULL);
2028 /* [HGM,HR] make sure board size is acceptable */
2029 if(appData.NrFiles > BOARD_FILES ||
2030 appData.NrRanks > BOARD_RANKS )
2031 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
2034 /* This feature does not work; animation needs a rewrite */
2035 appData.highlightDragging = FALSE;
2039 xDisplay = XtDisplay(shellWidget);
2040 xScreen = DefaultScreen(xDisplay);
2041 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
2043 gameInfo.variant = StringToVariant(appData.variant);
2044 InitPosition(FALSE);
2047 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
2049 if (isdigit(appData.boardSize[0])) {
2050 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
2051 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
2052 &fontPxlSize, &smallLayout, &tinyLayout);
2054 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
2055 programName, appData.boardSize);
2059 /* Find some defaults; use the nearest known size */
2060 SizeDefaults *szd, *nearest;
2061 int distance = 99999;
2062 nearest = szd = sizeDefaults;
2063 while (szd->name != NULL) {
2064 if (abs(szd->squareSize - squareSize) < distance) {
2066 distance = abs(szd->squareSize - squareSize);
2067 if (distance == 0) break;
2071 if (i < 2) lineGap = nearest->lineGap;
2072 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
2073 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
2074 if (i < 5) fontPxlSize = nearest->fontPxlSize;
2075 if (i < 6) smallLayout = nearest->smallLayout;
2076 if (i < 7) tinyLayout = nearest->tinyLayout;
2079 SizeDefaults *szd = sizeDefaults;
2080 if (*appData.boardSize == NULLCHAR) {
2081 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
2082 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
2085 if (szd->name == NULL) szd--;
2086 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
2088 while (szd->name != NULL &&
2089 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
2090 if (szd->name == NULL) {
2091 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
2092 programName, appData.boardSize);
2096 squareSize = szd->squareSize;
2097 lineGap = szd->lineGap;
2098 clockFontPxlSize = szd->clockFontPxlSize;
2099 coordFontPxlSize = szd->coordFontPxlSize;
2100 fontPxlSize = szd->fontPxlSize;
2101 smallLayout = szd->smallLayout;
2102 tinyLayout = szd->tinyLayout;
2103 // [HGM] font: use defaults from settings file if available and not overruled
2105 if(!fontIsSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
2106 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
2107 if(!fontIsSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
2108 appData.font = fontTable[MESSAGE_FONT][squareSize];
2109 if(!fontIsSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
2110 appData.coordFont = fontTable[COORD_FONT][squareSize];
2112 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
2113 if (strlen(appData.pixmapDirectory) > 0) {
2114 p = ExpandPathName(appData.pixmapDirectory);
2116 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
2117 appData.pixmapDirectory);
2120 if (appData.debugMode) {
2121 fprintf(stderr, _("\
2122 XBoard square size (hint): %d\n\
2123 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
2125 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
2126 if (appData.debugMode) {
2127 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
2130 defaultLineGap = lineGap;
2131 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
2133 /* [HR] height treated separately (hacked) */
2134 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
2135 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
2136 if (appData.showJail == 1) {
2137 /* Jail on top and bottom */
2138 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2139 XtSetArg(boardArgs[2], XtNheight,
2140 boardHeight + 2*(lineGap + squareSize));
2141 } else if (appData.showJail == 2) {
2143 XtSetArg(boardArgs[1], XtNwidth,
2144 boardWidth + 2*(lineGap + squareSize));
2145 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2148 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2149 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2153 * Determine what fonts to use.
2156 appData.font = InsertPxlSize(appData.font, fontPxlSize);
2157 appData.clockFont = InsertPxlSize(appData.clockFont, clockFontPxlSize);
2158 appData.coordFont = InsertPxlSize(appData.coordFont, coordFontPxlSize);
2159 fontSet = CreateFontSet(appData.font);
2160 clockFontSet = CreateFontSet(appData.clockFont);
2162 appData.font = FindFont(appData.font, fontPxlSize);
2163 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2164 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2165 clockFontID = XLoadFont(xDisplay, appData.clockFont);
2166 clockFontStruct = XQueryFont(xDisplay, clockFontID);
2168 coordFontID = XLoadFont(xDisplay, appData.coordFont);
2169 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2170 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
2171 countFontStruct = XQueryFont(xDisplay, countFontID);
2173 xdb = XtDatabase(xDisplay);
2175 XrmPutLineResource(&xdb, "*international: True");
2176 vTo.size = sizeof(XFontSet);
2177 vTo.addr = (XtPointer) &fontSet;
2178 XrmPutResource(&xdb, "*fontSet", XtRFontSet, &vTo);
2180 XrmPutStringResource(&xdb, "*font", appData.font);
2184 * Detect if there are not enough colors available and adapt.
2186 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2187 appData.monoMode = True;
2190 forceMono = MakeColors();
2193 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2195 appData.monoMode = True;
2198 if (appData.lowTimeWarning && !appData.monoMode) {
2199 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2200 vFrom.size = strlen(appData.lowTimeWarningColor);
2201 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2202 if (vTo.addr == NULL)
2203 appData.monoMode = True;
2205 lowTimeWarningColor = *(Pixel *) vTo.addr;
2208 if (appData.monoMode && appData.debugMode) {
2209 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2210 (unsigned long) XWhitePixel(xDisplay, xScreen),
2211 (unsigned long) XBlackPixel(xDisplay, xScreen));
2214 ParseIcsTextColors();
2215 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2216 textColors[ColorNone].attr = 0;
2218 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2224 layoutName = "tinyLayout";
2225 } else if (smallLayout) {
2226 layoutName = "smallLayout";
2228 layoutName = "normalLayout";
2230 /* Outer layoutWidget is there only to provide a name for use in
2231 resources that depend on the layout style */
2233 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2234 layoutArgs, XtNumber(layoutArgs));
2236 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2237 formArgs, XtNumber(formArgs));
2238 XtSetArg(args[0], XtNdefaultDistance, &sep);
2239 XtGetValues(formWidget, args, 1);
2242 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2243 XtSetArg(args[0], XtNtop, XtChainTop);
2244 XtSetArg(args[1], XtNbottom, XtChainTop);
2245 XtSetArg(args[2], XtNright, XtChainLeft);
2246 XtSetValues(menuBarWidget, args, 3);
2248 widgetList[j++] = whiteTimerWidget =
2249 XtCreateWidget("whiteTime", labelWidgetClass,
2250 formWidget, timerArgs, XtNumber(timerArgs));
2252 XtSetArg(args[0], XtNfontSet, clockFontSet);
2254 XtSetArg(args[0], XtNfont, clockFontStruct);
2256 XtSetArg(args[1], XtNtop, XtChainTop);
2257 XtSetArg(args[2], XtNbottom, XtChainTop);
2258 XtSetValues(whiteTimerWidget, args, 3);
2260 widgetList[j++] = blackTimerWidget =
2261 XtCreateWidget("blackTime", labelWidgetClass,
2262 formWidget, timerArgs, XtNumber(timerArgs));
2264 XtSetArg(args[0], XtNfontSet, clockFontSet);
2266 XtSetArg(args[0], XtNfont, clockFontStruct);
2268 XtSetArg(args[1], XtNtop, XtChainTop);
2269 XtSetArg(args[2], XtNbottom, XtChainTop);
2270 XtSetValues(blackTimerWidget, args, 3);
2272 if (appData.titleInWindow) {
2273 widgetList[j++] = titleWidget =
2274 XtCreateWidget("title", labelWidgetClass, formWidget,
2275 titleArgs, XtNumber(titleArgs));
2276 XtSetArg(args[0], XtNtop, XtChainTop);
2277 XtSetArg(args[1], XtNbottom, XtChainTop);
2278 XtSetValues(titleWidget, args, 2);
2281 if (appData.showButtonBar) {
2282 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2283 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2284 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2285 XtSetArg(args[2], XtNtop, XtChainTop);
2286 XtSetArg(args[3], XtNbottom, XtChainTop);
2287 XtSetValues(buttonBarWidget, args, 4);
2290 widgetList[j++] = messageWidget =
2291 XtCreateWidget("message", labelWidgetClass, formWidget,
2292 messageArgs, XtNumber(messageArgs));
2293 XtSetArg(args[0], XtNtop, XtChainTop);
2294 XtSetArg(args[1], XtNbottom, XtChainTop);
2295 XtSetValues(messageWidget, args, 2);
2297 widgetList[j++] = boardWidget =
2298 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2299 XtNumber(boardArgs));
2301 XtManageChildren(widgetList, j);
2303 timerWidth = (boardWidth - sep) / 2;
2304 XtSetArg(args[0], XtNwidth, timerWidth);
2305 XtSetValues(whiteTimerWidget, args, 1);
2306 XtSetValues(blackTimerWidget, args, 1);
2308 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2309 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2310 XtGetValues(whiteTimerWidget, args, 2);
2312 if (appData.showButtonBar) {
2313 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2314 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2315 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2319 * formWidget uses these constraints but they are stored
2323 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2324 XtSetValues(menuBarWidget, args, i);
2325 if (appData.titleInWindow) {
2328 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2329 XtSetValues(whiteTimerWidget, args, i);
2331 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2332 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2333 XtSetValues(blackTimerWidget, args, i);
2335 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2336 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2337 XtSetValues(titleWidget, args, i);
2339 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2340 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2341 XtSetValues(messageWidget, args, i);
2342 if (appData.showButtonBar) {
2344 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2345 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2346 XtSetValues(buttonBarWidget, args, i);
2350 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2351 XtSetValues(whiteTimerWidget, args, i);
2353 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2354 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2355 XtSetValues(blackTimerWidget, args, i);
2357 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2358 XtSetValues(titleWidget, args, i);
2360 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2361 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2362 XtSetValues(messageWidget, args, i);
2363 if (appData.showButtonBar) {
2365 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2366 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2367 XtSetValues(buttonBarWidget, args, i);
2372 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2373 XtSetValues(whiteTimerWidget, args, i);
2375 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2376 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2377 XtSetValues(blackTimerWidget, args, i);
2379 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2380 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2381 XtSetValues(messageWidget, args, i);
2382 if (appData.showButtonBar) {
2384 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2385 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2386 XtSetValues(buttonBarWidget, args, i);
2390 XtSetArg(args[0], XtNfromVert, messageWidget);
2391 XtSetArg(args[1], XtNtop, XtChainTop);
2392 XtSetArg(args[2], XtNbottom, XtChainBottom);
2393 XtSetArg(args[3], XtNleft, XtChainLeft);
2394 XtSetArg(args[4], XtNright, XtChainRight);
2395 XtSetValues(boardWidget, args, 5);
2397 XtRealizeWidget(shellWidget);
2400 XtSetArg(args[0], XtNx, wpMain.x);
2401 XtSetArg(args[1], XtNy, wpMain.y);
2402 XtSetValues(shellWidget, args, 2);
2406 * Correct the width of the message and title widgets.
2407 * It is not known why some systems need the extra fudge term.
2408 * The value "2" is probably larger than needed.
2410 XawFormDoLayout(formWidget, False);
2412 #define WIDTH_FUDGE 2
2414 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2415 XtSetArg(args[i], XtNheight, &h); i++;
2416 XtGetValues(messageWidget, args, i);
2417 if (appData.showButtonBar) {
2419 XtSetArg(args[i], XtNwidth, &w); i++;
2420 XtGetValues(buttonBarWidget, args, i);
2421 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2423 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2426 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2427 if (gres != XtGeometryYes && appData.debugMode) {
2428 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2429 programName, gres, w, h, wr, hr);
2432 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2433 /* The size used for the child widget in layout lags one resize behind
2434 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2436 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2437 if (gres != XtGeometryYes && appData.debugMode) {
2438 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2439 programName, gres, w, h, wr, hr);
2442 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2443 XtSetArg(args[1], XtNright, XtChainRight);
2444 XtSetValues(messageWidget, args, 2);
2446 if (appData.titleInWindow) {
2448 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2449 XtSetArg(args[i], XtNheight, &h); i++;
2450 XtGetValues(titleWidget, args, i);
2452 w = boardWidth - 2*bor;
2454 XtSetArg(args[0], XtNwidth, &w);
2455 XtGetValues(menuBarWidget, args, 1);
2456 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2459 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2460 if (gres != XtGeometryYes && appData.debugMode) {
2462 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2463 programName, gres, w, h, wr, hr);
2466 XawFormDoLayout(formWidget, True);
2468 xBoardWindow = XtWindow(boardWidget);
2470 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2471 // not need to go into InitDrawingSizes().
2475 * Create X checkmark bitmap and initialize option menu checks.
2477 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2478 checkmark_bits, checkmark_width, checkmark_height);
2479 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2480 #ifndef OPTIONSDIALOG
2481 if (appData.alwaysPromoteToQueen) {
2482 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2485 if (appData.animateDragging) {
2486 XtSetValues(XtNameToWidget(menuBarWidget,
2487 "menuOptions.Animate Dragging"),
2490 if (appData.animate) {
2491 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2494 if (appData.autoCallFlag) {
2495 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2498 if (appData.autoFlipView) {
2499 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2502 if (appData.blindfold) {
2503 XtSetValues(XtNameToWidget(menuBarWidget,
2504 "menuOptions.Blindfold"), args, 1);
2506 if (appData.flashCount > 0) {
2507 XtSetValues(XtNameToWidget(menuBarWidget,
2508 "menuOptions.Flash Moves"),
2512 if (appData.highlightDragging) {
2513 XtSetValues(XtNameToWidget(menuBarWidget,
2514 "menuOptions.Highlight Dragging"),
2518 if (appData.highlightLastMove) {
2519 XtSetValues(XtNameToWidget(menuBarWidget,
2520 "menuOptions.Highlight Last Move"),
2523 if (appData.highlightMoveWithArrow) {
2524 XtSetValues(XtNameToWidget(menuBarWidget,
2525 "menuOptions.Arrow"),
2528 // if (appData.icsAlarm) {
2529 // XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2532 if (appData.ringBellAfterMoves) {
2533 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2536 if (appData.oneClick) {
2537 XtSetValues(XtNameToWidget(menuBarWidget,
2538 "menuOptions.OneClick"), args, 1);
2540 if (appData.periodicUpdates) {
2541 XtSetValues(XtNameToWidget(menuBarWidget,
2542 "menuOptions.Periodic Updates"), args, 1);
2544 if (appData.ponderNextMove) {
2545 XtSetValues(XtNameToWidget(menuBarWidget,
2546 "menuOptions.Ponder Next Move"), args, 1);
2548 if (appData.popupExitMessage) {
2549 XtSetValues(XtNameToWidget(menuBarWidget,
2550 "menuOptions.Popup Exit Message"), args, 1);
2552 if (appData.popupMoveErrors) {
2553 XtSetValues(XtNameToWidget(menuBarWidget,
2554 "menuOptions.Popup Move Errors"), args, 1);
2556 // if (appData.premove) {
2557 // XtSetValues(XtNameToWidget(menuBarWidget,
2558 // "menuOptions.Premove"), args, 1);
2560 if (appData.showCoords) {
2561 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2564 if (appData.hideThinkingFromHuman) {
2565 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2568 if (appData.testLegality) {
2569 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2573 if (saveSettingsOnExit) {
2574 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2581 ReadBitmap(&wIconPixmap, "icon_white.bm",
2582 icon_white_bits, icon_white_width, icon_white_height);
2583 ReadBitmap(&bIconPixmap, "icon_black.bm",
2584 icon_black_bits, icon_black_width, icon_black_height);
2585 iconPixmap = wIconPixmap;
2587 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2588 XtSetValues(shellWidget, args, i);
2591 * Create a cursor for the board widget.
2593 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2594 XChangeWindowAttributes(xDisplay, xBoardWindow,
2595 CWCursor, &window_attributes);
2598 * Inhibit shell resizing.
2600 shellArgs[0].value = (XtArgVal) &w;
2601 shellArgs[1].value = (XtArgVal) &h;
2602 XtGetValues(shellWidget, shellArgs, 2);
2603 shellArgs[4].value = shellArgs[2].value = w;
2604 shellArgs[5].value = shellArgs[3].value = h;
2605 XtSetValues(shellWidget, &shellArgs[2], 4);
2606 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2607 marginH = h - boardHeight;
2609 CatchDeleteWindow(shellWidget, "QuitProc");
2617 if (appData.animate || appData.animateDragging)
2620 XtAugmentTranslations(formWidget,
2621 XtParseTranslationTable(globalTranslations));
2622 XtAugmentTranslations(boardWidget,
2623 XtParseTranslationTable(boardTranslations));
2624 XtAugmentTranslations(whiteTimerWidget,
2625 XtParseTranslationTable(whiteTranslations));
2626 XtAugmentTranslations(blackTimerWidget,
2627 XtParseTranslationTable(blackTranslations));
2629 /* Why is the following needed on some versions of X instead
2630 * of a translation? */
2631 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2632 (XtEventHandler) EventProc, NULL);
2634 XtAddEventHandler(formWidget, KeyPressMask, False,
2635 (XtEventHandler) MoveTypeInProc, NULL);
2637 /* [AS] Restore layout */
2638 if( wpMoveHistory.visible ) {
2642 if( wpEvalGraph.visible )
2647 if( wpEngineOutput.visible ) {
2648 EngineOutputPopUp();
2653 if (errorExitStatus == -1) {
2654 if (appData.icsActive) {
2655 /* We now wait until we see "login:" from the ICS before
2656 sending the logon script (problems with timestamp otherwise) */
2657 /*ICSInitScript();*/
2658 if (appData.icsInputBox) ICSInputBoxPopUp();
2662 signal(SIGWINCH, TermSizeSigHandler);
2664 signal(SIGINT, IntSigHandler);
2665 signal(SIGTERM, IntSigHandler);
2666 if (*appData.cmailGameName != NULLCHAR) {
2667 signal(SIGUSR1, CmailSigHandler);
2670 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2672 // XtSetKeyboardFocus(shellWidget, formWidget);
2673 XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
2675 XtAppMainLoop(appContext);
2676 if (appData.debugMode) fclose(debugFP); // [DM] debug
2683 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2684 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2686 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2687 unlink(gameCopyFilename);
2688 unlink(gamePasteFilename);
2691 RETSIGTYPE TermSizeSigHandler(int sig)
2704 CmailSigHandler(sig)
2710 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2712 /* Activate call-back function CmailSigHandlerCallBack() */
2713 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2715 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2719 CmailSigHandlerCallBack(isr, closure, message, count, error)
2727 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2729 /**** end signal code ****/
2735 /* try to open the icsLogon script, either in the location given
2736 * or in the users HOME directory
2743 f = fopen(appData.icsLogon, "r");
2746 homedir = getenv("HOME");
2747 if (homedir != NULL)
2749 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2750 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2751 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2752 f = fopen(buf, "r");
2757 ProcessICSInitScript(f);
2759 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2782 if (!menuBarWidget) return;
2783 w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2785 DisplayError("menuEdit.Revert", 0);
2787 XtSetSensitive(w, !grey);
2789 w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2791 DisplayError("menuEdit.Annotate", 0);
2793 XtSetSensitive(w, !grey);
2798 SetMenuEnables(enab)
2802 if (!menuBarWidget) return;
2803 while (enab->name != NULL) {
2804 w = XtNameToWidget(menuBarWidget, enab->name);
2806 DisplayError(enab->name, 0);
2808 XtSetSensitive(w, enab->value);
2814 Enables icsEnables[] = {
2815 { "menuFile.Mail Move", False },
2816 { "menuFile.Reload CMail Message", False },
2817 { "menuMode.Machine Black", False },
2818 { "menuMode.Machine White", False },
2819 { "menuMode.Analysis Mode", False },
2820 { "menuMode.Analyze File", False },
2821 { "menuMode.Two Machines", False },
2822 { "menuMode.Machine Match", False },
2824 { "menuEngine.Hint", False },
2825 { "menuEngine.Book", False },
2826 { "menuEngine.Move Now", False },
2827 #ifndef OPTIONSDIALOG
2828 { "menuOptions.Periodic Updates", False },
2829 { "menuOptions.Hide Thinking", False },
2830 { "menuOptions.Ponder Next Move", False },
2833 { "menuEngine.Engine #1 Settings", False },
2834 { "menuEngine.Engine #2 Settings", False },
2835 { "menuEngine.Load Engine", False },
2836 { "menuEdit.Annotate", False },
2837 { "menuOptions.Match", False },
2841 Enables ncpEnables[] = {
2842 { "menuFile.Mail Move", False },
2843 { "menuFile.Reload CMail Message", False },
2844 { "menuMode.Machine White", False },
2845 { "menuMode.Machine Black", False },
2846 { "menuMode.Analysis Mode", False },
2847 { "menuMode.Analyze File", False },
2848 { "menuMode.Two Machines", False },
2849 { "menuMode.Machine Match", False },
2850 { "menuMode.ICS Client", False },
2851 { "menuView.ICStex", False },
2852 { "menuView.ICS Input Box", False },
2853 { "Action", False },
2854 { "menuEdit.Revert", False },
2855 { "menuEdit.Annotate", False },
2856 { "menuEngine.Engine #1 Settings", False },
2857 { "menuEngine.Engine #2 Settings", False },
2858 { "menuEngine.Move Now", False },
2859 { "menuEngine.Retract Move", False },
2860 { "menuOptions.ICS", False },
2861 #ifndef OPTIONSDIALOG
2862 { "menuOptions.Auto Flag", False },
2863 { "menuOptions.Auto Flip View", False },
2864 // { "menuOptions.ICS Alarm", False },
2865 { "menuOptions.Move Sound", False },
2866 { "menuOptions.Hide Thinking", False },
2867 { "menuOptions.Periodic Updates", False },
2868 { "menuOptions.Ponder Next Move", False },
2870 { "menuEngine.Hint", False },
2871 { "menuEngine.Book", False },
2875 Enables gnuEnables[] = {
2876 { "menuMode.ICS Client", False },
2877 { "menuView.ICStex", False },
2878 { "menuView.ICS Input Box", False },
2879 { "menuAction.Accept", False },
2880 { "menuAction.Decline", False },
2881 { "menuAction.Rematch", False },
2882 { "menuAction.Adjourn", False },
2883 { "menuAction.Stop Examining", False },
2884 { "menuAction.Stop Observing", False },
2885 { "menuAction.Upload to Examine", False },
2886 { "menuEdit.Revert", False },
2887 { "menuEdit.Annotate", False },
2888 { "menuOptions.ICS", False },
2890 /* The next two options rely on SetCmailMode being called *after* */
2891 /* SetGNUMode so that when GNU is being used to give hints these */
2892 /* menu options are still available */
2894 { "menuFile.Mail Move", False },
2895 { "menuFile.Reload CMail Message", False },
2896 // [HGM] The following have been added to make a switch from ncp to GNU mode possible
2897 { "menuMode.Machine White", True },
2898 { "menuMode.Machine Black", True },
2899 { "menuMode.Analysis Mode", True },
2900 { "menuMode.Analyze File", True },
2901 { "menuMode.Two Machines", True },
2902 { "menuMode.Machine Match", True },
2903 { "menuEngine.Engine #1 Settings", True },
2904 { "menuEngine.Engine #2 Settings", True },
2905 { "menuEngine.Hint", True },
2906 { "menuEngine.Book", True },
2907 { "menuEngine.Move Now", True },
2908 { "menuEngine.Retract Move", True },
2913 Enables cmailEnables[] = {
2915 { "menuAction.Call Flag", False },
2916 { "menuAction.Draw", True },
2917 { "menuAction.Adjourn", False },
2918 { "menuAction.Abort", False },
2919 { "menuAction.Stop Observing", False },
2920 { "menuAction.Stop Examining", False },
2921 { "menuFile.Mail Move", True },
2922 { "menuFile.Reload CMail Message", True },
2926 Enables trainingOnEnables[] = {
2927 { "menuMode.Edit Comment", False },
2928 { "menuMode.Pause", False },
2929 { "menuEdit.Forward", False },
2930 { "menuEdit.Backward", False },
2931 { "menuEdit.Forward to End", False },
2932 { "menuEdit.Back to Start", False },
2933 { "menuEngine.Move Now", False },
2934 { "menuEdit.Truncate Game", False },
2938 Enables trainingOffEnables[] = {
2939 { "menuMode.Edit Comment", True },
2940 { "menuMode.Pause", True },
2941 { "menuEdit.Forward", True },
2942 { "menuEdit.Backward", True },
2943 { "menuEdit.Forward to End", True },
2944 { "menuEdit.Back to Start", True },
2945 { "menuEngine.Move Now", True },
2946 { "menuEdit.Truncate Game", True },
2950 Enables machineThinkingEnables[] = {
2951 { "menuFile.Load Game", False },
2952 // { "menuFile.Load Next Game", False },
2953 // { "menuFile.Load Previous Game", False },
2954 // { "menuFile.Reload Same Game", False },
2955 { "menuEdit.Paste Game", False },
2956 { "menuFile.Load Position", False },
2957 // { "menuFile.Load Next Position", False },
2958 // { "menuFile.Load Previous Position", False },
2959 // { "menuFile.Reload Same Position", False },
2960 { "menuEdit.Paste Position", False },
2961 { "menuMode.Machine White", False },
2962 { "menuMode.Machine Black", False },
2963 { "menuMode.Two Machines", False },
2964 // { "menuMode.Machine Match", False },
2965 { "menuEngine.Retract Move", False },
2969 Enables userThinkingEnables[] = {
2970 { "menuFile.Load Game", True },
2971 // { "menuFile.Load Next Game", True },
2972 // { "menuFile.Load Previous Game", True },
2973 // { "menuFile.Reload Same Game", True },
2974 { "menuEdit.Paste Game", True },
2975 { "menuFile.Load Position", True },
2976 // { "menuFile.Load Next Position", True },
2977 // { "menuFile.Load Previous Position", True },
2978 // { "menuFile.Reload Same Position", True },
2979 { "menuEdit.Paste Position", True },
2980 { "menuMode.Machine White", True },
2981 { "menuMode.Machine Black", True },
2982 { "menuMode.Two Machines", True },
2983 // { "menuMode.Machine Match", True },
2984 { "menuEngine.Retract Move", True },
2990 SetMenuEnables(icsEnables);
2993 if (appData.zippyPlay && !appData.noChessProgram) { /* [DM] icsEngineAnalyze */
2994 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2995 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuEngine.Engine #1 Settings"), True);
3003 SetMenuEnables(ncpEnables);
3009 SetMenuEnables(gnuEnables);
3015 SetMenuEnables(cmailEnables);
3021 SetMenuEnables(trainingOnEnables);
3022 if (appData.showButtonBar) {
3023 XtSetSensitive(buttonBarWidget, False);
3029 SetTrainingModeOff()
3031 SetMenuEnables(trainingOffEnables);
3032 if (appData.showButtonBar) {
3033 XtSetSensitive(buttonBarWidget, True);
3038 SetUserThinkingEnables()
3040 if (appData.noChessProgram) return;
3041 SetMenuEnables(userThinkingEnables);
3045 SetMachineThinkingEnables()
3047 if (appData.noChessProgram) return;
3048 SetMenuEnables(machineThinkingEnables);
3050 case MachinePlaysBlack:
3051 case MachinePlaysWhite:
3052 case TwoMachinesPlay:
3053 XtSetSensitive(XtNameToWidget(menuBarWidget,
3054 ModeToWidgetName(gameMode)), True);
3061 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
3062 #define HISTORY_SIZE 64
3063 static char *history[HISTORY_SIZE];
3064 int histIn = 0, histP = 0;
3067 SaveInHistory(char *cmd)
3069 if (history[histIn] != NULL) {
3070 free(history[histIn]);
3071 history[histIn] = NULL;
3073 if (*cmd == NULLCHAR) return;
3074 history[histIn] = StrSave(cmd);
3075 histIn = (histIn + 1) % HISTORY_SIZE;
3076 if (history[histIn] != NULL) {
3077 free(history[histIn]);
3078 history[histIn] = NULL;
3084 PrevInHistory(char *cmd)
3087 if (histP == histIn) {
3088 if (history[histIn] != NULL) free(history[histIn]);
3089 history[histIn] = StrSave(cmd);
3091 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
3092 if (newhp == histIn || history[newhp] == NULL) return NULL;
3094 return history[histP];
3100 if (histP == histIn) return NULL;
3101 histP = (histP + 1) % HISTORY_SIZE;
3102 return history[histP];
3104 // end of borrowed code
3106 #define Abs(n) ((n)<0 ? -(n) : (n))
3110 InsertPxlSize(pattern, targetPxlSize)
3114 char *base_fnt_lst, strInt[3], *p;
3116 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3117 snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
3118 p = strstr(pattern, "--");
3120 /* Can't insert size; use string as-is */
3123 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3124 strcat(base_fnt_lst, strInt);
3125 strcat(base_fnt_lst, strchr(p + 2, '-'));
3126 return base_fnt_lst;
3130 CreateFontSet(base_fnt_lst)
3134 char **missing_list;
3138 fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
3139 &missing_list, &missing_count, &def_string);
3140 if (missing_count > 0 && appData.debugMode) {
3142 for (i = 0; i < missing_count; i++) {
3143 fprintf(debugFP, _("Missing charset %s for %s (usually harmless)\n"),
3144 missing_list[i], base_fnt_lst);
3147 if (fntSet == NULL) {
3148 fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
3153 #else // not ENABLE_NLS
3155 * Find a font that matches "pattern" that is as close as
3156 * possible to the targetPxlSize. Prefer fonts that are k
3157 * pixels smaller to fonts that are k pixels larger. The
3158 * pattern must be in the X Consortium standard format,
3159 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3160 * The return value should be freed with XtFree when no
3164 FindFont(pattern, targetPxlSize)
3168 char **fonts, *p, *best, *scalable, *scalableTail;
3169 int i, j, nfonts, minerr, err, pxlSize;
3171 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3173 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3174 programName, pattern);
3181 for (i=0; i<nfonts; i++) {
3184 if (*p != '-') continue;
3186 if (*p == NULLCHAR) break;
3187 if (*p++ == '-') j++;
3189 if (j < 7) continue;
3192 scalable = fonts[i];
3195 err = pxlSize - targetPxlSize;
3196 if (Abs(err) < Abs(minerr) ||
3197 (minerr > 0 && err < 0 && -err == minerr)) {
3203 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3204 /* If the error is too big and there is a scalable font,
3205 use the scalable font. */
3206 int headlen = scalableTail - scalable;
3207 p = (char *) XtMalloc(strlen(scalable) + 10);
3208 while (isdigit(*scalableTail)) scalableTail++;
3209 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3211 p = (char *) XtMalloc(strlen(best) + 2);
3212 safeStrCpy(p, best, strlen(best)+1 );
3214 if (appData.debugMode) {
3215 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3216 pattern, targetPxlSize, p);
3218 XFreeFontNames(fonts);
3224 { // [HGM] deletes GCs that are to be remade, to prevent resource leak;
3225 // must be called before all non-first callse to CreateGCs()
3226 XtReleaseGC(shellWidget, highlineGC);
3227 XtReleaseGC(shellWidget, lightSquareGC);
3228 XtReleaseGC(shellWidget, darkSquareGC);
3229 XtReleaseGC(shellWidget, lineGC);
3230 if (appData.monoMode) {
3231 if (DefaultDepth(xDisplay, xScreen) == 1) {
3232 XtReleaseGC(shellWidget, wbPieceGC);
3234 XtReleaseGC(shellWidget, bwPieceGC);
3237 XtReleaseGC(shellWidget, prelineGC);
3238 XtReleaseGC(shellWidget, jailSquareGC);
3239 XtReleaseGC(shellWidget, wdPieceGC);
3240 XtReleaseGC(shellWidget, wlPieceGC);
3241 XtReleaseGC(shellWidget, wjPieceGC);
3242 XtReleaseGC(shellWidget, bdPieceGC);
3243 XtReleaseGC(shellWidget, blPieceGC);
3244 XtReleaseGC(shellWidget, bjPieceGC);
3248 void CreateGCs(int redo)
3250 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3251 | GCBackground | GCFunction | GCPlaneMask;
3252 XGCValues gc_values;
3255 gc_values.plane_mask = AllPlanes;
3256 gc_values.line_width = lineGap;
3257 gc_values.line_style = LineSolid;
3258 gc_values.function = GXcopy;
3261 DeleteGCs(); // called a second time; clean up old GCs first
3262 } else { // [HGM] grid and font GCs created on first call only
3263 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3264 gc_values.background = XWhitePixel(xDisplay, xScreen);
3265 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3266 XSetFont(xDisplay, coordGC, coordFontID);
3268 // [HGM] make font for holdings counts (white on black)
3269 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3270 gc_values.background = XBlackPixel(xDisplay, xScreen);
3271 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3272 XSetFont(xDisplay, countGC, countFontID);
3274 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3275 gc_values.background = XBlackPixel(xDisplay, xScreen);
3276 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3278 if (appData.monoMode) {
3279 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3280 gc_values.background = XWhitePixel(xDisplay, xScreen);
3281 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3283 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3284 gc_values.background = XBlackPixel(xDisplay, xScreen);
3285 lightSquareGC = wbPieceGC
3286 = XtGetGC(shellWidget, value_mask, &gc_values);
3288 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3289 gc_values.background = XWhitePixel(xDisplay, xScreen);
3290 darkSquareGC = bwPieceGC
3291 = XtGetGC(shellWidget, value_mask, &gc_values);
3293 if (DefaultDepth(xDisplay, xScreen) == 1) {
3294 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3295 gc_values.function = GXcopyInverted;
3296 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3297 gc_values.function = GXcopy;
3298 if (XBlackPixel(xDisplay, xScreen) == 1) {
3299 bwPieceGC = darkSquareGC;
3300 wbPieceGC = copyInvertedGC;
3302 bwPieceGC = copyInvertedGC;
3303 wbPieceGC = lightSquareGC;
3307 gc_values.foreground = highlightSquareColor;
3308 gc_values.background = highlightSquareColor;
3309 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3311 gc_values.foreground = premoveHighlightColor;
3312 gc_values.background = premoveHighlightColor;
3313 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3315 gc_values.foreground = lightSquareColor;
3316 gc_values.background = darkSquareColor;
3317 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3319 gc_values.foreground = darkSquareColor;
3320 gc_values.background = lightSquareColor;
3321 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3323 gc_values.foreground = jailSquareColor;
3324 gc_values.background = jailSquareColor;
3325 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3327 gc_values.foreground = whitePieceColor;
3328 gc_values.background = darkSquareColor;
3329 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3331 gc_values.foreground = whitePieceColor;
3332 gc_values.background = lightSquareColor;
3333 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3335 gc_values.foreground = whitePieceColor;
3336 gc_values.background = jailSquareColor;
3337 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3339 gc_values.foreground = blackPieceColor;
3340 gc_values.background = darkSquareColor;
3341 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3343 gc_values.foreground = blackPieceColor;
3344 gc_values.background = lightSquareColor;
3345 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3347 gc_values.foreground = blackPieceColor;
3348 gc_values.background = jailSquareColor;
3349 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3353 void loadXIM(xim, xmask, filename, dest, mask)
3366 fp = fopen(filename, "rb");
3368 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3375 for (y=0; y<h; ++y) {
3376 for (x=0; x<h; ++x) {
3381 XPutPixel(xim, x, y, blackPieceColor);
3383 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3386 XPutPixel(xim, x, y, darkSquareColor);
3388 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3391 XPutPixel(xim, x, y, whitePieceColor);
3393 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3396 XPutPixel(xim, x, y, lightSquareColor);
3398 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3406 /* create Pixmap of piece */
3407 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3409 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3412 /* create Pixmap of clipmask
3413 Note: We assume the white/black pieces have the same
3414 outline, so we make only 6 masks. This is okay
3415 since the XPM clipmask routines do the same. */
3417 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3419 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3422 /* now create the 1-bit version */
3423 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3426 values.foreground = 1;
3427 values.background = 0;
3429 /* Don't use XtGetGC, not read only */
3430 maskGC = XCreateGC(xDisplay, *mask,
3431 GCForeground | GCBackground, &values);
3432 XCopyPlane(xDisplay, temp, *mask, maskGC,
3433 0, 0, squareSize, squareSize, 0, 0, 1);
3434 XFreePixmap(xDisplay, temp);
3439 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3441 void CreateXIMPieces()
3446 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3451 /* The XSynchronize calls were copied from CreatePieces.
3452 Not sure if needed, but can't hurt */
3453 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3456 /* temp needed by loadXIM() */
3457 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3458 0, 0, ss, ss, AllPlanes, XYPixmap);
3460 if (strlen(appData.pixmapDirectory) == 0) {
3464 if (appData.monoMode) {
3465 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3469 fprintf(stderr, _("\nLoading XIMs...\n"));
3471 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3472 fprintf(stderr, "%d", piece+1);
3473 for (kind=0; kind<4; kind++) {
3474 fprintf(stderr, ".");
3475 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3476 ExpandPathName(appData.pixmapDirectory),
3477 piece <= (int) WhiteKing ? "" : "w",
3478 pieceBitmapNames[piece],
3480 ximPieceBitmap[kind][piece] =
3481 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3482 0, 0, ss, ss, AllPlanes, XYPixmap);
3483 if (appData.debugMode)
3484 fprintf(stderr, _("(File:%s:) "), buf);
3485 loadXIM(ximPieceBitmap[kind][piece],
3487 &(xpmPieceBitmap2[kind][piece]),
3488 &(ximMaskPm2[piece]));
3489 if(piece <= (int)WhiteKing)
3490 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3492 fprintf(stderr," ");
3494 /* Load light and dark squares */
3495 /* If the LSQ and DSQ pieces don't exist, we will
3496 draw them with solid squares. */
3497 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3498 if (access(buf, 0) != 0) {
3502 fprintf(stderr, _("light square "));
3504 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3505 0, 0, ss, ss, AllPlanes, XYPixmap);
3506 if (appData.debugMode)
3507 fprintf(stderr, _("(File:%s:) "), buf);
3509 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3510 fprintf(stderr, _("dark square "));
3511 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3512 ExpandPathName(appData.pixmapDirectory), ss);
3513 if (appData.debugMode)
3514 fprintf(stderr, _("(File:%s:) "), buf);
3516 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3517 0, 0, ss, ss, AllPlanes, XYPixmap);
3518 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3519 xpmJailSquare = xpmLightSquare;
3521 fprintf(stderr, _("Done.\n"));
3523 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3526 static VariantClass oldVariant = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
3529 void CreateXPMBoard(char *s, int kind)
3533 if(s == NULL || *s == 0 || *s == '*') { useTexture &= ~(kind+1); return; }
3534 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3535 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3539 void FreeXPMPieces()
3540 { // [HGM] to prevent resoucre leak on calling CreaeXPMPieces() a second time,
3541 // thisroutine has to be called t free the old piece pixmaps
3543 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++)
3544 for (kind=0; kind<4; kind++) XFreePixmap(xDisplay, xpmPieceBitmap2[kind][piece]);
3546 XFreePixmap(xDisplay, xpmLightSquare);
3547 XFreePixmap(xDisplay, xpmDarkSquare);
3551 void CreateXPMPieces()
3555 u_int ss = squareSize;
3557 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3558 XpmColorSymbol symbols[4];
3559 static int redo = False;
3561 if(redo) FreeXPMPieces(); else redo = 1;
3563 /* The XSynchronize calls were copied from CreatePieces.
3564 Not sure if needed, but can't hurt */
3565 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3567 /* Setup translations so piece colors match square colors */
3568 symbols[0].name = "light_piece";
3569 symbols[0].value = appData.whitePieceColor;
3570 symbols[1].name = "dark_piece";
3571 symbols[1].value = appData.blackPieceColor;
3572 symbols[2].name = "light_square";
3573 symbols[2].value = appData.lightSquareColor;
3574 symbols[3].name = "dark_square";
3575 symbols[3].value = appData.darkSquareColor;
3577 attr.valuemask = XpmColorSymbols;
3578 attr.colorsymbols = symbols;
3579 attr.numsymbols = 4;
3581 if (appData.monoMode) {
3582 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3586 if (strlen(appData.pixmapDirectory) == 0) {
3587 XpmPieces* pieces = builtInXpms;
3590 while (pieces->size != squareSize && pieces->size) pieces++;
3591 if (!pieces->size) {
3592 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3595 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3596 for (kind=0; kind<4; kind++) {
3598 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3599 pieces->xpm[piece][kind],
3600 &(xpmPieceBitmap2[kind][piece]),
3601 NULL, &attr)) != 0) {
3602 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3606 if(piece <= (int) WhiteKing)
3607 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3611 xpmJailSquare = xpmLightSquare;
3615 fprintf(stderr, _("\nLoading XPMs...\n"));
3618 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3619 fprintf(stderr, "%d ", piece+1);
3620 for (kind=0; kind<4; kind++) {
3621 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3622 ExpandPathName(appData.pixmapDirectory),
3623 piece > (int) WhiteKing ? "w" : "",
3624 pieceBitmapNames[piece],
3626 if (appData.debugMode) {
3627 fprintf(stderr, _("(File:%s:) "), buf);
3629 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3630 &(xpmPieceBitmap2[kind][piece]),
3631 NULL, &attr)) != 0) {
3632 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3633 // [HGM] missing: read of unorthodox piece failed; substitute King.
3634 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3635 ExpandPathName(appData.pixmapDirectory),