2 * xboard.c -- X front end for XBoard
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
8 * 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
10 * The following terms apply to Digital Equipment Corporation's copyright
12 * ------------------------------------------------------------------------
15 * Permission to use, copy, modify, and distribute this software and its
16 * documentation for any purpose and without fee is hereby granted,
17 * provided that the above copyright notice appear in all copies and that
18 * both that copyright notice and this permission notice appear in
19 * supporting documentation, and that the name of Digital not be
20 * used in advertising or publicity pertaining to distribution of the
21 * software without specific, written prior permission.
23 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
30 * ------------------------------------------------------------------------
32 * The following terms apply to the enhanced version of XBoard
33 * distributed by the Free Software Foundation:
34 * ------------------------------------------------------------------------
36 * GNU XBoard is free software: you can redistribute it and/or modify
37 * it under the terms of the GNU General Public License as published by
38 * the Free Software Foundation, either version 3 of the License, or (at
39 * your option) any later version.
41 * GNU XBoard is distributed in the hope that it will be useful, but
42 * WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44 * General Public License for more details.
46 * You should have received a copy of the GNU General Public License
47 * along with this program. If not, see http://www.gnu.org/licenses/. *
49 *------------------------------------------------------------------------
50 ** See the file ChangeLog for a revision history. */
60 #include <sys/types.h>
66 # if HAVE_SYS_SOCKET_H
67 # include <sys/socket.h>
68 # include <netinet/in.h>
70 # else /* not HAVE_SYS_SOCKET_H */
71 # if HAVE_LAN_SOCKET_H
72 # include <lan/socket.h>
74 # include <lan/netdb.h>
75 # else /* not HAVE_LAN_SOCKET_H */
76 # define OMIT_SOCKETS 1
77 # endif /* not HAVE_LAN_SOCKET_H */
78 # endif /* not HAVE_SYS_SOCKET_H */
79 #endif /* !OMIT_SOCKETS */
84 #else /* not STDC_HEADERS */
85 extern char *getenv();
88 # else /* not HAVE_STRING_H */
90 # endif /* not HAVE_STRING_H */
91 #endif /* not STDC_HEADERS */
94 # include <sys/fcntl.h>
95 #else /* not HAVE_SYS_FCNTL_H */
98 # endif /* HAVE_FCNTL_H */
99 #endif /* not HAVE_SYS_FCNTL_H */
101 #if HAVE_SYS_SYSTEMINFO_H
102 # include <sys/systeminfo.h>
103 #endif /* HAVE_SYS_SYSTEMINFO_H */
105 #if TIME_WITH_SYS_TIME
106 # include <sys/time.h>
110 # include <sys/time.h>
121 # include <sys/wait.h>
126 # define NAMLEN(dirent) strlen((dirent)->d_name)
127 # define HAVE_DIR_STRUCT
129 # define dirent direct
130 # define NAMLEN(dirent) (dirent)->d_namlen
132 # include <sys/ndir.h>
133 # define HAVE_DIR_STRUCT
136 # include <sys/dir.h>
137 # define HAVE_DIR_STRUCT
141 # define HAVE_DIR_STRUCT
149 #include <X11/Intrinsic.h>
150 #include <X11/StringDefs.h>
151 #include <X11/Shell.h>
152 #include <X11/cursorfont.h>
153 #include <X11/Xatom.h>
154 #include <X11/Xmu/Atoms.h>
156 #include <X11/Xaw3d/Dialog.h>
157 #include <X11/Xaw3d/Form.h>
158 #include <X11/Xaw3d/List.h>
159 #include <X11/Xaw3d/Label.h>
160 #include <X11/Xaw3d/SimpleMenu.h>
161 #include <X11/Xaw3d/SmeBSB.h>
162 #include <X11/Xaw3d/SmeLine.h>
163 #include <X11/Xaw3d/Box.h>
164 #include <X11/Xaw3d/MenuButton.h>
165 #include <X11/Xaw3d/Text.h>
166 #include <X11/Xaw3d/AsciiText.h>
168 #include <X11/Xaw/Dialog.h>
169 #include <X11/Xaw/Form.h>
170 #include <X11/Xaw/List.h>
171 #include <X11/Xaw/Label.h>
172 #include <X11/Xaw/SimpleMenu.h>
173 #include <X11/Xaw/SmeBSB.h>
174 #include <X11/Xaw/SmeLine.h>
175 #include <X11/Xaw/Box.h>
176 #include <X11/Xaw/MenuButton.h>
177 #include <X11/Xaw/Text.h>
178 #include <X11/Xaw/AsciiText.h>
181 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
186 #include "pixmaps/pixmaps.h"
187 #define IMAGE_EXT "xpm"
189 #define IMAGE_EXT "xim"
190 #include "bitmaps/bitmaps.h"
193 #include "bitmaps/icon_white.bm"
194 #include "bitmaps/icon_black.bm"
195 #include "bitmaps/checkmark.bm"
197 #include "frontend.h"
199 #include "backendz.h"
203 #include "xgamelist.h"
204 #include "xhistory.h"
205 #include "xedittags.h"
208 // must be moved to xengineoutput.h
210 void EngineOutputProc P((Widget w, XEvent *event,
211 String *prms, Cardinal *nprms));
212 void EvalGraphProc P((Widget w, XEvent *event,
213 String *prms, Cardinal *nprms));
220 #define usleep(t) _sleep2(((t)+500)/1000)
224 # define _(s) gettext (s)
225 # define N_(s) gettext_noop (s)
245 int main P((int argc, char **argv));
246 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
247 char *init_path, char *filter, char *mode, int (*show_entry)(), char **name_return));
248 RETSIGTYPE CmailSigHandler P((int sig));
249 RETSIGTYPE IntSigHandler P((int sig));
250 RETSIGTYPE TermSizeSigHandler P((int sig));
251 void CreateGCs P((int redo));
252 void CreateAnyPieces P((void));
253 void CreateXIMPieces P((void));
254 void CreateXPMPieces P((void));
255 void CreateXPMBoard P((char *s, int n));
256 void CreatePieces P((void));
257 void CreatePieceMenus P((void));
258 Widget CreateMenuBar P((Menu *mb, int boardWidth));
259 Widget CreateButtonBar P ((MenuItem *mi));
261 char *InsertPxlSize P((char *pattern, int targetPxlSize));
262 XFontSet CreateFontSet P((char *base_fnt_lst));
264 char *FindFont P((char *pattern, int targetPxlSize));
266 void PieceMenuPopup P((Widget w, XEvent *event,
267 String *params, Cardinal *num_params));
268 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
269 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
270 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
271 u_int wreq, u_int hreq));
272 void CreateGrid P((void));
273 int EventToSquare P((int x, int limit));
274 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
275 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
276 void DelayedDrag P((void));
277 void MoveTypeInProc P((Widget widget, caddr_t unused, XEvent *event));
278 void HandleUserMove P((Widget w, XEvent *event,
279 String *prms, Cardinal *nprms));
280 void AnimateUserMove P((Widget w, XEvent * event,
281 String * params, Cardinal * nParams));
282 void HandlePV P((Widget w, XEvent * event,
283 String * params, Cardinal * nParams));
284 void SelectPV P((Widget w, XEvent * event,
285 String * params, Cardinal * nParams));
286 void StopPV P((Widget w, XEvent * event,
287 String * params, Cardinal * nParams));
288 void WhiteClock P((Widget w, XEvent *event,
289 String *prms, Cardinal *nprms));
290 void BlackClock P((Widget w, XEvent *event,
291 String *prms, Cardinal *nprms));
292 void DrawPositionProc P((Widget w, XEvent *event,
293 String *prms, Cardinal *nprms));
294 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
296 void CommentClick P((Widget w, XEvent * event,
297 String * params, Cardinal * nParams));
298 void CommentPopUp P((char *title, char *label));
299 void CommentPopDown P((void));
300 void ICSInputBoxPopUp P((void));
301 void ICSInputBoxPopDown P((void));
302 void FileNamePopUp P((char *label, char *def, char *filter,
303 FileProc proc, char *openMode));
304 void FileNamePopDown P((void));
305 void FileNameCallback P((Widget w, XtPointer client_data,
306 XtPointer call_data));
307 void FileNameAction P((Widget w, XEvent *event,
308 String *prms, Cardinal *nprms));
309 void AskQuestionReplyAction P((Widget w, XEvent *event,
310 String *prms, Cardinal *nprms));
311 void AskQuestionProc P((Widget w, XEvent *event,
312 String *prms, Cardinal *nprms));
313 void AskQuestionPopDown P((void));
314 void PromotionPopDown P((void));
315 void PromotionCallback P((Widget w, XtPointer client_data,
316 XtPointer call_data));
317 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
318 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
319 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
320 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
322 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
324 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
326 void LoadPositionProc P((Widget w, XEvent *event,
327 String *prms, Cardinal *nprms));
328 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
330 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
332 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
334 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
336 void PastePositionProc P((Widget w, XEvent *event, String *prms,
338 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
339 void CopyGameListProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
340 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
341 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
342 void SavePositionProc P((Widget w, XEvent *event,
343 String *prms, Cardinal *nprms));
344 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
345 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
347 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
348 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
349 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
351 void MachineWhiteProc P((Widget w, XEvent *event,
352 String *prms, Cardinal *nprms));
353 void AnalyzeModeProc P((Widget w, XEvent *event,
354 String *prms, Cardinal *nprms));
355 void AnalyzeFileProc P((Widget w, XEvent *event,
356 String *prms, Cardinal *nprms));
357 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
359 void MatchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void MatchOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void IcsClientProc P((Widget w, XEvent *event, String *prms,
363 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void EditPositionProc P((Widget w, XEvent *event,
365 String *prms, Cardinal *nprms));
366 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void EditCommentProc P((Widget w, XEvent *event,
368 String *prms, Cardinal *nprms));
369 void IcsInputBoxProc P((Widget w, XEvent *event,
370 String *prms, Cardinal *nprms));
371 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
372 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
373 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
374 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
375 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
376 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
377 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
379 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
380 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void TypeInProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
384 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
385 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
386 void StopObservingProc P((Widget w, XEvent *event, String *prms,
388 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
390 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
391 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
392 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
393 void TempBackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
394 void TempForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
395 Boolean TempBackwardActive = False;
396 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
397 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
398 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
399 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
400 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
402 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
404 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
405 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
407 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
409 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
411 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
412 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
413 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
414 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
416 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
417 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
419 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
421 void HighlightArrowProc P((Widget w, XEvent *event, String *prms,
423 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
424 //void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
425 void OneClickProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
426 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
428 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
430 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
432 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
434 //void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
435 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
437 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
439 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
441 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
443 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
444 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
445 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
446 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
447 void GuideProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
448 void HomePageProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
449 void NewsPageProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
450 void BugReportProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
451 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
452 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
453 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
454 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
455 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
456 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
457 void DisplayMove P((int moveNumber));
458 void DisplayTitle P((char *title));
459 void ICSInitScript P((void));
460 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
461 void ErrorPopUp P((char *title, char *text, int modal));
462 void ErrorPopDown P((void));
463 static char *ExpandPathName P((char *path));
464 static void CreateAnimVars P((void));
465 static void DragPieceMove P((int x, int y));
466 static void DrawDragPiece P((void));
467 char *ModeToWidgetName P((GameMode mode));
468 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
469 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
470 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
471 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
472 void OptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
473 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
474 void IcsTextProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
475 void LoadEngineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
476 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
477 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
478 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
479 void IcsOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
480 void SoundOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
481 void BoardOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
482 void LoadOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
483 void SaveOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
484 void EditBookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
485 void SelectMove P((Widget w, XEvent * event, String * params, Cardinal * nParams));
486 void GameListOptionsPopDown P(());
487 void GenericPopDown P(());
488 void update_ics_width P(());
489 int get_term_width P(());
490 int CopyMemoProc P(());
491 void DrawArrowHighlight P((int fromX, int fromY, int toX,int toY));
492 Boolean IsDrawArrowEnabled P(());
495 * XBoard depends on Xt R4 or higher
497 int xtVersion = XtSpecificationRelease;
502 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
503 jailSquareColor, highlightSquareColor, premoveHighlightColor;
504 Pixel lowTimeWarningColor;
505 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
506 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
507 wjPieceGC, bjPieceGC, prelineGC, countGC;
508 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
509 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
510 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
511 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
512 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
513 ICSInputShell, fileNameShell, askQuestionShell;
514 Widget historyShell, evalGraphShell, gameListShell;
515 int hOffset; // [HGM] dual
516 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
517 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
518 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
520 XFontSet fontSet, clockFontSet;
523 XFontStruct *clockFontStruct;
525 Font coordFontID, countFontID;
526 XFontStruct *coordFontStruct, *countFontStruct;
527 XtAppContext appContext;
529 char *oldICSInteractionTitle;
533 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
535 Position commentX = -1, commentY = -1;
536 Dimension commentW, commentH;
537 typedef unsigned int BoardSize;
539 Boolean chessProgram;
541 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
542 int squareSize, smallLayout = 0, tinyLayout = 0,
543 marginW, marginH, // [HGM] for run-time resizing
544 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
545 ICSInputBoxUp = False, askQuestionUp = False,
546 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
547 errorUp = False, errorExitStatus = -1, lineGap, defaultLineGap;
548 Dimension textHeight;
549 Pixel timerForegroundPixel, timerBackgroundPixel;
550 Pixel buttonForegroundPixel, buttonBackgroundPixel;
551 char *chessDir, *programName, *programVersion,
552 *gameCopyFilename, *gamePasteFilename;
553 Boolean alwaysOnTop = False;
554 Boolean saveSettingsOnExit;
555 char *settingsFileName;
556 char *icsTextMenuString;
558 char *firstChessProgramNames;
559 char *secondChessProgramNames;
561 WindowPlacement wpMain;
562 WindowPlacement wpConsole;
563 WindowPlacement wpComment;
564 WindowPlacement wpMoveHistory;
565 WindowPlacement wpEvalGraph;
566 WindowPlacement wpEngineOutput;
567 WindowPlacement wpGameList;
568 WindowPlacement wpTags;
570 extern Widget shells[];
571 extern Boolean shellUp[];
575 Pixmap pieceBitmap[2][(int)BlackPawn];
576 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
577 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
578 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
579 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
580 Pixmap xpmBoardBitmap[2];
581 int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
582 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
583 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
584 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
585 XImage *ximLightSquare, *ximDarkSquare;
588 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
589 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
591 #define White(piece) ((int)(piece) < (int)BlackPawn)
593 /* Variables for doing smooth animation. This whole thing
594 would be much easier if the board was double-buffered,
595 but that would require a fairly major rewrite. */
600 GC blitGC, pieceGC, outlineGC;
601 XPoint startSquare, prevFrame, mouseDelta;
605 int startBoardX, startBoardY;
608 /* There can be two pieces being animated at once: a player
609 can begin dragging a piece before the remote opponent has moved. */
611 static AnimState game, player;
613 /* Bitmaps for use as masks when drawing XPM pieces.
614 Need one for each black and white piece. */
615 static Pixmap xpmMask[BlackKing + 1];
617 /* This magic number is the number of intermediate frames used
618 in each half of the animation. For short moves it's reduced
619 by 1. The total number of frames will be factor * 2 + 1. */
622 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
624 MenuItem fileMenu[] = {
625 {N_("New Game Ctrl+N"), "New Game", ResetProc},
626 {N_("New Shuffle Game ..."), "New Shuffle Game", ShuffleMenuProc},
627 {N_("New Variant ... Alt+Shift+V"), "New Variant", NewVariantProc}, // [HGM] variant: not functional yet
628 {"----", NULL, NothingProc},
629 {N_("Load Game Ctrl+O"), "Load Game", LoadGameProc},
630 {N_("Load Position Ctrl+Shift+O"), "Load Position", LoadPositionProc},
631 // {N_("Load Next Game"), "Load Next Game", LoadNextGameProc},
632 // {N_("Load Previous Game"), "Load Previous Game", LoadPrevGameProc},
633 // {N_("Reload Same Game"), "Reload Same Game", ReloadGameProc},
634 {N_("Next Position Shift+PgDn"), "Load Next Position", LoadNextPositionProc},
635 {N_("Prev Position Shift+PgUp"), "Load Previous Position", LoadPrevPositionProc},
636 {"----", NULL, NothingProc},
637 // {N_("Reload Same Position"), "Reload Same Position", ReloadPositionProc},
638 {N_("Save Game Ctrl+S"), "Save Game", SaveGameProc},
639 {N_("Save Position Ctrl+Shift+S"), "Save Position", SavePositionProc},
640 {"----", NULL, NothingProc},
641 {N_("Mail Move"), "Mail Move", MailMoveProc},
642 {N_("Reload CMail Message"), "Reload CMail Message", ReloadCmailMsgProc},
643 {"----", NULL, NothingProc},
644 {N_("Quit Ctr+Q"), "Exit", QuitProc},
648 MenuItem editMenu[] = {
649 {N_("Copy Game Ctrl+C"), "Copy Game", CopyGameProc},
650 {N_("Copy Position Ctrl+Shift+C"), "Copy Position", CopyPositionProc},
651 {N_("Copy Game List"), "Copy Game List", CopyGameListProc},
652 {"----", NULL, NothingProc},
653 {N_("Paste Game Ctrl+V"), "Paste Game", PasteGameProc},
654 {N_("Paste Position Ctrl+Shift+V"), "Paste Position", PastePositionProc},
655 {"----", NULL, NothingProc},
656 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
657 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
658 {N_("Edit Tags"), "Edit Tags", EditTagsProc},
659 {N_("Edit Comment"), "Edit Comment", EditCommentProc},
660 {N_("Edit Book"), "Edit Book", EditBookProc},
661 {"----", NULL, NothingProc},
662 {N_("Revert Home"), "Revert", RevertProc},
663 {N_("Annotate"), "Annotate", AnnotateProc},
664 {N_("Truncate Game End"), "Truncate Game", TruncateGameProc},
665 {"----", NULL, NothingProc},
666 {N_("Backward Alt+Left"), "Backward", BackwardProc},
667 {N_("Forward Alt+Right"), "Forward", ForwardProc},
668 {N_("Back to Start Alt+Home"), "Back to Start", ToStartProc},
669 {N_("Forward to End Alt+End"), "Forward to End", ToEndProc},
673 MenuItem viewMenu[] = {
674 {N_("Flip View F2"), "Flip View", FlipViewProc},
675 {"----", NULL, NothingProc},
676 {N_("Engine Output Alt+Shift+O"), "Show Engine Output", EngineOutputProc},
677 {N_("Move History Alt+Shift+H"), "Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
678 {N_("Evaluation Graph Alt+Shift+E"), "Show Evaluation Graph", EvalGraphProc},
679 {N_("Game List Alt+Shift+G"), "Show Game List", ShowGameListProc},
680 {N_("ICS text menu"), "ICStex", IcsTextProc},
681 {"----", NULL, NothingProc},
682 {N_("Tags"), "Show Tags", EditTagsProc},
683 {N_("Comments"), "Show Comments", EditCommentProc},
684 {N_("ICS Input Box"), "ICS Input Box", IcsInputBoxProc},
685 {"----", NULL, NothingProc},
686 {N_("Board..."), "Board Options", BoardOptionsProc},
687 {N_("Game List Tags..."), "Game List", GameListOptionsPopUp},
691 MenuItem modeMenu[] = {
692 {N_("Machine White Ctrl+W"), "Machine White", MachineWhiteProc},
693 {N_("Machine Black Ctrl+B"), "Machine Black", MachineBlackProc},
694 {N_("Two Machines Ctrl+T"), "Two Machines", TwoMachinesProc},
695 {N_("Analysis Mode Ctrl+A"), "Analysis Mode", AnalyzeModeProc},
696 {N_("Analyze Game Ctrl+G"), "Analyze File", AnalyzeFileProc },
697 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
698 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
699 {N_("Training"), "Training", TrainingProc},
700 {N_("ICS Client"), "ICS Client", IcsClientProc},
701 {"----", NULL, NothingProc},
702 {N_("Machine Match"), "Machine Match", MatchProc},
703 {N_("Pause Pause"), "Pause", PauseProc},
707 MenuItem actionMenu[] = {
708 {N_("Accept F3"), "Accept", AcceptProc},
709 {N_("Decline F4"), "Decline", DeclineProc},
710 {N_("Rematch F12"), "Rematch", RematchProc},
711 {"----", NULL, NothingProc},
712 {N_("Call Flag F5"), "Call Flag", CallFlagProc},
713 {N_("Draw F6"), "Draw", DrawProc},
714 {N_("Adjourn F7"), "Adjourn", AdjournProc},
715 {N_("Abort F8"),"Abort", AbortProc},
716 {N_("Resign F9"), "Resign", ResignProc},
717 {"----", NULL, NothingProc},
718 {N_("Stop Observing F10"), "Stop Observing", StopObservingProc},
719 {N_("Stop Examining F11"), "Stop Examining", StopExaminingProc},
720 {N_("Upload to Examine"), "Upload to Examine", UploadProc},
721 {"----", NULL, NothingProc},
722 {N_("Adjudicate to White"), "Adjudicate to White", AdjuWhiteProc},
723 {N_("Adjudicate to Black"), "Adjudicate to Black", AdjuBlackProc},
724 {N_("Adjudicate Draw"), "Adjudicate Draw", AdjuDrawProc},
728 MenuItem engineMenu[] = {
729 {N_("Load New Engine ..."), "Load Engine", LoadEngineProc},
730 {"----", NULL, NothingProc},
731 {N_("Engine #1 Settings ..."), "Engine #1 Settings", FirstSettingsProc},
732 {N_("Engine #2 Settings ..."), "Engine #2 Settings", SecondSettingsProc},
733 {"----", NULL, NothingProc},
734 {N_("Hint"), "Hint", HintProc},
735 {N_("Book"), "Book", BookProc},
736 {"----", NULL, NothingProc},
737 {N_("Move Now Ctrl+M"), "Move Now", MoveNowProc},
738 {N_("Retract Move Ctrl+X"), "Retract Move", RetractMoveProc},
742 MenuItem optionsMenu[] = {
743 #define OPTIONSDIALOG
745 {N_("General ..."), "General", OptionsProc},
747 {N_("Time Control ... Alt+Shift+T"), "Time Control", TimeControlProc},
748 {N_("Common Engine ... Alt+Shift+U"), "Common Engine", UciMenuProc},
749 {N_("Adjudications ... Alt+Shift+J"), "Adjudications", EngineMenuProc},
750 {N_("ICS ..."), "ICS", IcsOptionsProc},
751 {N_("Match ..."), "Match", MatchOptionsProc},
752 {N_("Load Game ..."), "Load Game", LoadOptionsProc},
753 {N_("Save Game ..."), "Save Game", SaveOptionsProc},
754 // {N_(" ..."), "", OptionsProc},
755 {N_("Game List ..."), "Game List", GameListOptionsPopUp},
756 {N_("Sounds ..."), "Sounds", SoundOptionsProc},
757 {"----", NULL, NothingProc},
758 #ifndef OPTIONSDIALOG
759 {N_("Always Queen Ctrl+Shift+Q"), "Always Queen", AlwaysQueenProc},
760 {N_("Animate Dragging"), "Animate Dragging", AnimateDraggingProc},
761 {N_("Animate Moving Ctrl+Shift+A"), "Animate Moving", AnimateMovingProc},
762 {N_("Auto Flag Ctrl+Shift+F"), "Auto Flag", AutoflagProc},
763 {N_("Auto Flip View"), "Auto Flip View", AutoflipProc},
764 {N_("Blindfold"), "Blindfold", BlindfoldProc},
765 {N_("Flash Moves"), "Flash Moves", FlashMovesProc},
767 {N_("Highlight Dragging"), "Highlight Dragging", HighlightDraggingProc},
769 {N_("Highlight Last Move"), "Highlight Last Move", HighlightLastMoveProc},
770 {N_("Highlight With Arrow"), "Arrow", HighlightArrowProc},
771 {N_("Move Sound"), "Move Sound", MoveSoundProc},
772 // {N_("ICS Alarm"), "ICS Alarm", IcsAlarmProc},
773 {N_("One-Click Moving"), "OneClick", OneClickProc},
774 {N_("Periodic Updates"), "Periodic Updates", PeriodicUpdatesProc},
775 {N_("Ponder Next Move Ctrl+Shift+P"), "Ponder Next Move", PonderNextMoveProc},
776 {N_("Popup Exit Message"), "Popup Exit Message", PopupExitMessageProc},
777 {N_("Popup Move Errors"), "Popup Move Errors", PopupMoveErrorsProc},
778 // {N_("Premove"), "Premove", PremoveProc},
779 {N_("Show Coords"), "Show Coords", ShowCoordsProc},
780 {N_("Hide Thinking Ctrl+Shift+H"), "Hide Thinking", HideThinkingProc},
781 {N_("Test Legality Ctrl+Shift+L"), "Test Legality", TestLegalityProc},
782 {"----", NULL, NothingProc},
784 {N_("Save Settings Now"), "Save Settings Now", SaveSettingsProc},
785 {N_("Save Settings on Exit"), "Save Settings on Exit", SaveOnExitProc},
789 MenuItem helpMenu[] = {
790 {N_("Info XBoard"), "Info XBoard", InfoProc},
791 {N_("Man XBoard F1"), "Man XBoard", ManProc},
792 {"----", NULL, NothingProc},
793 {N_("XBoard Home Page"), "Home Page", HomePageProc},
794 {N_("On-line User Guide"), "User Guide", GuideProc},
795 {N_("Development News"), "News Page", NewsPageProc},
796 {N_("e-Mail Bug Report"), "Bug Report", BugReportProc},
797 {"----", NULL, NothingProc},
798 {N_("About XBoard"), "About XBoard", AboutProc},
803 {N_("File"), "File", fileMenu},
804 {N_("Edit"), "Edit", editMenu},
805 {N_("View"), "View", viewMenu},
806 {N_("Mode"), "Mode", modeMenu},
807 {N_("Action"), "Action", actionMenu},
808 {N_("Engine"), "Engine", engineMenu},
809 {N_("Options"), "Options", optionsMenu},
810 {N_("Help"), "Help", helpMenu},
814 #define PAUSE_BUTTON "P"
815 MenuItem buttonBar[] = {
816 {"<<", "<<", ToStartProc},
817 {"<", "<", BackwardProc},
818 {N_(PAUSE_BUTTON), PAUSE_BUTTON, PauseProc},
819 {">", ">", ForwardProc},
820 {">>", ">>", ToEndProc},
824 #define PIECE_MENU_SIZE 18
825 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
826 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
827 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
828 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
829 N_("Empty square"), N_("Clear board") },
830 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
831 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
832 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
833 N_("Empty square"), N_("Clear board") }
835 /* must be in same order as pieceMenuStrings! */
836 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
837 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
838 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
839 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
840 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
841 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
842 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
843 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
844 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
847 #define DROP_MENU_SIZE 6
848 String dropMenuStrings[DROP_MENU_SIZE] = {
849 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
851 /* must be in same order as dropMenuStrings! */
852 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
853 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
854 WhiteRook, WhiteQueen
862 DropMenuEnables dmEnables[] = {
880 { XtNborderWidth, 0 },
881 { XtNdefaultDistance, 0 },
885 { XtNborderWidth, 0 },
886 { XtNresizable, (XtArgVal) True },
890 { XtNborderWidth, 0 },
896 { XtNjustify, (XtArgVal) XtJustifyRight },
897 { XtNlabel, (XtArgVal) "..." },
898 { XtNresizable, (XtArgVal) True },
899 { XtNresize, (XtArgVal) False }
902 Arg messageArgs[] = {
903 { XtNjustify, (XtArgVal) XtJustifyLeft },
904 { XtNlabel, (XtArgVal) "..." },
905 { XtNresizable, (XtArgVal) True },
906 { XtNresize, (XtArgVal) False }
910 { XtNborderWidth, 0 },
911 { XtNjustify, (XtArgVal) XtJustifyLeft }
914 XtResource clientResources[] = {
915 { "flashCount", "flashCount", XtRInt, sizeof(int),
916 XtOffset(AppDataPtr, flashCount), XtRImmediate,
917 (XtPointer) FLASH_COUNT },
920 XrmOptionDescRec shellOptions[] = {
921 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
922 { "-flash", "flashCount", XrmoptionNoArg, "3" },
923 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
926 XtActionsRec boardActions[] = {
927 { "DrawPosition", DrawPositionProc },
928 { "HandleUserMove", HandleUserMove },
929 { "AnimateUserMove", AnimateUserMove },
930 { "HandlePV", HandlePV },
931 { "SelectPV", SelectPV },
932 { "StopPV", StopPV },
933 { "FileNameAction", FileNameAction },
934 { "AskQuestionProc", AskQuestionProc },
935 { "AskQuestionReplyAction", AskQuestionReplyAction },
936 { "PieceMenuPopup", PieceMenuPopup },
937 { "WhiteClock", WhiteClock },
938 { "BlackClock", BlackClock },
939 { "ResetProc", ResetProc },
940 { "NewVariantProc", NewVariantProc },
941 { "LoadGameProc", LoadGameProc },
942 { "LoadNextGameProc", LoadNextGameProc },
943 { "LoadPrevGameProc", LoadPrevGameProc },
944 { "LoadSelectedProc", LoadSelectedProc },
945 { "SetFilterProc", SetFilterProc },
946 { "ReloadGameProc", ReloadGameProc },
947 { "LoadPositionProc", LoadPositionProc },
948 { "LoadNextPositionProc", LoadNextPositionProc },
949 { "LoadPrevPositionProc", LoadPrevPositionProc },
950 { "ReloadPositionProc", ReloadPositionProc },
951 { "CopyPositionProc", CopyPositionProc },
952 { "PastePositionProc", PastePositionProc },
953 { "CopyGameProc", CopyGameProc },
954 { "CopyGameListProc", CopyGameListProc },
955 { "PasteGameProc", PasteGameProc },
956 { "SaveGameProc", SaveGameProc },
957 { "SavePositionProc", SavePositionProc },
958 { "MailMoveProc", MailMoveProc },
959 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
960 { "QuitProc", QuitProc },
961 { "MachineWhiteProc", MachineWhiteProc },
962 { "MachineBlackProc", MachineBlackProc },
963 { "AnalysisModeProc", AnalyzeModeProc },
964 { "AnalyzeFileProc", AnalyzeFileProc },
965 { "TwoMachinesProc", TwoMachinesProc },
966 { "IcsClientProc", IcsClientProc },
967 { "EditGameProc", EditGameProc },
968 { "EditPositionProc", EditPositionProc },
969 { "TrainingProc", EditPositionProc },
970 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
971 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
972 { "ShowGameListProc", ShowGameListProc },
973 { "ShowMoveListProc", HistoryShowProc},
974 { "EditTagsProc", EditTagsProc },
975 { "EditBookProc", EditBookProc },
976 { "EditCommentProc", EditCommentProc },
977 { "IcsInputBoxProc", IcsInputBoxProc },
978 { "PauseProc", PauseProc },
979 { "AcceptProc", AcceptProc },
980 { "DeclineProc", DeclineProc },
981 { "RematchProc", RematchProc },
982 { "CallFlagProc", CallFlagProc },
983 { "DrawProc", DrawProc },
984 { "AdjournProc", AdjournProc },
985 { "AbortProc", AbortProc },
986 { "ResignProc", ResignProc },
987 { "AdjuWhiteProc", AdjuWhiteProc },
988 { "AdjuBlackProc", AdjuBlackProc },
989 { "AdjuDrawProc", AdjuDrawProc },
990 { "TypeInProc", TypeInProc },
991 { "EnterKeyProc", EnterKeyProc },
992 { "UpKeyProc", UpKeyProc },
993 { "DownKeyProc", DownKeyProc },
994 { "StopObservingProc", StopObservingProc },
995 { "StopExaminingProc", StopExaminingProc },
996 { "UploadProc", UploadProc },
997 { "BackwardProc", BackwardProc },
998 { "ForwardProc", ForwardProc },
999 { "TempBackwardProc", TempBackwardProc },
1000 { "TempForwardProc", TempForwardProc },
1001 { "ToStartProc", ToStartProc },
1002 { "ToEndProc", ToEndProc },
1003 { "RevertProc", RevertProc },
1004 { "AnnotateProc", AnnotateProc },
1005 { "TruncateGameProc", TruncateGameProc },
1006 { "MoveNowProc", MoveNowProc },
1007 { "RetractMoveProc", RetractMoveProc },
1008 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
1009 { "UciMenuProc", (XtActionProc) UciMenuProc },
1010 { "TimeControlProc", (XtActionProc) TimeControlProc },
1011 { "FlipViewProc", FlipViewProc },
1012 { "PonderNextMoveProc", PonderNextMoveProc },
1013 #ifndef OPTIONSDIALOG
1014 { "AlwaysQueenProc", AlwaysQueenProc },
1015 { "AnimateDraggingProc", AnimateDraggingProc },
1016 { "AnimateMovingProc", AnimateMovingProc },
1017 { "AutoflagProc", AutoflagProc },
1018 { "AutoflipProc", AutoflipProc },
1019 { "BlindfoldProc", BlindfoldProc },
1020 { "FlashMovesProc", FlashMovesProc },
1022 { "HighlightDraggingProc", HighlightDraggingProc },
1024 { "HighlightLastMoveProc", HighlightLastMoveProc },
1025 // { "IcsAlarmProc", IcsAlarmProc },
1026 { "MoveSoundProc", MoveSoundProc },
1027 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
1028 { "PopupExitMessageProc", PopupExitMessageProc },
1029 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
1030 // { "PremoveProc", PremoveProc },
1031 { "ShowCoordsProc", ShowCoordsProc },
1032 { "ShowThinkingProc", ShowThinkingProc },
1033 { "HideThinkingProc", HideThinkingProc },
1034 { "TestLegalityProc", TestLegalityProc },
1036 { "SaveSettingsProc", SaveSettingsProc },
1037 { "SaveOnExitProc", SaveOnExitProc },
1038 { "InfoProc", InfoProc },
1039 { "ManProc", ManProc },
1040 { "HintProc", HintProc },
1041 { "BookProc", BookProc },
1042 { "AboutGameProc", AboutGameProc },
1043 { "AboutProc", AboutProc },
1044 { "DebugProc", DebugProc },
1045 { "NothingProc", NothingProc },
1046 { "CommentClick", (XtActionProc) CommentClick },
1047 { "CommentPopDown", (XtActionProc) CommentPopDown },
1048 { "TagsPopDown", (XtActionProc) TagsPopDown },
1049 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
1050 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
1051 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
1052 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
1053 { "GameListPopDown", (XtActionProc) GameListPopDown },
1054 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
1055 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1056 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1057 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1058 { "GenericPopDown", (XtActionProc) GenericPopDown },
1059 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1060 { "SelectMove", (XtActionProc) SelectMove },
1063 char globalTranslations[] =
1064 ":<Key>F9: ResignProc() \n \
1065 :Ctrl<Key>n: ResetProc() \n \
1066 :Meta<Key>V: NewVariantProc() \n \
1067 :Ctrl<Key>o: LoadGameProc() \n \
1068 :Meta<Key>Next: LoadNextGameProc() \n \
1069 :Meta<Key>Prior: LoadPrevGameProc() \n \
1070 :Ctrl<Key>Down: LoadSelectedProc(3) \n \
1071 :Ctrl<Key>Up: LoadSelectedProc(-3) \n \
1072 :Ctrl<Key>s: SaveGameProc() \n \
1073 :Ctrl<Key>c: CopyGameProc() \n \
1074 :Ctrl<Key>v: PasteGameProc() \n \
1075 :Ctrl<Key>O: LoadPositionProc() \n \
1076 :Shift<Key>Next: LoadNextPositionProc() \n \
1077 :Shift<Key>Prior: LoadPrevPositionProc() \n \
1078 :Ctrl<Key>S: SavePositionProc() \n \
1079 :Ctrl<Key>C: CopyPositionProc() \n \
1080 :Ctrl<Key>V: PastePositionProc() \n \
1081 :Ctrl<Key>q: QuitProc() \n \
1082 :Ctrl<Key>w: MachineWhiteProc() \n \
1083 :Ctrl<Key>b: MachineBlackProc() \n \
1084 :Ctrl<Key>t: TwoMachinesProc() \n \
1085 :Ctrl<Key>a: AnalysisModeProc() \n \
1086 :Ctrl<Key>g: AnalyzeFileProc() \n \
1087 :Ctrl<Key>e: EditGameProc() \n \
1088 :Ctrl<Key>E: EditPositionProc() \n \
1089 :Meta<Key>O: EngineOutputProc() \n \
1090 :Meta<Key>E: EvalGraphProc() \n \
1091 :Meta<Key>G: ShowGameListProc() \n \
1092 :Meta<Key>H: ShowMoveListProc() \n \
1093 :<Key>Pause: PauseProc() \n \
1094 :<Key>F3: AcceptProc() \n \
1095 :<Key>F4: DeclineProc() \n \
1096 :<Key>F12: RematchProc() \n \
1097 :<Key>F5: CallFlagProc() \n \
1098 :<Key>F6: DrawProc() \n \
1099 :<Key>F7: AdjournProc() \n \
1100 :<Key>F8: AbortProc() \n \
1101 :<Key>F10: StopObservingProc() \n \
1102 :<Key>F11: StopExaminingProc() \n \
1103 :Meta Ctrl<Key>F12: DebugProc() \n \
1104 :Meta<Key>End: ToEndProc() \n \
1105 :Meta<Key>Right: ForwardProc() \n \
1106 :Meta<Key>Home: ToStartProc() \n \
1107 :Meta<Key>Left: BackwardProc() \n \
1108 :<Key>Left: BackwardProc() \n \
1109 :<Key>Right: ForwardProc() \n \
1110 :<Key>Home: RevertProc() \n \
1111 :<Key>End: TruncateGameProc() \n \
1112 :Ctrl<Key>m: MoveNowProc() \n \
1113 :Ctrl<Key>x: RetractMoveProc() \n \
1114 :Meta<Key>J: EngineMenuProc() \n \
1115 :Meta<Key>U: UciMenuProc() \n \
1116 :Meta<Key>T: TimeControlProc() \n \
1117 :Ctrl<Key>P: PonderNextMoveProc() \n "
1118 #ifndef OPTIONSDIALOG
1120 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1121 :Ctrl<Key>F: AutoflagProc() \n \
1122 :Ctrl<Key>A: AnimateMovingProc() \n \
1123 :Ctrl<Key>L: TestLegalityProc() \n \
1124 :Ctrl<Key>H: HideThinkingProc() \n "
1127 :<Key>F1: ManProc() \n \
1128 :<Key>F2: FlipViewProc() \n \
1129 :<KeyDown>Return: TempBackwardProc() \n \
1130 :<KeyUp>Return: TempForwardProc() \n";
1132 char boardTranslations[] =
1133 "<Btn1Down>: HandleUserMove(0) \n \
1134 Shift<Btn1Up>: HandleUserMove(1) \n \
1135 <Btn1Up>: HandleUserMove(0) \n \
1136 <Btn1Motion>: AnimateUserMove() \n \
1137 <Btn3Motion>: HandlePV() \n \
1138 <Btn2Motion>: HandlePV() \n \
1139 <Btn3Up>: PieceMenuPopup(menuB) \n \
1140 <Btn2Up>: PieceMenuPopup(menuB) \n \
1141 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1142 PieceMenuPopup(menuB) \n \
1143 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1144 PieceMenuPopup(menuW) \n \
1145 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1146 PieceMenuPopup(menuW) \n \
1147 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1148 PieceMenuPopup(menuB) \n";
1150 char whiteTranslations[] =
1151 "Shift<BtnDown>: WhiteClock(1)\n \
1152 <BtnDown>: WhiteClock(0)\n";
1153 char blackTranslations[] =
1154 "Shift<BtnDown>: BlackClock(1)\n \
1155 <BtnDown>: BlackClock(0)\n";
1157 char ICSInputTranslations[] =
1158 "<Key>Up: UpKeyProc() \n "
1159 "<Key>Down: DownKeyProc() \n "
1160 "<Key>Return: EnterKeyProc() \n";
1162 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1163 // as the widget is destroyed before the up-click can call extend-end
1164 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1166 String xboardResources[] = {
1167 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1168 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1169 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1174 /* Max possible square size */
1175 #define MAXSQSIZE 256
1177 static int xpm_avail[MAXSQSIZE];
1179 #ifdef HAVE_DIR_STRUCT
1181 /* Extract piece size from filename */
1183 xpm_getsize (char *name, int len, char *ext)
1191 if ((p=strchr(name, '.')) == NULL ||
1192 StrCaseCmp(p+1, ext) != 0)
1198 while (*p && isdigit(*p))
1205 /* Setup xpm_avail */
1207 xpm_getavail (char *dirname, char *ext)
1213 for (i=0; i<MAXSQSIZE; ++i)
1216 if (appData.debugMode)
1217 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1219 dir = opendir(dirname);
1222 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1223 programName, dirname);
1227 while ((ent=readdir(dir)) != NULL) {
1228 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1229 if (i > 0 && i < MAXSQSIZE)
1239 xpm_print_avail (FILE *fp, char *ext)
1243 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1244 for (i=1; i<MAXSQSIZE; ++i) {
1250 /* Return XPM piecesize closest to size */
1252 xpm_closest_to (char *dirname, int size, char *ext)
1255 int sm_diff = MAXSQSIZE;
1259 xpm_getavail(dirname, ext);
1261 if (appData.debugMode)
1262 xpm_print_avail(stderr, ext);
1264 for (i=1; i<MAXSQSIZE; ++i) {
1267 diff = (diff<0) ? -diff : diff;
1268 if (diff < sm_diff) {
1276 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1282 #else /* !HAVE_DIR_STRUCT */
1283 /* If we are on a system without a DIR struct, we can't
1284 read the directory, so we can't collect a list of
1285 filenames, etc., so we can't do any size-fitting. */
1287 xpm_closest_to (char *dirname, int size, char *ext)
1289 fprintf(stderr, _("\
1290 Warning: No DIR structure found on this system --\n\
1291 Unable to autosize for XPM/XIM pieces.\n\
1292 Please report this error to %s.\n\
1293 Include system type & operating system in message.\n"), PACKAGE_BUGREPORT););
1296 #endif /* HAVE_DIR_STRUCT */
1298 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1299 "magenta", "cyan", "white" };
1303 TextColors textColors[(int)NColorClasses];
1305 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1307 parse_color (char *str, int which)
1309 char *p, buf[100], *d;
1312 if (strlen(str) > 99) /* watch bounds on buf */
1317 for (i=0; i<which; ++i) {
1324 /* Could be looking at something like:
1326 .. in which case we want to stop on a comma also */
1327 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1331 return -1; /* Use default for empty field */
1334 if (which == 2 || isdigit(*p))
1337 while (*p && isalpha(*p))
1342 for (i=0; i<8; ++i) {
1343 if (!StrCaseCmp(buf, cnames[i]))
1344 return which? (i+40) : (i+30);
1346 if (!StrCaseCmp(buf, "default")) return -1;
1348 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1353 parse_cpair (ColorClass cc, char *str)
1355 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1356 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1361 /* bg and attr are optional */
1362 textColors[(int)cc].bg = parse_color(str, 1);
1363 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1364 textColors[(int)cc].attr = 0;
1370 /* Arrange to catch delete-window events */
1371 Atom wm_delete_window;
1373 CatchDeleteWindow (Widget w, String procname)
1376 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1377 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1378 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1385 XtSetArg(args[0], XtNiconic, False);
1386 XtSetValues(shellWidget, args, 1);
1388 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1391 //---------------------------------------------------------------------------------------------------------
1392 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1395 #define CW_USEDEFAULT (1<<31)
1396 #define ICS_TEXT_MENU_SIZE 90
1397 #define DEBUG_FILE "xboard.debug"
1398 #define SetCurrentDirectory chdir
1399 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1403 // these two must some day move to frontend.h, when they are implemented
1404 Boolean GameListIsUp();
1406 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1409 // front-end part of option handling
1411 // [HGM] This platform-dependent table provides the location for storing the color info
1412 extern char *crWhite, * crBlack;
1416 &appData.whitePieceColor,
1417 &appData.blackPieceColor,
1418 &appData.lightSquareColor,
1419 &appData.darkSquareColor,
1420 &appData.highlightSquareColor,
1421 &appData.premoveHighlightColor,
1422 &appData.lowTimeWarningColor,
1433 // [HGM] font: keep a font for each square size, even non-stndard ones
1434 #define NUM_SIZES 18
1435 #define MAX_SIZE 130
1436 Boolean fontIsSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1437 char *fontTable[NUM_FONTS][MAX_SIZE];
1440 ParseFont (char *name, int number)
1441 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1443 if(sscanf(name, "size%d:", &size)) {
1444 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1445 // defer processing it until we know if it matches our board size
1446 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1447 fontTable[number][size] = strdup(strchr(name, ':')+1);
1448 fontValid[number][size] = True;
1453 case 0: // CLOCK_FONT
1454 appData.clockFont = strdup(name);
1456 case 1: // MESSAGE_FONT
1457 appData.font = strdup(name);
1459 case 2: // COORD_FONT
1460 appData.coordFont = strdup(name);
1465 fontIsSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1470 { // only 2 fonts currently
1471 appData.clockFont = CLOCK_FONT_NAME;
1472 appData.coordFont = COORD_FONT_NAME;
1473 appData.font = DEFAULT_FONT_NAME;
1478 { // no-op, until we identify the code for this already in XBoard and move it here
1482 ParseColor (int n, char *name)
1483 { // in XBoard, just copy the color-name string
1484 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1488 ParseTextAttribs (ColorClass cc, char *s)
1490 (&appData.colorShout)[cc] = strdup(s);
1494 ParseBoardSize (void *addr, char *name)
1496 appData.boardSize = strdup(name);
1501 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1505 SetCommPortDefaults ()
1506 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1509 // [HGM] args: these three cases taken out to stay in front-end
1511 SaveFontArg (FILE *f, ArgDescriptor *ad)
1514 int i, n = (int)(intptr_t)ad->argLoc;
1516 case 0: // CLOCK_FONT
1517 name = appData.clockFont;
1519 case 1: // MESSAGE_FONT
1520 name = appData.font;
1522 case 2: // COORD_FONT
1523 name = appData.coordFont;
1528 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1529 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1530 fontTable[n][squareSize] = strdup(name);
1531 fontValid[n][squareSize] = True;
1534 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1535 fprintf(f, OPTCHAR "%s" SEPCHAR "\"size%d:%s\"\n", ad->argName, i, fontTable[n][i]);
1540 { // nothing to do, as the sounds are at all times represented by their text-string names already
1544 SaveAttribsArg (FILE *f, ArgDescriptor *ad)
1545 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1546 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
1550 SaveColor (FILE *f, ArgDescriptor *ad)
1551 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1552 if(colorVariable[(int)(intptr_t)ad->argLoc])
1553 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
1557 SaveBoardSize (FILE *f, char *name, void *addr)
1558 { // wrapper to shield back-end from BoardSize & sizeInfo
1559 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1563 ParseCommPortSettings (char *s)
1564 { // no such option in XBoard (yet)
1567 extern Widget engineOutputShell;
1571 GetActualPlacement (Widget wg, WindowPlacement *wp)
1576 XWindowAttributes winAt;
1583 XGetWindowAttributes(xDisplay, win, &winAt); // this works, where XtGetValues on XtNx, XtNy does not!
1584 XTranslateCoordinates (xDisplay, win, winAt.root, -winAt.border_width, -winAt.border_width, &rx, &ry, &dummy);
1585 wp->x = rx - winAt.x;
1586 wp->y = ry - winAt.y;
1587 wp->height = winAt.height;
1588 wp->width = winAt.width;
1589 frameX = winAt.x; frameY = winAt.y; // remember to decide if windows touch
1594 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1595 // In XBoard this will have to wait until awareness of window parameters is implemented
1596 GetActualPlacement(shellWidget, &wpMain);
1597 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput);
1598 if(MoveHistoryIsUp()) GetActualPlacement(shells[7], &wpMoveHistory);
1599 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1600 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1601 if(shellUp[1]) GetActualPlacement(shells[1], &wpComment);
1602 if(shellUp[2]) GetActualPlacement(shells[2], &wpTags);
1606 PrintCommPortSettings (FILE *f, char *name)
1607 { // This option does not exist in XBoard
1611 MySearchPath (char *installDir, char *name, char *fullname)
1612 { // just append installDir and name. Perhaps ExpandPath should be used here?
1613 name = ExpandPathName(name);
1614 if(name && name[0] == '/')
1615 safeStrCpy(fullname, name, MSG_SIZ );
1617 sprintf(fullname, "%s%c%s", installDir, '/', name);
1623 MyGetFullPathName (char *name, char *fullname)
1624 { // should use ExpandPath?
1625 name = ExpandPathName(name);
1626 safeStrCpy(fullname, name, MSG_SIZ );
1631 EnsureOnScreen (int *x, int *y, int minX, int minY)
1638 { // [HGM] args: allows testing if main window is realized from back-end
1639 return xBoardWindow != 0;
1643 PopUpStartupDialog ()
1644 { // start menu not implemented in XBoard
1648 ConvertToLine (int argc, char **argv)
1650 static char line[128*1024], buf[1024];
1654 for(i=1; i<argc; i++)
1656 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') || argv[i][0] == NULLCHAR)
1657 && argv[i][0] != '{' )
1658 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1660 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1661 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1664 line[strlen(line)-1] = NULLCHAR;
1668 //--------------------------------------------------------------------------------------------
1670 extern Boolean twoBoards, partnerUp;
1673 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1675 #define BoardSize int
1677 InitDrawingSizes (BoardSize boardSize, int flags)
1678 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1679 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1681 XtGeometryResult gres;
1683 static Dimension oldWidth, oldHeight;
1684 static VariantClass oldVariant;
1685 static int oldDual = -1, oldMono = -1;
1687 if(!formWidget) return;
1689 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1690 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1691 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1693 if(boardWidth != oldWidth || boardHeight != oldHeight || oldDual != twoBoards) { // do resizing stuff only if size actually changed
1695 * Enable shell resizing.
1697 shellArgs[0].value = (XtArgVal) &w;
1698 shellArgs[1].value = (XtArgVal) &h;
1699 XtGetValues(shellWidget, shellArgs, 2);
1701 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1702 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1703 XtSetValues(shellWidget, &shellArgs[2], 4);
1705 XtSetArg(args[0], XtNdefaultDistance, &sep);
1706 XtGetValues(formWidget, args, 1);
1708 oldWidth = boardWidth; oldHeight = boardHeight; oldDual = twoBoards;
1710 hOffset = boardWidth + 10;
1711 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1712 secondSegments[i] = gridSegments[i];
1713 secondSegments[i].x1 += hOffset;
1714 secondSegments[i].x2 += hOffset;
1717 XtSetArg(args[0], XtNwidth, boardWidth);
1718 XtSetArg(args[1], XtNheight, boardHeight);
1719 XtSetValues(boardWidget, args, 2);
1721 timerWidth = (boardWidth - sep) / 2;
1722 XtSetArg(args[0], XtNwidth, timerWidth);
1723 XtSetValues(whiteTimerWidget, args, 1);
1724 XtSetValues(blackTimerWidget, args, 1);
1726 XawFormDoLayout(formWidget, False);
1728 if (appData.titleInWindow) {
1730 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1731 XtSetArg(args[i], XtNheight, &h); i++;
1732 XtGetValues(titleWidget, args, i);
1734 w = boardWidth - 2*bor;
1736 XtSetArg(args[0], XtNwidth, &w);
1737 XtGetValues(menuBarWidget, args, 1);
1738 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1741 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1742 if (gres != XtGeometryYes && appData.debugMode) {
1744 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1745 programName, gres, w, h, wr, hr);
1749 XawFormDoLayout(formWidget, True);
1752 * Inhibit shell resizing.
1754 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1755 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1756 shellArgs[4].value = shellArgs[2].value = w;
1757 shellArgs[5].value = shellArgs[3].value = h;
1758 XtSetValues(shellWidget, &shellArgs[0], 6);
1760 XSync(xDisplay, False);
1764 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1767 if(gameInfo.variant != oldVariant) { // and only if variant changed
1770 for(i=0; i<4; i++) {
1772 for(p=0; p<=(int)WhiteKing; p++)
1773 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1774 if(gameInfo.variant == VariantShogi) {
1775 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1776 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1777 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1778 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1779 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1782 if(gameInfo.variant == VariantGothic) {
1783 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1786 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1787 xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
1788 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1791 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1792 for(p=0; p<=(int)WhiteKing; p++)
1793 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1794 if(gameInfo.variant == VariantShogi) {
1795 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1796 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1797 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1798 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1799 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1802 if(gameInfo.variant == VariantGothic) {
1803 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1806 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1807 ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
1808 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1813 for(i=0; i<2; i++) {
1815 for(p=0; p<=(int)WhiteKing; p++)
1816 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1817 if(gameInfo.variant == VariantShogi) {
1818 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1819 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1820 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1821 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1822 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1825 if(gameInfo.variant == VariantGothic) {
1826 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1829 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1830 pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
1831 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1835 oldMono = -10; // kludge to force recreation of animation masks
1836 oldVariant = gameInfo.variant;
1839 if(appData.monoMode != oldMono)
1842 oldMono = appData.monoMode;
1847 ParseIcsTextColors ()
1848 { // [HGM] tken out of main(), so it can be called from ICS-Options dialog
1849 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1850 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1851 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1852 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1853 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1854 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1855 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1856 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1857 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1858 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1860 if (appData.colorize) {
1862 _("%s: can't parse color names; disabling colorization\n"),
1865 appData.colorize = FALSE;
1871 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
1872 XrmValue vFrom, vTo;
1873 int forceMono = False;
1875 if (!appData.monoMode) {
1876 vFrom.addr = (caddr_t) appData.lightSquareColor;
1877 vFrom.size = strlen(appData.lightSquareColor);
1878 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1879 if (vTo.addr == NULL) {
1880 appData.monoMode = True;
1883 lightSquareColor = *(Pixel *) vTo.addr;
1886 if (!appData.monoMode) {
1887 vFrom.addr = (caddr_t) appData.darkSquareColor;
1888 vFrom.size = strlen(appData.darkSquareColor);
1889 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1890 if (vTo.addr == NULL) {
1891 appData.monoMode = True;
1894 darkSquareColor = *(Pixel *) vTo.addr;
1897 if (!appData.monoMode) {
1898 vFrom.addr = (caddr_t) appData.whitePieceColor;
1899 vFrom.size = strlen(appData.whitePieceColor);
1900 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1901 if (vTo.addr == NULL) {
1902 appData.monoMode = True;
1905 whitePieceColor = *(Pixel *) vTo.addr;
1908 if (!appData.monoMode) {
1909 vFrom.addr = (caddr_t) appData.blackPieceColor;
1910 vFrom.size = strlen(appData.blackPieceColor);
1911 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1912 if (vTo.addr == NULL) {
1913 appData.monoMode = True;
1916 blackPieceColor = *(Pixel *) vTo.addr;
1920 if (!appData.monoMode) {
1921 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1922 vFrom.size = strlen(appData.highlightSquareColor);
1923 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1924 if (vTo.addr == NULL) {
1925 appData.monoMode = True;
1928 highlightSquareColor = *(Pixel *) vTo.addr;
1932 if (!appData.monoMode) {
1933 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1934 vFrom.size = strlen(appData.premoveHighlightColor);
1935 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1936 if (vTo.addr == NULL) {
1937 appData.monoMode = True;
1940 premoveHighlightColor = *(Pixel *) vTo.addr;
1948 { // [HGM] taken out of main
1950 if (appData.monoMode && // [HGM] no sense to go on to certain doom
1951 (appData.bitmapDirectory == NULL || appData.bitmapDirectory[0] == NULLCHAR))
1952 appData.bitmapDirectory = strdup(DEF_BITMAP_DIR);
1954 if (appData.bitmapDirectory[0] != NULLCHAR) {
1958 CreateXPMBoard(appData.liteBackTextureFile, 1);
1959 CreateXPMBoard(appData.darkBackTextureFile, 0);
1963 /* Create regular pieces */
1964 if (!useImages) CreatePieces();
1969 main (int argc, char **argv)
1971 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1972 XSetWindowAttributes window_attributes;
1974 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1975 XrmValue vFrom, vTo;
1976 XtGeometryResult gres;
1979 int forceMono = False;
1981 srandom(time(0)); // [HGM] book: make random truly random
1983 setbuf(stdout, NULL);
1984 setbuf(stderr, NULL);
1987 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1988 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1992 programName = strrchr(argv[0], '/');
1993 if (programName == NULL)
1994 programName = argv[0];
1999 XtSetLanguageProc(NULL, NULL, NULL);
2000 bindtextdomain(PACKAGE, LOCALEDIR);
2001 textdomain(PACKAGE);
2005 XtAppInitialize(&appContext, "XBoard", shellOptions,
2006 XtNumber(shellOptions),
2007 &argc, argv, xboardResources, NULL, 0);
2008 appData.boardSize = "";
2009 InitAppData(ConvertToLine(argc, argv));
2011 if (p == NULL) p = "/tmp";
2012 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
2013 gameCopyFilename = (char*) malloc(i);
2014 gamePasteFilename = (char*) malloc(i);
2015 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
2016 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
2018 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
2019 clientResources, XtNumber(clientResources),
2022 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
2023 static char buf[MSG_SIZ];
2024 EscapeExpand(buf, appData.firstInitString);
2025 appData.firstInitString = strdup(buf);
2026 EscapeExpand(buf, appData.secondInitString);
2027 appData.secondInitString = strdup(buf);
2028 EscapeExpand(buf, appData.firstComputerString);
2029 appData.firstComputerString = strdup(buf);
2030 EscapeExpand(buf, appData.secondComputerString);
2031 appData.secondComputerString = strdup(buf);
2034 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
2037 if (chdir(chessDir) != 0) {
2038 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
2044 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
2045 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
2046 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
2047 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
2050 setbuf(debugFP, NULL);
2054 if (appData.debugMode) {
2055 fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
2059 /* [HGM,HR] make sure board size is acceptable */
2060 if(appData.NrFiles > BOARD_FILES ||
2061 appData.NrRanks > BOARD_RANKS )
2062 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
2065 /* This feature does not work; animation needs a rewrite */
2066 appData.highlightDragging = FALSE;
2070 xDisplay = XtDisplay(shellWidget);
2071 xScreen = DefaultScreen(xDisplay);
2072 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
2074 gameInfo.variant = StringToVariant(appData.variant);
2075 InitPosition(FALSE);
2078 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
2080 if (isdigit(appData.boardSize[0])) {
2081 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
2082 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
2083 &fontPxlSize, &smallLayout, &tinyLayout);
2085 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
2086 programName, appData.boardSize);
2090 /* Find some defaults; use the nearest known size */
2091 SizeDefaults *szd, *nearest;
2092 int distance = 99999;
2093 nearest = szd = sizeDefaults;
2094 while (szd->name != NULL) {
2095 if (abs(szd->squareSize - squareSize) < distance) {
2097 distance = abs(szd->squareSize - squareSize);
2098 if (distance == 0) break;
2102 if (i < 2) lineGap = nearest->lineGap;
2103 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
2104 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
2105 if (i < 5) fontPxlSize = nearest->fontPxlSize;
2106 if (i < 6) smallLayout = nearest->smallLayout;
2107 if (i < 7) tinyLayout = nearest->tinyLayout;
2110 SizeDefaults *szd = sizeDefaults;
2111 if (*appData.boardSize == NULLCHAR) {
2112 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
2113 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
2116 if (szd->name == NULL) szd--;
2117 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
2119 while (szd->name != NULL &&
2120 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
2121 if (szd->name == NULL) {
2122 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
2123 programName, appData.boardSize);
2127 squareSize = szd->squareSize;
2128 lineGap = szd->lineGap;
2129 clockFontPxlSize = szd->clockFontPxlSize;
2130 coordFontPxlSize = szd->coordFontPxlSize;
2131 fontPxlSize = szd->fontPxlSize;
2132 smallLayout = szd->smallLayout;
2133 tinyLayout = szd->tinyLayout;
2134 // [HGM] font: use defaults from settings file if available and not overruled
2136 if(!fontIsSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
2137 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
2138 if(!fontIsSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
2139 appData.font = fontTable[MESSAGE_FONT][squareSize];
2140 if(!fontIsSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
2141 appData.coordFont = fontTable[COORD_FONT][squareSize];
2143 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
2144 if (strlen(appData.pixmapDirectory) > 0) {
2145 p = ExpandPathName(appData.pixmapDirectory);
2147 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
2148 appData.pixmapDirectory);
2151 if (appData.debugMode) {
2152 fprintf(stderr, _("\
2153 XBoard square size (hint): %d\n\
2154 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
2156 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
2157 if (appData.debugMode) {
2158 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
2161 defaultLineGap = lineGap;
2162 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
2164 /* [HR] height treated separately (hacked) */
2165 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
2166 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
2167 if (appData.showJail == 1) {
2168 /* Jail on top and bottom */
2169 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2170 XtSetArg(boardArgs[2], XtNheight,
2171 boardHeight + 2*(lineGap + squareSize));
2172 } else if (appData.showJail == 2) {
2174 XtSetArg(boardArgs[1], XtNwidth,
2175 boardWidth + 2*(lineGap + squareSize));
2176 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2179 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2180 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2184 * Determine what fonts to use.
2187 appData.font = InsertPxlSize(appData.font, fontPxlSize);
2188 appData.clockFont = InsertPxlSize(appData.clockFont, clockFontPxlSize);
2189 appData.coordFont = InsertPxlSize(appData.coordFont, coordFontPxlSize);
2190 fontSet = CreateFontSet(appData.font);
2191 clockFontSet = CreateFontSet(appData.clockFont);
2193 /* For the coordFont, use the 0th font of the fontset. */
2194 XFontSet coordFontSet = CreateFontSet(appData.coordFont);
2195 XFontStruct **font_struct_list;
2196 XFontSetExtents *fontSize;
2197 char **font_name_list;
2198 XFontsOfFontSet(coordFontSet, &font_struct_list, &font_name_list);
2199 coordFontID = XLoadFont(xDisplay, font_name_list[0]);
2200 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2201 fontSize = XExtentsOfFontSet(fontSet); // [HGM] figure out how much vertical space font takes
2202 textHeight = fontSize->max_logical_extent.height + 5; // add borderWidth
2205 appData.font = FindFont(appData.font, fontPxlSize);
2206 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2207 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2208 clockFontID = XLoadFont(xDisplay, appData.clockFont);
2209 clockFontStruct = XQueryFont(xDisplay, clockFontID);
2210 coordFontID = XLoadFont(xDisplay, appData.coordFont);
2211 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2213 countFontID = coordFontID; // [HGM] holdings
2214 countFontStruct = coordFontStruct;
2216 xdb = XtDatabase(xDisplay);
2218 XrmPutLineResource(&xdb, "*international: True");
2219 vTo.size = sizeof(XFontSet);
2220 vTo.addr = (XtPointer) &fontSet;
2221 XrmPutResource(&xdb, "*fontSet", XtRFontSet, &vTo);
2223 XrmPutStringResource(&xdb, "*font", appData.font);
2227 * Detect if there are not enough colors available and adapt.
2229 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2230 appData.monoMode = True;
2233 forceMono = MakeColors();
2236 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2238 appData.monoMode = True;
2241 if (appData.lowTimeWarning && !appData.monoMode) {
2242 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2243 vFrom.size = strlen(appData.lowTimeWarningColor);
2244 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2245 if (vTo.addr == NULL)
2246 appData.monoMode = True;
2248 lowTimeWarningColor = *(Pixel *) vTo.addr;
2251 if (appData.monoMode && appData.debugMode) {
2252 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2253 (unsigned long) XWhitePixel(xDisplay, xScreen),
2254 (unsigned long) XBlackPixel(xDisplay, xScreen));
2257 ParseIcsTextColors();
2258 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2259 textColors[ColorNone].attr = 0;
2261 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2267 layoutName = "tinyLayout";
2268 } else if (smallLayout) {
2269 layoutName = "smallLayout";
2271 layoutName = "normalLayout";
2273 /* Outer layoutWidget is there only to provide a name for use in
2274 resources that depend on the layout style */
2276 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2277 layoutArgs, XtNumber(layoutArgs));
2279 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2280 formArgs, XtNumber(formArgs));
2281 XtSetArg(args[0], XtNdefaultDistance, &sep);
2282 XtGetValues(formWidget, args, 1);
2285 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar, boardWidth);
2286 XtSetArg(args[0], XtNtop, XtChainTop);
2287 XtSetArg(args[1], XtNbottom, XtChainTop);
2288 XtSetArg(args[2], XtNright, XtChainLeft);
2289 XtSetValues(menuBarWidget, args, 3);
2291 widgetList[j++] = whiteTimerWidget =
2292 XtCreateWidget("whiteTime", labelWidgetClass,
2293 formWidget, timerArgs, XtNumber(timerArgs));
2295 XtSetArg(args[0], XtNfontSet, clockFontSet);
2297 XtSetArg(args[0], XtNfont, clockFontStruct);
2299 XtSetArg(args[1], XtNtop, XtChainTop);
2300 XtSetArg(args[2], XtNbottom, XtChainTop);
2301 XtSetValues(whiteTimerWidget, args, 3);
2303 widgetList[j++] = blackTimerWidget =
2304 XtCreateWidget("blackTime", labelWidgetClass,
2305 formWidget, timerArgs, XtNumber(timerArgs));
2307 XtSetArg(args[0], XtNfontSet, clockFontSet);
2309 XtSetArg(args[0], XtNfont, clockFontStruct);
2311 XtSetArg(args[1], XtNtop, XtChainTop);
2312 XtSetArg(args[2], XtNbottom, XtChainTop);
2313 XtSetValues(blackTimerWidget, args, 3);
2315 if (appData.titleInWindow) {
2316 widgetList[j++] = titleWidget =
2317 XtCreateWidget("title", labelWidgetClass, formWidget,
2318 titleArgs, XtNumber(titleArgs));
2319 XtSetArg(args[0], XtNtop, XtChainTop);
2320 XtSetArg(args[1], XtNbottom, XtChainTop);
2321 XtSetValues(titleWidget, args, 2);
2324 if (appData.showButtonBar) {
2325 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2326 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2327 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2328 XtSetArg(args[2], XtNtop, XtChainTop);
2329 XtSetArg(args[3], XtNbottom, XtChainTop);
2330 XtSetValues(buttonBarWidget, args, 4);
2333 widgetList[j++] = messageWidget =
2334 XtCreateWidget("message", labelWidgetClass, formWidget,
2335 messageArgs, XtNumber(messageArgs));
2336 XtSetArg(args[0], XtNtop, XtChainTop);
2337 XtSetArg(args[1], XtNbottom, XtChainTop);
2338 XtSetValues(messageWidget, args, 2);
2340 widgetList[j++] = boardWidget =
2341 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2342 XtNumber(boardArgs));
2344 XtManageChildren(widgetList, j);
2346 timerWidth = (boardWidth - sep) / 2;
2347 XtSetArg(args[0], XtNwidth, timerWidth);
2348 XtSetValues(whiteTimerWidget, args, 1);
2349 XtSetValues(blackTimerWidget, args, 1);
2351 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2352 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2353 XtGetValues(whiteTimerWidget, args, 2);
2355 if (appData.showButtonBar) {
2356 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2357 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2358 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2362 * formWidget uses these constraints but they are stored
2366 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2367 XtSetValues(menuBarWidget, args, i);
2368 if (appData.titleInWindow) {
2371 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2372 XtSetValues(whiteTimerWidget, args, i);
2374 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2375 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2376 XtSetValues(blackTimerWidget, args, i);
2378 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2379 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2380 XtSetValues(titleWidget, args, i);
2382 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2383 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2384 XtSetValues(messageWidget, args, i);
2385 if (appData.showButtonBar) {
2387 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2388 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2389 XtSetValues(buttonBarWidget, args, i);
2393 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2394 XtSetValues(whiteTimerWidget, args, i);
2396 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2397 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2398 XtSetValues(blackTimerWidget, args, i);
2400 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2401 XtSetValues(titleWidget, args, i);
2403 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2404 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2405 XtSetValues(messageWidget, args, i);
2406 if (appData.showButtonBar) {
2408 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2409 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2410 XtSetValues(buttonBarWidget, args, i);
2415 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2416 XtSetValues(whiteTimerWidget, args, i);
2418 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2419 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2420 XtSetValues(blackTimerWidget, args, i);
2422 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2423 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2424 XtSetValues(messageWidget, args, i);
2425 if (appData.showButtonBar) {
2427 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2428 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2429 XtSetValues(buttonBarWidget, args, i);
2433 XtSetArg(args[0], XtNfromVert, messageWidget);
2434 XtSetArg(args[1], XtNtop, XtChainTop);
2435 XtSetArg(args[2], XtNbottom, XtChainBottom);
2436 XtSetArg(args[3], XtNleft, XtChainLeft);
2437 XtSetArg(args[4], XtNright, XtChainRight);
2438 XtSetValues(boardWidget, args, 5);
2440 XtRealizeWidget(shellWidget);
2443 XtSetArg(args[0], XtNx, wpMain.x);
2444 XtSetArg(args[1], XtNy, wpMain.y);
2445 XtSetValues(shellWidget, args, 2);
2449 * Correct the width of the message and title widgets.
2450 * It is not known why some systems need the extra fudge term.
2451 * The value "2" is probably larger than needed.
2453 XawFormDoLayout(formWidget, False);
2455 #define WIDTH_FUDGE 2
2457 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2458 XtSetArg(args[i], XtNheight, &h); i++;
2459 XtGetValues(messageWidget, args, i);
2460 if (appData.showButtonBar) {
2462 XtSetArg(args[i], XtNwidth, &w); i++;
2463 XtGetValues(buttonBarWidget, args, i);
2464 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2466 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2469 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2470 if (gres != XtGeometryYes && appData.debugMode) {
2471 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2472 programName, gres, w, h, wr, hr);
2475 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2476 /* The size used for the child widget in layout lags one resize behind
2477 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2479 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2480 if (gres != XtGeometryYes && appData.debugMode) {
2481 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2482 programName, gres, w, h, wr, hr);
2485 if(!textHeight) textHeight = hr; // [HGM] if !NLS textHeight is still undefined, and we grab it from here
2486 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2487 XtSetArg(args[1], XtNright, XtChainRight);
2488 XtSetValues(messageWidget, args, 2);
2490 if (appData.titleInWindow) {
2492 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2493 XtSetArg(args[i], XtNheight, &h); i++;
2494 XtGetValues(titleWidget, args, i);
2496 w = boardWidth - 2*bor;
2498 XtSetArg(args[0], XtNwidth, &w);
2499 XtGetValues(menuBarWidget, args, 1);
2500 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2503 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2504 if (gres != XtGeometryYes && appData.debugMode) {
2506 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2507 programName, gres, w, h, wr, hr);
2510 XawFormDoLayout(formWidget, True);
2512 xBoardWindow = XtWindow(boardWidget);
2514 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2515 // not need to go into InitDrawingSizes().
2519 * Create X checkmark bitmap and initialize option menu checks.
2521 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2522 checkmark_bits, checkmark_width, checkmark_height);
2523 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2524 #ifndef OPTIONSDIALOG
2525 if (appData.alwaysPromoteToQueen) {
2526 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2529 if (appData.animateDragging) {
2530 XtSetValues(XtNameToWidget(menuBarWidget,
2531 "menuOptions.Animate Dragging"),
2534 if (appData.animate) {
2535 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2538 if (appData.autoCallFlag) {
2539 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2542 if (appData.autoFlipView) {
2543 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2546 if (appData.blindfold) {
2547 XtSetValues(XtNameToWidget(menuBarWidget,
2548 "menuOptions.Blindfold"), args, 1);
2550 if (appData.flashCount > 0) {
2551 XtSetValues(XtNameToWidget(menuBarWidget,
2552 "menuOptions.Flash Moves"),
2556 if (appData.highlightDragging) {
2557 XtSetValues(XtNameToWidget(menuBarWidget,
2558 "menuOptions.Highlight Dragging"),
2562 if (appData.highlightLastMove) {
2563 XtSetValues(XtNameToWidget(menuBarWidget,
2564 "menuOptions.Highlight Last Move"),
2567 if (appData.highlightMoveWithArrow) {
2568 XtSetValues(XtNameToWidget(menuBarWidget,
2569 "menuOptions.Arrow"),
2572 // if (appData.icsAlarm) {
2573 // XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2576 if (appData.ringBellAfterMoves) {
2577 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2580 if (appData.oneClick) {
2581 XtSetValues(XtNameToWidget(menuBarWidget,
2582 "menuOptions.OneClick"), args, 1);
2584 if (appData.periodicUpdates) {
2585 XtSetValues(XtNameToWidget(menuBarWidget,
2586 "menuOptions.Periodic Updates"), args, 1);
2588 if (appData.ponderNextMove) {
2589 XtSetValues(XtNameToWidget(menuBarWidget,
2590 "menuOptions.Ponder Next Move"), args, 1);
2592 if (appData.popupExitMessage) {
2593 XtSetValues(XtNameToWidget(menuBarWidget,
2594 "menuOptions.Popup Exit Message"), args, 1);
2596 if (appData.popupMoveErrors) {
2597 XtSetValues(XtNameToWidget(menuBarWidget,
2598 "menuOptions.Popup Move Errors"), args, 1);
2600 // if (appData.premove) {
2601 // XtSetValues(XtNameToWidget(menuBarWidget,
2602 // "menuOptions.Premove"), args, 1);
2604 if (appData.showCoords) {
2605 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2608 if (appData.hideThinkingFromHuman) {
2609 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2612 if (appData.testLegality) {
2613 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2617 if (saveSettingsOnExit) {
2618 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2625 ReadBitmap(&wIconPixmap, "icon_white.bm",
2626 icon_white_bits, icon_white_width, icon_white_height);
2627 ReadBitmap(&bIconPixmap, "icon_black.bm",
2628 icon_black_bits, icon_black_width, icon_black_height);
2629 iconPixmap = wIconPixmap;
2631 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2632 XtSetValues(shellWidget, args, i);
2635 * Create a cursor for the board widget.
2637 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2638 XChangeWindowAttributes(xDisplay, xBoardWindow,
2639 CWCursor, &window_attributes);
2642 * Inhibit shell resizing.
2644 shellArgs[0].value = (XtArgVal) &w;
2645 shellArgs[1].value = (XtArgVal) &h;
2646 XtGetValues(shellWidget, shellArgs, 2);
2647 shellArgs[4].value = shellArgs[2].value = w;
2648 shellArgs[5].value = shellArgs[3].value = h;
2649 XtSetValues(shellWidget, &shellArgs[2], 4);
2650 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2651 marginH = h - boardHeight;
2653 CatchDeleteWindow(shellWidget, "QuitProc");
2661 if (appData.animate || appData.animateDragging)
2664 XtAugmentTranslations(formWidget,
2665 XtParseTranslationTable(globalTranslations));
2666 XtAugmentTranslations(boardWidget,
2667 XtParseTranslationTable(boardTranslations));
2668 XtAugmentTranslations(whiteTimerWidget,
2669 XtParseTranslationTable(whiteTranslations));
2670 XtAugmentTranslations(blackTimerWidget,
2671 XtParseTranslationTable(blackTranslations));
2673 /* Why is the following needed on some versions of X instead
2674 * of a translation? */
2675 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2676 (XtEventHandler) EventProc, NULL);
2678 XtAddEventHandler(formWidget, KeyPressMask, False,
2679 (XtEventHandler) MoveTypeInProc, NULL);
2680 XtAddEventHandler(shellWidget, StructureNotifyMask, False,
2681 (XtEventHandler) EventProc, NULL);
2683 /* [AS] Restore layout */
2684 if( wpMoveHistory.visible ) {
2688 if( wpEvalGraph.visible )
2693 if( wpEngineOutput.visible ) {
2694 EngineOutputPopUp();
2699 if (errorExitStatus == -1) {
2700 if (appData.icsActive) {
2701 /* We now wait until we see "login:" from the ICS before
2702 sending the logon script (problems with timestamp otherwise) */
2703 /*ICSInitScript();*/
2704 if (appData.icsInputBox) ICSInputBoxPopUp();
2708 signal(SIGWINCH, TermSizeSigHandler);
2710 signal(SIGINT, IntSigHandler);
2711 signal(SIGTERM, IntSigHandler);
2712 if (*appData.cmailGameName != NULLCHAR) {
2713 signal(SIGUSR1, CmailSigHandler);
2716 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2718 // XtSetKeyboardFocus(shellWidget, formWidget);
2719 XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
2721 XtAppMainLoop(appContext);
2722 if (appData.debugMode) fclose(debugFP); // [DM] debug
2726 static Boolean noEcho;
2731 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2732 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2734 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2735 unlink(gameCopyFilename);
2736 unlink(gamePasteFilename);
2737 if(noEcho) EchoOn();
2741 TermSizeSigHandler (int sig)
2747 IntSigHandler (int sig)
2753 CmailSigHandler (int sig)
2758 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2760 /* Activate call-back function CmailSigHandlerCallBack() */
2761 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2763 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2767 CmailSigHandlerCallBack (InputSourceRef isr, VOIDSTAR closure, char *message, int count, int error)
2770 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2772 /**** end signal code ****/
2778 /* try to open the icsLogon script, either in the location given
2779 * or in the users HOME directory
2786 f = fopen(appData.icsLogon, "r");
2789 homedir = getenv("HOME");
2790 if (homedir != NULL)
2792 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2793 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2794 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2795 f = fopen(buf, "r");
2800 ProcessICSInitScript(f);
2802 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2821 GreyRevert (Boolean grey)
2824 if (!menuBarWidget) return;
2825 w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2827 DisplayError("menuEdit.Revert", 0);
2829 XtSetSensitive(w, !grey);
2831 w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2833 DisplayError("menuEdit.Annotate", 0);
2835 XtSetSensitive(w, !grey);
2840 SetMenuEnables (Enables *enab)
2843 if (!menuBarWidget) return;
2844 while (enab->name != NULL) {
2845 w = XtNameToWidget(menuBarWidget, enab->name);
2847 DisplayError(enab->name, 0);
2849 XtSetSensitive(w, enab->value);
2855 Enables icsEnables[] = {
2856 { "menuFile.Mail Move", False },
2857 { "menuFile.Reload CMail Message", False },
2858 { "menuMode.Machine Black", False },
2859 { "menuMode.Machine White", False },
2860 { "menuMode.Analysis Mode", False },
2861 { "menuMode.Analyze File", False },
2862 { "menuMode.Two Machines", False },
2863 { "menuMode.Machine Match", False },
2865 { "menuEngine.Hint", False },
2866 { "menuEngine.Book", False },
2867 { "menuEngine.Move Now", False },
2868 #ifndef OPTIONSDIALOG
2869 { "menuOptions.Periodic Updates", False },
2870 { "menuOptions.Hide Thinking", False },
2871 { "menuOptions.Ponder Next Move", False },
2874 { "menuEngine.Engine #1 Settings", False },
2875 { "menuEngine.Engine #2 Settings", False },
2876 { "menuEngine.Load Engine", False },
2877 { "menuEdit.Annotate", False },
2878 { "menuOptions.Match", False },
2882 Enables ncpEnables[] = {
2883 { "menuFile.Mail Move", False },
2884 { "menuFile.Reload CMail Message", False },
2885 { "menuMode.Machine White", False },
2886 { "menuMode.Machine Black", False },
2887 { "menuMode.Analysis Mode", False },
2888 { "menuMode.Analyze File", False },
2889 { "menuMode.Two Machines", False },
2890 { "menuMode.Machine Match", False },
2891 { "menuMode.ICS Client", False },
2892 { "menuView.ICStex", False },
2893 { "menuView.ICS Input Box", False },
2894 { "Action", False },
2895 { "menuEdit.Revert", False },
2896 { "menuEdit.Annotate", False },
2897 { "menuEngine.Engine #1 Settings", False },
2898 { "menuEngine.Engine #2 Settings", False },
2899 { "menuEngine.Move Now", False },
2900 { "menuEngine.Retract Move", False },
2901 { "menuOptions.ICS", False },
2902 #ifndef OPTIONSDIALOG
2903 { "menuOptions.Auto Flag", False },
2904 { "menuOptions.Auto Flip View", False },
2905 // { "menuOptions.ICS Alarm", False },
2906 { "menuOptions.Move Sound", False },
2907 { "menuOptions.Hide Thinking", False },
2908 { "menuOptions.Periodic Updates", False },
2909 { "menuOptions.Ponder Next Move", False },
2911 { "menuEngine.Hint", False },
2912 { "menuEngine.Book", False },
2916 Enables gnuEnables[] = {
2917 { "menuMode.ICS Client", False },
2918 { "menuView.ICStex", False },
2919 { "menuView.ICS Input Box", False },
2920 { "menuAction.Accept", False },
2921 { "menuAction.Decline", False },
2922 { "menuAction.Rematch", False },
2923 { "menuAction.Adjourn", False },
2924 { "menuAction.Stop Examining", False },
2925 { "menuAction.Stop Observing", False },
2926 { "menuAction.Upload to Examine", False },
2927 { "menuEdit.Revert", False },
2928 { "menuEdit.Annotate", False },
2929 { "menuOptions.ICS", False },
2931 /* The next two options rely on SetCmailMode being called *after* */
2932 /* SetGNUMode so that when GNU is being used to give hints these */
2933 /* menu options are still available */
2935 { "menuFile.Mail Move", False },
2936 { "menuFile.Reload CMail Message", False },
2937 // [HGM] The following have been added to make a switch from ncp to GNU mode possible
2938 { "menuMode.Machine White", True },
2939 { "menuMode.Machine Black", True },
2940 { "menuMode.Analysis Mode", True },
2941 { "menuMode.Analyze File", True },
2942 { "menuMode.Two Machines", True },
2943 { "menuMode.Machine Match", True },
2944 { "menuEngine.Engine #1 Settings", True },
2945 { "menuEngine.Engine #2 Settings", True },
2946 { "menuEngine.Hint", True },
2947 { "menuEngine.Book", True },
2948 { "menuEngine.Move Now", True },
2949 { "menuEngine.Retract Move", True },
2954 Enables cmailEnables[] = {
2956 { "menuAction.Call Flag", False },
2957 { "menuAction.Draw", True },
2958 { "menuAction.Adjourn", False },
2959 { "menuAction.Abort", False },
2960 { "menuAction.Stop Observing", False },
2961 { "menuAction.Stop Examining", False },
2962 { "menuFile.Mail Move", True },
2963 { "menuFile.Reload CMail Message", True },
2967 Enables trainingOnEnables[] = {
2968 { "menuMode.Edit Comment", False },
2969 { "menuMode.Pause", False },
2970 { "menuEdit.Forward", False },
2971 { "menuEdit.Backward", False },
2972 { "menuEdit.Forward to End", False },
2973 { "menuEdit.Back to Start", False },
2974 { "menuEngine.Move Now", False },
2975 { "menuEdit.Truncate Game", False },
2979 Enables trainingOffEnables[] = {
2980 { "menuMode.Edit Comment", True },
2981 { "menuMode.Pause", True },
2982 { "menuEdit.Forward", True },
2983 { "menuEdit.Backward", True },
2984 { "menuEdit.Forward to End", True },
2985 { "menuEdit.Back to Start", True },
2986 { "menuEngine.Move Now", True },
2987 { "menuEdit.Truncate Game", True },
2991 Enables machineThinkingEnables[] = {
2992 { "menuFile.Load Game", False },
2993 // { "menuFile.Load Next Game", False },
2994 // { "menuFile.Load Previous Game", False },
2995 // { "menuFile.Reload Same Game", False },
2996 { "menuEdit.Paste Game", False },
2997 { "menuFile.Load Position", False },
2998 // { "menuFile.Load Next Position", False },
2999 // { "menuFile.Load Previous Position", False },
3000 // { "menuFile.Reload Same Position", False },
3001 { "menuEdit.Paste Position", False },
3002 { "menuMode.Machine White", False },
3003 { "menuMode.Machine Black", False },
3004 { "menuMode.Two Machines", False },
3005 // { "menuMode.Machine Match", False },
3006 { "menuEngine.Retract Move", False },
3010 Enables userThinkingEnables[] = {
3011 { "menuFile.Load Game", True },
3012 // { "menuFile.Load Next Game", True },
3013 // { "menuFile.Load Previous Game", True },
3014 // { "menuFile.Reload Same Game", True },
3015 { "menuEdit.Paste Game", True },
3016 { "menuFile.Load Position", True },
3017 // { "menuFile.Load Next Position", True },
3018 // { "menuFile.Load Previous Position", True },
3019 // { "menuFile.Reload Same Position", True },
3020 { "menuEdit.Paste Position", True },
3021 { "menuMode.Machine White", True },
3022 { "menuMode.Machine Black", True },
3023 { "menuMode.Two Machines", True },
3024 // { "menuMode.Machine Match", True },
3025 { "menuEngine.Retract Move", True },
3032 SetMenuEnables(icsEnables);
3035 if (appData.zippyPlay && !appData.noChessProgram) { /* [DM] icsEngineAnalyze */
3036 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
3037 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuEngine.Engine #1 Settings"), True);
3045 SetMenuEnables(ncpEnables);
3051 SetMenuEnables(gnuEnables);
3057 SetMenuEnables(cmailEnables);
3061 SetTrainingModeOn ()
3063 SetMenuEnables(trainingOnEnables);
3064 if (appData.showButtonBar) {
3065 XtSetSensitive(buttonBarWidget, False);
3071 SetTrainingModeOff ()
3073 SetMenuEnables(trainingOffEnables);
3074 if (appData.showButtonBar) {
3075 XtSetSensitive(buttonBarWidget, True);
3080 SetUserThinkingEnables ()
3082 if (appData.noChessProgram) return;
3083 SetMenuEnables(userThinkingEnables);
3087 SetMachineThinkingEnables ()
3089 if (appData.noChessProgram) return;
3090 SetMenuEnables(machineThinkingEnables);
3092 case MachinePlaysBlack:
3093 case MachinePlaysWhite:
3094 case TwoMachinesPlay:
3095 XtSetSensitive(XtNameToWidget(menuBarWidget,
3096 ModeToWidgetName(gameMode)), True);
3103 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
3104 #define HISTORY_SIZE 64
3105 static char *history[HISTORY_SIZE];
3106 int histIn = 0, histP = 0;
3109 SaveInHistory (char *cmd)
3111 if (history[histIn] != NULL) {
3112 free(history[histIn]);
3113 history[histIn] = NULL;
3115 if (*cmd == NULLCHAR) return;
3116 history[histIn] = StrSave(cmd);
3117 histIn = (histIn + 1) % HISTORY_SIZE;
3118 if (history[histIn] != NULL) {
3119 free(history[histIn]);
3120 history[histIn] = NULL;
3126 PrevInHistory (char *cmd)
3129 if (histP == histIn) {
3130 if (history[histIn] != NULL) free(history[histIn]);
3131 history[histIn] = StrSave(cmd);
3133 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
3134 if (newhp == histIn || history[newhp] == NULL) return NULL;
3136 return history[histP];
3142 if (histP == histIn) return NULL;
3143 histP = (histP + 1) % HISTORY_SIZE;
3144 return history[histP];
3146 // end of borrowed code
3148 #define Abs(n) ((n)<0 ? -(n) : (n))
3152 InsertPxlSize (char *pattern, int targetPxlSize)
3154 char *base_fnt_lst, strInt[12], *p, *q;
3155 int alternatives, i, len, strIntLen;
3158 * Replace the "*" (if present) in the pixel-size slot of each
3159 * alternative with the targetPxlSize.
3163 while ((p = strchr(p, ',')) != NULL) {
3167 snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
3168 strIntLen = strlen(strInt);
3169 base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
3173 while (alternatives--) {
3174 char *comma = strchr(p, ',');
3175 for (i=0; i<14; i++) {
3176 char *hyphen = strchr(p, '-');
3178 if (comma && hyphen > comma) break;
3179 len = hyphen + 1 - p;
3180 if (i == 7 && *p == '*' && len == 2) {
3182 memcpy(q, strInt, strIntLen);
3192 len = comma + 1 - p;
3199 return base_fnt_lst;
3203 CreateFontSet (char *base_fnt_lst)
3206 char **missing_list;
3210 fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
3211 &missing_list, &missing_count, &def_string);
3212 if (appData.debugMode) {
3214 XFontStruct **font_struct_list;
3215 char **font_name_list;
3216 fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
3218 fprintf(debugFP, " got list %s, locale %s\n",
3219 XBaseFontNameListOfFontSet(fntSet),
3220 XLocaleOfFontSet(fntSet));
3221 count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
3222 for (i = 0; i < count; i++) {
3223 fprintf(debugFP, " got charset %s\n", font_name_list[i]);
3226 for (i = 0; i < missing_count; i++) {
3227 fprintf(debugFP, " missing charset %s\n", missing_list[i]);
3230 if (fntSet == NULL) {
3231 fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
3236 #else // not ENABLE_NLS
3238 * Find a font that matches "pattern" that is as close as
3239 * possible to the targetPxlSize. Prefer fonts that are k
3240 * pixels smaller to fonts that are k pixels larger. The
3241 * pattern must be in the X Consortium standard format,
3242 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3243 * The return value should be freed with XtFree when no
3247 FindFont (char *pattern, int targetPxlSize)
3249 char **fonts, *p, *best, *scalable, *scalableTail;
3250 int i, j, nfonts, minerr, err, pxlSize;
3252 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3254 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3255 programName, pattern);
3262 for (i=0; i<nfonts; i++) {
3265 if (*p != '-') continue;
3267 if (*p == NULLCHAR) break;
3268 if (*p++ == '-') j++;
3270 if (j < 7) continue;
3273 scalable = fonts[i];
3276 err = pxlSize - targetPxlSize;
3277 if (Abs(err) < Abs(minerr) ||
3278 (minerr > 0 && err < 0 && -err == minerr)) {
3284 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3285 /* If the error is too big and there is a scalable font,
3286 use the scalable font. */
3287 int headlen = scalableTail - scalable;
3288 p = (char *) XtMalloc(strlen(scalable) + 10);
3289 while (isdigit(*scalableTail)) scalableTail++;
3290 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3292 p = (char *) XtMalloc(strlen(best) + 2);
3293 safeStrCpy(p, best, strlen(best)+1 );
3295 if (appData.debugMode) {
3296 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3297 pattern, targetPxlSize, p);
3299 XFreeFontNames(fonts);
3306 { // [HGM] deletes GCs that are to be remade, to prevent resource leak;
3307 // must be called before all non-first callse to CreateGCs()
3308 XtReleaseGC(shellWidget, highlineGC);
3309 XtReleaseGC(shellWidget, lightSquareGC);
3310 XtReleaseGC(shellWidget, darkSquareGC);
3311 XtReleaseGC(shellWidget, lineGC);
3312 if (appData.monoMode) {
3313 if (DefaultDepth(xDisplay, xScreen) == 1) {
3314 XtReleaseGC(shellWidget, wbPieceGC);
3316 XtReleaseGC(shellWidget, bwPieceGC);
3319 XtReleaseGC(shellWidget, prelineGC);
3320 XtReleaseGC(shellWidget, jailSquareGC);
3321 XtReleaseGC(shellWidget, wdPieceGC);
3322 XtReleaseGC(shellWidget, wlPieceGC);
3323 XtReleaseGC(shellWidget, wjPieceGC);
3324 XtReleaseGC(shellWidget, bdPieceGC);
3325 XtReleaseGC(shellWidget, blPieceGC);
3326 XtReleaseGC(shellWidget, bjPieceGC);
3331 CreateGCs (int redo)
3333 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3334 | GCBackground | GCFunction | GCPlaneMask;
3335 XGCValues gc_values;
3338 gc_values.plane_mask = AllPlanes;
3339 gc_values.line_width = lineGap;
3340 gc_values.line_style = LineSolid;
3341 gc_values.function = GXcopy;
3344 DeleteGCs(); // called a second time; clean up old GCs first
3345 } else { // [HGM] grid and font GCs created on first call only
3346 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3347 gc_values.background = XWhitePixel(xDisplay, xScreen);
3348 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3349 XSetFont(xDisplay, coordGC, coordFontID);
3351 // [HGM] make font for holdings counts (white on black)
3352 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3353 gc_values.background = XBlackPixel(xDisplay, xScreen);
3354 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3355 XSetFont(xDisplay, countGC, countFontID);
3357 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3358 gc_values.background = XBlackPixel(xDisplay, xScreen);
3359 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3361 if (appData.monoMode) {
3362 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3363 gc_values.background = XWhitePixel(xDisplay, xScreen);
3364 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3366 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3367 gc_values.background = XBlackPixel(xDisplay, xScreen);
3368 lightSquareGC = wbPieceGC
3369 = XtGetGC(shellWidget, value_mask, &gc_values);
3371 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3372 gc_values.background = XWhitePixel(xDisplay, xScreen);
3373 darkSquareGC = bwPieceGC
3374 = XtGetGC(shellWidget, value_mask, &gc_values);
3376 if (DefaultDepth(xDisplay, xScreen) == 1) {
3377 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3378 gc_values.function = GXcopyInverted;
3379 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3380 gc_values.function = GXcopy;
3381 if (XBlackPixel(xDisplay, xScreen) == 1) {
3382 bwPieceGC = darkSquareGC;
3383 wbPieceGC = copyInvertedGC;
3385 bwPieceGC = copyInvertedGC;
3386 wbPieceGC = lightSquareGC;
3390 gc_values.foreground = highlightSquareColor;
3391 gc_values.background = highlightSquareColor;
3392 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3394 gc_values.foreground = premoveHighlightColor;
3395 gc_values.background = premoveHighlightColor;
3396 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3398 gc_values.foreground = lightSquareColor;
3399 gc_values.background = darkSquareColor;
3400 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3402 gc_values.foreground = darkSquareColor;
3403 gc_values.background = lightSquareColor;
3404 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3406 gc_values.foreground = jailSquareColor;
3407 gc_values.background = jailSquareColor;
3408 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3410 gc_values.foreground = whitePieceColor;
3411 gc_values.background = darkSquareColor;
3412 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3414 gc_values.foreground = whitePieceColor;
3415 gc_values.background = lightSquareColor;
3416 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3418 gc_values.foreground = whitePieceColor;
3419 gc_values.background = jailSquareColor;
3420 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3422 gc_values.foreground = blackPieceColor;
3423 gc_values.background = darkSquareColor;
3424 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3426 gc_values.foreground = blackPieceColor;
3427 gc_values.background = lightSquareColor;
3428 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3430 gc_values.foreground = blackPieceColor;
3431 gc_values.background = jailSquareColor;
3432 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3437 loadXIM (XImage *xim, XImage *xmask, char *filename, Pixmap *dest, Pixmap *mask)
3445 fp = fopen(filename, "rb");
3447 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3454 for (y=0; y<h; ++y) {
3455 for (x=0; x<h; ++x) {
3460 XPutPixel(xim, x, y, blackPieceColor);
3462 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3465 XPutPixel(xim, x, y, darkSquareColor);
3467 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3470 XPutPixel(xim, x, y, whitePieceColor);
3472 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3475 XPutPixel(xim, x, y, lightSquareColor);
3477 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3485 /* create Pixmap of piece */
3486 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3488 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3491 /* create Pixmap of clipmask
3492 Note: We assume the white/black pieces have the same
3493 outline, so we make only 6 masks. This is okay
3494 since the XPM clipmask routines do the same. */
3496 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3498 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3501 /* now create the 1-bit version */
3502 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3505 values.foreground = 1;
3506 values.background = 0;
3508 /* Don't use XtGetGC, not read only */
3509 maskGC = XCreateGC(xDisplay, *mask,
3510 GCForeground | GCBackground, &values);
3511 XCopyPlane(xDisplay, temp, *mask, maskGC,
3512 0, 0, squareSize, squareSize, 0, 0, 1);
3513 XFreePixmap(xDisplay, temp);
3518 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3526 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3531 /* The XSynchronize calls were copied from CreatePieces.
3532 Not sure if needed, but can't hurt */
3533 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3536 /* temp needed by loadXIM() */
3537 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3538 0, 0, ss, ss, AllPlanes, XYPixmap);
3540 if (strlen(appData.pixmapDirectory) == 0) {
3544 if (appData.monoMode) {
3545 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3549 fprintf(stderr, _("\nLoading XIMs...\n"));
3551 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3552 fprintf(stderr, "%d", piece+1);
3553 for (kind=0; kind<4; kind++) {
3554 fprintf(stderr, ".");
3555 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3556 ExpandPathName(appData.pixmapDirectory),
3557 piece <= (int) WhiteKing ? "" : "w",
3558 pieceBitmapNames[piece],
3560 ximPieceBitmap[kind][piece] =
3561 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3562 0, 0, ss, ss, AllPlanes, XYPixmap);
3563 if (appData.debugMode)
3564 fprintf(stderr, _("(File:%s:) "), buf);
3565 loadXIM(ximPieceBitmap[kind][piece],
3567 &(xpmPieceBitmap2[kind][piece]),
3568 &(ximMaskPm2[piece]));
3569 if(piece <= (int)WhiteKing)
3570 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3572 fprintf(stderr," ");
3574 /* Load light and dark squares */
3575 /* If the LSQ and DSQ pieces don't exist, we will
3576 draw them with solid squares. */
3577 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3578 if (access(buf, 0) != 0) {
3582 fprintf(stderr, _("light square "));
3584 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3585 0, 0, ss, ss, AllPlanes, XYPixmap);
3586 if (appData.debugMode)
3587 fprintf(stderr, _("(File:%s:) "), buf);
3589 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3590 fprintf(stderr, _("dark square "));
3591 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3592 ExpandPathName(appData.pixmapDirectory), ss);
3593 if (appData.debugMode)
3594 fprintf(stderr, _("(File:%s:) "), buf);
3596 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3597 0, 0, ss, ss, AllPlanes, XYPixmap);
3598 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3599 xpmJailSquare = xpmLightSquare;
3601 fprintf(stderr, _("Done.\n"));
3603 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3606 static VariantClass oldVariant = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
3610 CreateXPMBoard (char *s, int kind)
3614 if(!appData.useBitmaps || s == NULL || *s == 0 || *s == '*') { useTexture &= ~(kind+1); return; }
3615 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3616 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3622 { // [HGM] to prevent resoucre leak on calling CreaeXPMPieces() a second time,
3623 // thisroutine has to be called t free the old piece pixmaps
3625 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++)
3626 for (kind=0; kind<4; kind++) XFreePixmap(xDisplay, xpmPieceBitmap2[kind][piece]);
3628 XFreePixmap(xDisplay, xpmLightSquare);
3629 XFreePixmap(xDisplay, xpmDarkSquare);
3638 u_int ss = squareSize;
3640 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3641 XpmColorSymbol symbols[4];
3642 static int redo = False;
3644 if(redo) FreeXPMPieces(); else redo = 1;
3646 /* The XSynchronize calls were copied from CreatePieces.
3647 Not sure if needed, but can't hurt */
3648 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3650 /* Setup translations so piece colors match square colors */
3651 symbols[0].name = "light_piece";
3652 symbols[0].value = appData.whitePieceColor;
3653 symbols[1].name = "dark_piece";
3654 symbols[1].value = appData.blackPieceColor;
3655 symbols[2].name = "light_square";
3656 symbols[2].value = appData.lightSquareColor;
3657 symbols[3].name = "dark_square";
3658 symbols[3].value = appData.darkSquareColor;
3660 attr.valuemask = XpmColorSymbols;
3661 attr.colorsymbols = symbols;
3662 attr.numsymbols = 4;
3664 if (appData.monoMode) {
3665 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3669 if (strlen(appData.pixmapDirectory) == 0) {
3670 XpmPieces* pieces = builtInXpms;
3673 while (pieces->size != squareSize && pieces->size) pieces++;
3674 if (!pieces->size) {
3675 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3678 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3679 for (kind=0; kind<4; kind++) {
3681 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3682 pieces->xpm[piece][kind],
3683 &(xpmPieceBitmap2[kind][piece]),
3684 NULL, &attr)) != 0) {
3685 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3689 if(piece <= (int) WhiteKing)
3690 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3694 xpmJailSquare = xpmLightSquare;
3698 fprintf(stderr, _("\nLoading XPMs...\n"));
3701 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3702 fprintf(stderr, "%d ", piece+1);
3703 for (kind=0; kind<4; kind++) {
3704 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3705 ExpandPathName(appData.pixmapDirectory),
3706 piece > (int) WhiteKing ? "w" : "",
3707 pieceBitmapNames[piece],
3709 if (appData.debugMode) {
3710 fprintf(stderr, _("(File:%s:) "), buf);
3712 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3713 &(xpmPieceBitmap2[kind][piece]),
3714 NULL, &attr)) != 0) {
3715 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3716 // [HGM] missing: read of unorthodox piece failed; substitute King.
3717 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3718 ExpandPathName(appData.pixmapDirectory),
3720 if (appData.debugMode) {
3721 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3723 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3724 &(xpmPieceBitmap2[kind][piece]),
3728 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3733 if(piece <= (int) WhiteKing)
3734 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3737 /* Load light and dark squares */
3738 /* If the LSQ and DSQ pieces don't exist, we will
3739 draw them with solid squares. */
3740 fprintf(stderr, _("light square "));
3741 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3742 if (access(buf, 0) != 0) {
3746 if (appData.debugMode)
3747 fprintf(stderr, _("(File:%s:) "), buf);
3749 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3750 &xpmLightSquare, NULL, &attr)) != 0) {
3751 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3754 fprintf(stderr, _("dark square "));
3755 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3756 ExpandPathName(appData.pixmapDirectory), ss);
3757 if (appData.debugMode) {
3758 fprintf(stderr, _("(File:%s:) "), buf);
3760 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3761 &xpmDarkSquare, NULL, &attr)) != 0) {
3762 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3766 xpmJailSquare = xpmLightSquare;
3767 fprintf(stderr, _("Done.\n"));
3769 oldVariant = -1; // kludge to force re-makig of animation masks
3770 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3773 #endif /* HAVE_LIBXPM */
3776 /* No built-in bitmaps */
3781 u_int ss = squareSize;
3783 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3786 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3787 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3788 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3789 pieceBitmapNames[piece],
3790 ss, kind == SOLID ? 's' : 'o');
3791 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3792 if(piece <= (int)WhiteKing)
3793 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3797 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3801 /* With built-in bitmaps */
3805 BuiltInBits* bib = builtInBits;
3808 u_int ss = squareSize;
3810 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3813 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3815 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3816 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3817 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3818 pieceBitmapNames[piece],
3819 ss, kind == SOLID ? 's' : 'o');
3820 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3821 bib->bits[kind][piece], ss, ss);
3822 if(piece <= (int)WhiteKing)
3823 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3827 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3833 ReadBitmap (Pixmap *pm, String name, unsigned char bits[], u_int wreq, u_int hreq)
3838 char msg[MSG_SIZ], fullname[MSG_SIZ];
3840 if (*appData.bitmapDirectory != NULLCHAR) {
3841 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3842 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3843 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3844 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3845 &w, &h, pm, &x_hot, &y_hot);
3846 fprintf(stderr, "load %s\n", name);
3847 if (errcode != BitmapSuccess) {
3849 case BitmapOpenFailed:
3850 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3852 case BitmapFileInvalid:
3853 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3855 case BitmapNoMemory:
3856 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3860 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3864 fprintf(stderr, _("%s: %s...using built-in\n"),
3866 } else if (w != wreq || h != hreq) {
3868 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3869 programName, fullname, w, h, wreq, hreq);
3875 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3885 if (lineGap == 0) return;
3887 /* [HR] Split this into 2 loops for non-square boards. */
3889 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3890 gridSegments[i].x1 = 0;
3891 gridSegments[i].x2 =
3892 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3893 gridSegments[i].y1 = gridSegments[i].y2
3894 = lineGap / 2 + (i * (squareSize + lineGap));
3897 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3898 gridSegments[j + i].y1 = 0;
3899 gridSegments[j + i].y2 =
3900 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3901 gridSegments[j + i].x1 = gridSegments[j + i].x2
3902 = lineGap / 2 + (j * (squareSize + lineGap));
3907 MenuBarSelect (Widget w, caddr_t addr, caddr_t index)
3909 XtActionProc proc = (XtActionProc) addr;
3911 (proc)(NULL, NULL, NULL, NULL);
3915 MenuEngineSelect (Widget w, caddr_t addr, caddr_t index)
3917 RecentEngineEvent((int) (intptr_t) addr);
3921 AppendEnginesToMenu (Widget menu, char *list)
3929 if(appData.icsActive || appData.recentEngines <= 0) return;
3930 recentEngines = strdup(list);
3932 XtSetArg(args[j], XtNleftMargin, 20); j++;
3933 XtSetArg(args[j], XtNrightMargin, 20); j++;
3935 p = strchr(list, '\n'); if(p == NULL) break;
3936 if(i == 0) XtCreateManagedWidget(_("----"), smeLineObjectClass, menu, args, j); // at least one valid item to add
3938 XtSetArg(args[j], XtNlabel, XtNewString(list));
3939 entry = XtCreateManagedWidget("engine", smeBSBObjectClass, menu, args, j+1);
3940 XtAddCallback(entry, XtNcallback,
3941 (XtCallbackProc) MenuEngineSelect,
3942 (caddr_t) (intptr_t) i);
3943 i++; *p = '\n'; list = p + 1;
3948 CreateMenuBarPopup (Widget parent, String name, Menu *mb)
3955 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3958 XtSetArg(args[j], XtNleftMargin, 20); j++;
3959 XtSetArg(args[j], XtNrightMargin, 20); j++;
3961 while (mi->string != NULL) {
3962 if (strcmp(mi->string, "----") == 0) {
3963 entry = XtCreateManagedWidget(_(mi->string), smeLineObjectClass,
3966 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3967 entry = XtCreateManagedWidget(mi->ref, smeBSBObjectClass,
3969 XtAddCallback(entry, XtNcallback,
3970 (XtCallbackProc) MenuBarSelect,
3971 (caddr_t) mi->proc);
3975 if(!strcmp(mb->name, "Engine")) AppendEnginesToMenu(menu, appData.recentEngineList);
3979 CreateMenuBar (Menu *mb, int boardWidth)
3981 int i, j, nr = 0, wtot = 0, widths[10];
3984 char menuName[MSG_SIZ];
3989 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3990 XtSetArg(args[j], XtNvSpace, 0); j++;
3991 XtSetArg(args[j], XtNborderWidth, 0); j++;
3992 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3993 formWidget, args, j);
3995 while (mb->name != NULL) {
3996 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3997 strncat(menuName, mb->ref, MSG_SIZ - strlen(menuName) - 1);
3999 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
4000 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
4001 XtSetArg(args[j], XtNborderWidth, 0); j++;
4002 mb->subMenu = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
4004 CreateMenuBarPopup(menuBar, menuName, mb);
4006 XtSetArg(args[j], XtNwidth, &w); j++;
4007 XtGetValues(mb->subMenu, args, j);
4008 wtot += mb->textWidth = widths[nr++] = w;
4011 while(wtot > boardWidth - 40) {
4013 for(i=0; i<nr; i++) if(widths[i] > wmax) wmax = widths[imax=i];
4017 for(i=0; i<nr; i++) if(widths[i] != ma[i].textWidth) {
4019 XtSetArg(args[j], XtNwidth, widths[i]); j++;
4020 XtSetValues(ma[i].subMenu, args, j);
4026 CreateButtonBar (MenuItem *mi)
4029 Widget button, buttonBar;
4033 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
4035 XtSetArg(args[j], XtNhSpace, 0); j++;
4037 XtSetArg(args[j], XtNborderWidth, 0); j++;
4038 XtSetArg(args[j], XtNvSpace, 0); j++;
4039 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
4040 formWidget, args, j);
4042 while (mi->string != NULL) {
4045 XtSetArg(args[j], XtNinternalWidth, 2); j++;
4046 XtSetArg(args[j], XtNborderWidth, 0); j++;
4048 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
4049 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
4050 buttonBar, args, j);
4051 XtAddCallback(button, XtNcallback,
4052 (XtCallbackProc) MenuBarSelect,
4053 (caddr_t) mi->proc);
4060 CreatePieceMenu (char *name, int color)
4065 ChessSquare selection;
4067 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
4068 boardWidget, args, 0);
4070 for (i = 0; i < PIECE_MENU_SIZE; i++) {
4071 String item = pieceMenuStrings[color][i];
4073 if (strcmp(item, "----") == 0) {
4074 entry = XtCreateManagedWidget(item, smeLineObjectClass,
4077 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
4078 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
4080 selection = pieceMenuTranslation[color][i];
4081 XtAddCallback(entry, XtNcallback,
4082 (XtCallbackProc) PieceMenuSelect,
4083 (caddr_t) selection);
4084 if (selection == WhitePawn || selection == BlackPawn) {
4085 XtSetArg(args[0], XtNpopupOnEntry, entry);
4086 XtSetValues(menu, args, 1);
4099 ChessSquare selection;
4101 whitePieceMenu = CreatePieceMenu("menuW", 0);
4102 blackPieceMenu = CreatePieceMenu("menuB", 1);
4104 if(appData.pieceMenu) // [HGM] sweep: no idea what this was good for, but it stopped reporting button events outside the window
4105 XtRegisterGrabAction(PieceMenuPopup, True,
4106 (unsigned)(ButtonPressMask|ButtonReleaseMask),
4107 GrabModeAsync, GrabModeAsync);
4109 XtSetArg(args[0], XtNlabel, _("Drop"));
4110 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
4111 boardWidget, args, 1);
4112 for (i = 0; i < DROP_MENU_SIZE; i++) {
4113 String item = dropMenuStrings[i];
4115 if (strcmp(item, "----") == 0) {
4116 entry = XtCreateManagedWidget(item, smeLineObjectClass,
4119 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
4120 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
4122 selection = dropMenuTranslation[i];
4123 XtAddCallback(entry, XtNcallback,
4124 (XtCallbackProc) DropMenuSelect,
4125 (caddr_t) selection);
4139 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
4140 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
4141 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
4142 dmEnables[i].piece);
4143 XtSetSensitive(entry, p != NULL || !appData.testLegality
4144 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
4145 && !appData.icsActive));
4147 while (p && *p++ == dmEnables[i].piece) count++;
4148 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
4150 XtSetArg(args[j], XtNlabel, label); j++;
4151 XtSetValues(entry, args, j);
4156 PieceMenuPopup (Widget w, XEvent *event, String *params, Cardinal *num_params)
4158 String whichMenu; int menuNr = -2;
4159 shiftKey = strcmp(params[0], "menuW"); // used to indicate black
4160 if (event->type == ButtonRelease)
4161 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
4162 else if (event->type == ButtonPress)
4163 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
4165 case 0: whichMenu = params[0]; break;
4166 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
4168 case -1: if (errorUp) ErrorPopDown();
4171 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
4175 PieceMenuSelect (Widget w, ChessSquare piece, caddr_t junk)
4177 if (pmFromX < 0 || pmFromY < 0) return;
4178 EditPositionMenuEvent(piece, pmFromX, pmFromY);
4182 DropMenuSelect (Widget w, ChessSquare piece, caddr_t junk)
4184 if (pmFromX < 0 || pmFromY < 0) return;
4185 DropMenuEvent(piece, pmFromX, pmFromY);
4189 WhiteClock (Widget w, XEvent *event, String *prms, Cardinal *nprms)
4191 shiftKey = prms[0][0] & 1;
4196 BlackClock (Widget w, XEvent *event, String *prms, Cardinal *nprms)
4198 shiftKey = prms[0][0] & 1;
4204 * If the user selects on a border boundary, return -1; if off the board,
4205 * return -2. Otherwise map the event coordinate to the square.
4208 EventToSquare (int x, int limit)
4215 if ((x % (squareSize + lineGap)) >= squareSize)
4217 x /= (squareSize + lineGap);
4224 do_flash_delay (unsigned long msec)
4230 drawHighlight (int file, int rank, GC gc)
4234 if (lineGap == 0) return;
4237 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
4238 (squareSize + lineGap);
4239 y = lineGap/2 + rank * (squareSize + lineGap);
4241 x = lineGap/2 + file * (squareSize + lineGap);
4242 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
4243 (squareSize + lineGap);
4246 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
4247 squareSize+lineGap, squareSize+lineGap);
4250 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
4251 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4254 SetHighlights (int fromX, int fromY, int toX, int toY)
4256 if (hi1X != fromX || hi1Y != fromY) {
4257 if (hi1X >= 0 && hi1Y >= 0) {
4258 drawHighlight(hi1X, hi1Y, lineGC);
4260 } // [HGM] first erase both, then draw new!
4261 if (hi2X != toX || hi2Y != toY) {
4262 if (hi2X >= 0 && hi2Y >= 0) {
4263 drawHighlight(hi2X, hi2Y, lineGC);
4266 if (hi1X != fromX || hi1Y != fromY) {
4267 if (fromX >= 0 && fromY >= 0) {
4268 drawHighlight(fromX, fromY, highlineGC);
4271 if (hi2X != toX || hi2Y != toY) {
4272 if (toX >= 0 && toY >= 0) {